Skip to content

Commit 1489be4

Browse files
committed
fix: repair solution references and integration tests
1 parent 6ee5f0b commit 1489be4

File tree

4 files changed

+166
-81
lines changed

4 files changed

+166
-81
lines changed

Reka.slnx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<Solution>
22
<Folder Name="/libs/">
33
<File Path="src/libs/Directory.Build.props" />
4-
<Project Path="src/libs/Ollama.Models/Ollama.Models.csproj" />
5-
<Project Path="src/libs/Ollama/Ollama.csproj" />
4+
<Project Path="src/libs/Reka.Models/Reka.Models.csproj" />
5+
<Project Path="src/libs/Reka/Reka.csproj" />
66
</Folder>
77
<Folder Name="/Solution Items/">
88
<File Path=".github/workflows/dotnet.yml" />
@@ -14,6 +14,6 @@
1414
<File Path="src/Directory.Build.props" />
1515
</Folder>
1616
<Folder Name="/tests/">
17-
<Project Path="src/tests/Ollama.IntegrationTests/Ollama.IntegrationTests.csproj" />
17+
<Project Path="src/tests/Reka.IntegrationTests/Reka.IntegrationTests.csproj" />
1818
</Folder>
1919
</Solution>

src/libs/Reka/Reka.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
</ItemGroup>
4646

4747
<ItemGroup>
48-
<ProjectReference Include="..\Ollama.Models\Ollama.Models.csproj" />
48+
<ProjectReference Include="..\Reka.Models\Reka.Models.csproj" />
4949
</ItemGroup>
5050

5151
</Project>

src/tests/Reka.IntegrationTests/Reka.IntegrationTests.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
</ItemGroup>
2424

2525
<ItemGroup>
26-
<ProjectReference Include="..\..\libs\Ollama\Ollama.csproj" />
26+
<ProjectReference Include="..\..\libs\Reka\Reka.csproj" />
2727
</ItemGroup>
2828

29-
</Project>
29+
</Project>
Lines changed: 160 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,158 +1,243 @@
11
using DotNet.Testcontainers.Builders;
2+
using DotNet.Testcontainers.Containers;
23

34
namespace Ollama.IntegrationTests;
45

