main
dart 256 lines 6.71 KB
Raw
1 import 'package:flutter_test/flutter_test.dart';
2 import 'package:localmind/core/models/enums.dart';
3 import 'package:localmind/core/storage/entities.dart';
4 import 'package:localmind/features/servers/data/models/server.dart';
5
6 void main() {
7 group('ServerEntity.resolveServerType', () {
8 test(
9 'resolves on-device server when typeIndex was 4 before Ollama Cloud was inserted',
10 () {
11 // Prior to Ollama Cloud (commit 51996bb), onDevice had index 4.
12 // After inserting Ollama Cloud at index 3, index 4 became openRouter.
13 // Existing on-device records in ObjectBox have typeIndex: 4.
14 final type = ServerEntity.resolveServerType(
15 typeIndex: 4,
16 id: 'on-device',
17 name: 'On-Device',
18 host: '',
19 port: 0,
20 );
21
22 expect(type, ServerType.onDevice);
23 },
24 );
25
26 test('resolves on-device server by id even if typeIndex is unexpected', () {
27 final type = ServerEntity.resolveServerType(
28 typeIndex: 99,
29 id: 'on-device',
30 name: 'Custom On Device',
31 host: '',
32 port: 0,
33 );
34
35 expect(type, ServerType.onDevice);
36 });
37
38 test(
39 'resolves on-device server created with timestamp id from onboarding',
40 () {
41 final type = ServerEntity.resolveServerType(
42 typeIndex: 4,
43 id: '1720000000000',
44 name: 'On-Device',
45 host: '',
46 port: 0,
47 );
48
49 expect(type, ServerType.onDevice);
50 },
51 );
52
53 test(
54 'resolves on-device server with empty host and port 0 without API key',
55 () {
56 final type = ServerEntity.resolveServerType(
57 typeIndex: 4,
58 id: 'custom-local',
59 name: 'Local inference',
60 host: '',
61 port: 0,
62 );
63
64 expect(type, ServerType.onDevice);
65 },
66 );
67
68 test(
69 'resolves openRouter server when typeIndex was 3 before Ollama Cloud was inserted',
70 () {
71 // Prior to Ollama Cloud, openRouter had index 3.
72 // When Ollama Cloud was inserted at index 3, existing OpenRouter records
73 // were deserialized as ollamaCloud.
74 final type = ServerEntity.resolveServerType(
75 typeIndex: 3,
76 id: 'openrouter-1',
77 name: 'OpenRouter',
78 host: 'https://openrouter.ai/api/v1',
79 port: 443,
80 apiKey: 'sk-or-v1-testkey',
81 );
82
83 expect(type, ServerType.openRouter);
84 },
85 );
86
87 test(
88 'resolves openRouter server by sk-or apiKey even with generic host',
89 () {
90 final type = ServerEntity.resolveServerType(
91 typeIndex: 3,
92 id: 'openrouter-2',
93 name: 'Cloud AI',
94 host: 'https://openrouter.ai',
95 port: 443,
96 apiKey: 'sk-or-testkey',
97 );
98
99 expect(type, ServerType.openRouter);
100 },
101 );
102
103 test('resolves ollamaCloud correctly when host points to ollama.com', () {
104 final type = ServerEntity.resolveServerType(
105 typeIndex: 3,
106 id: 'ollama-cloud-1',
107 name: 'Ollama Cloud',
108 host: 'https://ollama.com',
109 port: 443,
110 );
111
112 expect(type, ServerType.ollamaCloud);
113 });
114
115 test('preserves standard server types by valid typeIndex', () {
116 expect(
117 ServerEntity.resolveServerType(
118 typeIndex: 0,
119 id: 'lm-studio',
120 name: 'LM Studio',
121 host: 'localhost',
122 port: 1234,
123 ),
124 ServerType.lmStudio,
125 );
126
127 expect(
128 ServerEntity.resolveServerType(
129 typeIndex: 1,
130 id: 'oai-compat',
131 name: 'Custom OpenAI',
132 host: 'http://localhost:8000',
133 port: 8000,
134 ),
135 ServerType.openAICompatible,
136 );
137
138 expect(
139 ServerEntity.resolveServerType(
140 typeIndex: 2,
141 id: 'ollama-local',
142 name: 'Ollama',
143 host: 'http://localhost:11434',
144 port: 11434,
145 ),
146 ServerType.ollama,
147 );
148
149 expect(
150 ServerEntity.resolveServerType(
151 typeIndex: 5,
152 id: 'on-device-new',
153 name: 'On-Device',
154 host: '',
155 port: 0,
156 ),
157 ServerType.onDevice,
158 );
159
160 expect(
161 ServerEntity.resolveServerType(
162 typeIndex: 6,
163 id: 'requesty-1',
164 name: 'Requesty',
165 host: 'router.requesty.ai',
166 port: 443,
167 ),
168 ServerType.requesty,
169 );
170 });
171 });
172
173 group('ServerEntity.toDomain healing', () {
174 test('heals corrupted on-device entity to ServerType.onDevice', () {
175 final now = DateTime(2026, 1, 1);
176 final entity = ServerEntity(
177 id: 'on-device',
178 name: 'On-Device',
179 typeIndex: 4, // Was onDevice, shifted to openRouter
180 host: '',
181 port: 0,
182 createdAt: now,
183 lastConnectedAt: now,
184 statusIndex: 1,
185 );
186
187 final domain = entity.toDomain();
188 expect(domain.id, 'on-device');
189 expect(domain.type, ServerType.onDevice);
190 expect(domain.isOnDevice, isTrue);
191 });
192
193 test('heals shifted OpenRouter entity to ServerType.openRouter', () {
194 final now = DateTime(2026, 1, 1);
195 final entity = ServerEntity(
196 id: 'or-server',
197 name: 'OpenRouter Cloud',
198 typeIndex: 3, // Was openRouter, shifted to ollamaCloud
199 host: 'https://openrouter.ai/api/v1',
200 port: 443,
201 apiKey: 'sk-or-v1-abcdef',
202 createdAt: now,
203 lastConnectedAt: now,
204 statusIndex: 1,
205 );
206
207 final domain = entity.toDomain();
208 expect(domain.type, ServerType.openRouter);
209 expect(domain.isOnDevice, isFalse);
210 });
211 });
212
213 group('Server.isOnDevice', () {
214 test('returns true for ServerType.onDevice', () {
215 final server = Server(
216 id: 'custom-id',
217 name: 'On-Device',
218 type: ServerType.onDevice,
219 host: '',
220 port: 0,
221 createdAt: DateTime(2026, 1, 1),
222 lastConnectedAt: DateTime(2026, 1, 1),
223 );
224
225 expect(server.isOnDevice, isTrue);
226 });
227
228 test('returns true for id on-device even if type was corrupted', () {
229 final server = Server(
230 id: 'on-device',
231 name: 'On-Device',
232 type: ServerType.openRouter,
233 host: '',
234 port: 0,
235 createdAt: DateTime(2026, 1, 1),
236 lastConnectedAt: DateTime(2026, 1, 1),
237 );
238
239 expect(server.isOnDevice, isTrue);
240 });
241
242 test('returns false for remote servers', () {
243 final server = Server(
244 id: 'cloud-server',
245 name: 'OpenRouter',
246 type: ServerType.openRouter,
247 host: 'https://openrouter.ai',
248 port: 443,
249 createdAt: DateTime(2026, 1, 1),
250 lastConnectedAt: DateTime(2026, 1, 1),
251 );
252
253 expect(server.isOnDevice, isFalse);
254 });
255 });
256 }