56
public partial class Tests
67
{
7-
private static async Task<Environment> PrepareEnvironmentAsync(EnvironmentType environmentType, string model = "")
8+
private static async Task<TestEnvironment> PrepareEnvironmentAsync(TestEnvironmentType environmentType, string model = "")
89
{
910
switch (environmentType)
1011
{
11-
case EnvironmentType.Local:
12+
case TestEnvironmentType.Local:
13+
return await CreateEnvironmentAsync(
14+
new OllamaApiClient(baseUri: CreateLocalBaseUri()),
15+
model).ConfigureAwait(false);
16+
case TestEnvironmentType.Container:
1217
{
13-
// set OLLAMA_HOST=172.16.50.107:11434
14-
// ollama serve
15-
var apiClient = new OllamaApiClient(baseUri: new Uri("http://172.16.50.107:11434/api"));
16-
17-
if (!string.IsNullOrEmpty(model))
18-
{
19-
await apiClient.PullModelAndEnsureSuccessAsync(model);
20-
}
18+
const int ollamaPort = 11434;
2119

22-
return new Environment
23-
{
24-
ApiClient = apiClient,
25-
};
26-
}
27-
case EnvironmentType.Container:
28-
{
2920
var container = new ContainerBuilder()
3021
.WithImage("ollama/ollama")
31-
.WithPortBinding(hostPort: 11434, containerPort: 11434)
32-
.WithWaitStrategy(Wait.ForUnixContainer().UntilPortIsAvailable(11434))
22+
.WithPortBinding(ollamaPort, true)
23+
.WithWaitStrategy(Wait.ForUnixContainer().UntilPortIsAvailable(ollamaPort))
3324
.Build();
34-
35-
await container.StartAsync();
36-
37-
var apiClient = new OllamaApiClient();
38-
if (!string.IsNullOrEmpty(model))
39-
{
40-
await apiClient.PullModelAndEnsureSuccessAsync(model);
41-
}
42-
43-
return new Environment
44-
{
45-
Container = container,
46-
ApiClient = apiClient,
47-
};
25+
26+
await container.StartAsync().ConfigureAwait(false);
27+
28+
return await CreateEnvironmentAsync(
29+
new OllamaApiClient(
30+
baseUri: new Uri($"http://{container.Hostname}:{container.GetMappedPublicPort(ollamaPort)}/api")),
31+
model,
32+
container).ConfigureAwait(false);
4833
}
4934
default:
5035
throw new ArgumentOutOfRangeException(nameof(environmentType), environmentType, null);
5136
}
5237
}
53-
38+
39+
private static Uri CreateLocalBaseUri()
40+
{
41+
var ollamaHost = System.Environment.GetEnvironmentVariable("OLLAMA_HOST");
42+
if (string.IsNullOrWhiteSpace(ollamaHost))
43+
{
44+
return new Uri("http://localhost:11434/api");
45+
}
46+
47+
if (!ollamaHost.Contains("://", StringComparison.Ordinal))
48+
{
49+
ollamaHost = $"http://{ollamaHost}";
50+
}
51+
52+
if (!ollamaHost.EndsWith("/api", StringComparison.OrdinalIgnoreCase))
53+
{
54+
ollamaHost = $"{ollamaHost.TrimEnd('/')}/api";
55+
}
56+
57+
return new Uri(ollamaHost, UriKind.Absolute);
58+
}
59+
60+
private static async Task<TestEnvironment> CreateEnvironmentAsync(
61+
OllamaApiClient apiClient,
62+
string model,
63+
IContainer? container = null)
64+
{
65+
if (!string.IsNullOrEmpty(model))
66+
{
67+
await PullModelAndEnsureSuccessAsync(apiClient, model).ConfigureAwait(false);
68+
}
69+
70+
return new TestEnvironment(apiClient, container);
71+
}
72+
73+
private static async Task PullModelAndEnsureSuccessAsync(OllamaApiClient apiClient, string model)
74+
{
75+
var response = await ReadLastAsync(
76+
apiClient.PullModelAsync(model, stream: false)).ConfigureAwait(false);
77+
78+
response.Status.Should().Be(PullModelResponseStatus.Success);
79+
}
80+
81+
private static async Task<T> ReadLastAsync<T>(IAsyncEnumerable<T> source)
82+
{
83+
var hasValue = false;
84+
var last = default(T);
85+
86+
await foreach (var item in source.ConfigureAwait(false))
87+
{
88+
last = item;
89+
hasValue = true;
90+
}
91+
92+
if (!hasValue)
93+
{
94+
throw new InvalidOperationException("The operation did not return any results.");
95+
}
96+
97+
return last!;
98+
}
99+
54100
[TestMethod]
55101
public async Task ListModels()
56102
{
57-
await using var container = await PrepareEnvironmentAsync(EnvironmentType.Container);
58-
103+
await using var container = await PrepareEnvironmentAsync(TestEnvironmentType.Container);
104+
59105
var models = await container.ApiClient.ListModelsAsync();
60106
models.Models.Should().BeNullOrEmpty();
61-
62-
await container.ApiClient.PullModelAndEnsureSuccessAsync("all-minilm");
63-
107+
108+
await PullModelAndEnsureSuccessAsync(container.ApiClient, "all-minilm");
109+
64110
models = await container.ApiClient.ListModelsAsync();
65111
models.Models.Should().NotBeNull();
66112
models.Models.Should().HaveCount(1);
67113
models.Models![0].Model.Should().Be("all-minilm:latest");
68114
}
69-
115+
70116
[TestMethod]
71117
public async Task PullModel()
72118
{
73-
await using var container = await PrepareEnvironmentAsync(EnvironmentType.Container);
74-
119+
await using var container = await PrepareEnvironmentAsync(TestEnvironmentType.Container);
120+
75121
await foreach (var response in container.ApiClient.PullModelAsync("all-minilm", stream: true))
76122
{
77123
Console.WriteLine($"{response.Status}. Progress: {response.Completed}/{response.Total}");
78124
}
79-
80-
var response2 = await container.ApiClient.PullModelAsync("all-minilm").WaitAsync();
81-
response2.EnsureSuccess();
82-
83-
await container.ApiClient.PullModelAndEnsureSuccessAsync("all-minilm");
125+
126+
var response2 = await ReadLastAsync(container.ApiClient.PullModelAsync("all-minilm", stream: false));
127+
response2.Status.Should().Be(PullModelResponseStatus.Success);
128+
129+
await PullModelAndEnsureSuccessAsync(container.ApiClient, "all-minilm");
84130
}
85-
131+
86132
[TestMethod]
87133
public async Task Embeddings()
88134
{
89-
await using var container = await PrepareEnvironmentAsync(EnvironmentType.Container);
90-
91-
await container.ApiClient.PullModelAndEnsureSuccessAsync("all-minilm");
92-
135+
await using var container = await PrepareEnvironmentAsync(TestEnvironmentType.Container);
136+
137+
await PullModelAndEnsureSuccessAsync(container.ApiClient, "all-minilm");
138+
93139
var embeddingResponse = await container.ApiClient.GenerateEmbeddingAsync(
94-
model:"all-minilm",
140+
model: "all-minilm",
95141
prompt: "hello");
96-
142+
97143
embeddingResponse.Embedding.Should().NotBeNullOrEmpty();
98144
}
99-
145+
100146
[TestMethod]
101147
public async Task GetCompletionWithOptions()
102148
{
103149
#if DEBUG
104-
await using var container = await PrepareEnvironmentAsync(EnvironmentType.Local, "llama3");
150+
await using var container = await PrepareEnvironmentAsync(TestEnvironmentType.Local, "llama3");
105151
#else
106-
await using var container = await PrepareEnvironmentAsync(EnvironmentType.Container, "llama3");
152+
await using var container = await PrepareEnvironmentAsync(TestEnvironmentType.Container, "llama3");
107153
#endif
108154

109-
var response = await container.ApiClient.GenerateCompletionAsync(new GenerateCompletionRequest
155+
var response = await ReadLastAsync(container.ApiClient.GenerateCompletionAsync(new GenerateCompletionRequest
110156
{
111157
Model = "llama3",
112158
Prompt = "answer me just \"123\"",
113-
Stream = true,
159+
Stream = false,
114160
Options = new RequestOptions
115161
{
116162
Temperature = 0,
117163
},
118-
}).WaitAsync();
164+
}));
119165
Console.WriteLine(response.Response);
120166
}
121-
167+
122168
[TestMethod]
123169
public async Task GetCompletion()
124170
{
125171
#if DEBUG
126-
await using var container = await PrepareEnvironmentAsync(EnvironmentType.Local, "llama3");
172+
await using var container = await PrepareEnvironmentAsync(TestEnvironmentType.Local, "llama3");
127173
#else
128-
await using var container = await PrepareEnvironmentAsync(EnvironmentType.Container, "llama3");
174+
await using var container = await PrepareEnvironmentAsync(TestEnvironmentType.Container, "llama3");
129175
#endif
130176

131177
IList<long>? context = null;
132178
var enumerable = container.ApiClient.GenerateCompletionAsync("llama3", "answer 5 random words", stream: true);
133179
await foreach (var response in enumerable)
134180
{
135181
Console.WriteLine($"> {response.Response}");
136-
182+
137183
context = response.Context;
138184
}
139-
140-
var lastResponse = await container.ApiClient.GenerateCompletionAsync("llama3", "answer 123", stream: false, context: context).WaitAsync();
185+
186+
var lastResponse = await ReadLastAsync(
187+
container.ApiClient.GenerateCompletionAsync("llama3", "answer 123", stream: false, context: context));
141188
Console.WriteLine(lastResponse.Response);
142189
}
143-
190+
144191
[TestMethod]
145192
public async Task GetChat()
146193
{
147194
#if DEBUG
148-
await using var container = await PrepareEnvironmentAsync(EnvironmentType.Local, "llama3");
195+
await using var container = await PrepareEnvironmentAsync(TestEnvironmentType.Local, "llama3");
149196
#else
150-
await using var container = await PrepareEnvironmentAsync(EnvironmentType.Container, "llama3");
197+
await using var container = await PrepareEnvironmentAsync(TestEnvironmentType.Container, "llama3");
151198
#endif
152-
153-
var chat = container.ApiClient.Chat("llama3");
154-
var message = await chat.SendAsync("answer in 5 words");
155-
156-
Console.WriteLine(message.Content);
199+
200+
var response = await ReadLastAsync(container.ApiClient.GenerateChatCompletionAsync(
201+
model: "llama3",
202+
messages:
203+
[
204+
new Message
205+
{
206+
Role = MessageRole.User,
207+
Content = "answer in 5 words",
208+
},
209+
],
210+
stream: false));
211+
212+
Console.WriteLine(response.Message?.Content);
213+
}
214+
}
215+
216+
internal enum TestEnvironmentType
217+
{
218+
Local,
219+
Container,
220+
}
221+
222+
internal sealed class TestEnvironment : IAsyncDisposable
223+
{
224+
internal TestEnvironment(OllamaApiClient apiClient, IContainer? container = null)
225+
{
226+
ApiClient = apiClient;
227+
Container = container;
228+
}
229+
230+
internal OllamaApiClient ApiClient { get; }
231+
232+
internal IContainer? Container { get; }
233+
234+
public async ValueTask DisposeAsync()
235+
{
236+
ApiClient.Dispose();
237+
238+
if (Container is not null)
239+
{
240+
await Container.DisposeAsync().ConfigureAwait(false);
241+
}
157242
}
158-
}
243+
}

0 commit comments

Comments
 (0)