Some checks failed
Security / Security check (push) Failing after 2s
Doctor: when the system AI uses an Ollama endpoint that no declared host service covers (host:port match, /v1 suffix stripped), the services panel says so in one sentence with a one-click 'declare as host service' via the new DeclareService RPC — and states honestly that it takes effect after a daemon restart (the restart button sits on the same page). Pure suggestOllamaServiceEndpoint pins every branch. Shell: one slim, dismissible banner after connecting when the release manifest offers a newer hub version; dismissal is persisted per version so each release hints exactly once (pure shouldShowUpdateHint + a widget test through the fake hub). Deliberately manifest-based — Studio and hub versions are independent counters, so a direct comparison would be wrong; unreleased dev skew stays with the per-page classified states. The probe stays inert under the test probe override: its timeout timer leaked into hub_banner_test (the hermeticity class again). Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
149 lines
4.1 KiB
Dart
149 lines
4.1 KiB
Dart
// The doctor's "declare the system AI's Ollama as a host service"
|
|
// suggestion and the shell's one-time update hint — both are pure
|
|
// functions so every branch is pinned here.
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
|
|
import 'package:chain_studio/data/hub.dart';
|
|
import 'package:chain_studio/main.dart'
|
|
show StudioApp, shouldShowUpdateHint;
|
|
import 'package:chain_studio/pages/doctor.dart'
|
|
show suggestOllamaServiceEndpoint;
|
|
|
|
import 'support/fake_hub.dart';
|
|
|
|
SystemAiStatus _ai({
|
|
bool enabled = true,
|
|
String provider = 'ollama',
|
|
String endpoint = 'http://127.0.0.1:11434/v1',
|
|
}) => SystemAiStatus(
|
|
enabled: enabled,
|
|
provider: provider,
|
|
endpoint: endpoint,
|
|
model: 'qwen2.5:14b',
|
|
privacyMode: 'off',
|
|
apiKeyEnv: '',
|
|
);
|
|
|
|
void main() {
|
|
group('suggestOllamaServiceEndpoint', () {
|
|
test('suggests the base URL with the /v1 suffix stripped', () {
|
|
expect(
|
|
suggestOllamaServiceEndpoint(ai: _ai(), services: const []),
|
|
'http://127.0.0.1:11434',
|
|
);
|
|
});
|
|
|
|
test('nothing to suggest when AI is off or another provider', () {
|
|
expect(
|
|
suggestOllamaServiceEndpoint(ai: _ai(enabled: false), services: const []),
|
|
isNull,
|
|
);
|
|
expect(
|
|
suggestOllamaServiceEndpoint(
|
|
ai: _ai(provider: 'openai'),
|
|
services: const [],
|
|
),
|
|
isNull,
|
|
);
|
|
expect(
|
|
suggestOllamaServiceEndpoint(ai: _ai(endpoint: ''), services: const []),
|
|
isNull,
|
|
);
|
|
});
|
|
|
|
test('a declared service on the same host:port silences it', () {
|
|
expect(
|
|
suggestOllamaServiceEndpoint(
|
|
ai: _ai(),
|
|
services: const [
|
|
ServiceEntry(
|
|
name: 'my-llm',
|
|
endpoint: 'http://127.0.0.1:11434',
|
|
tags: [],
|
|
),
|
|
],
|
|
),
|
|
isNull,
|
|
);
|
|
});
|
|
|
|
test('a service on another port does not silence it', () {
|
|
expect(
|
|
suggestOllamaServiceEndpoint(
|
|
ai: _ai(),
|
|
services: const [
|
|
ServiceEntry(
|
|
name: 'judge-ner',
|
|
endpoint: 'http://127.0.0.1:8756',
|
|
tags: [],
|
|
),
|
|
],
|
|
),
|
|
'http://127.0.0.1:11434',
|
|
);
|
|
});
|
|
});
|
|
|
|
testWidgets('the shell hints once and dismisses persistently', (
|
|
tester,
|
|
) async {
|
|
SharedPreferences.setMockInitialValues({});
|
|
final fake = installFakeHub();
|
|
fake.updateHint = const UpdateStatus(
|
|
channel: 'stable',
|
|
localVersion: '0.22.0',
|
|
latestVersion: '0.23.0',
|
|
updateAvailable: true,
|
|
manifestReachable: true,
|
|
);
|
|
await tester.pumpWidget(
|
|
const StudioApp(
|
|
initialThemeMode: ThemeModeValue.dark,
|
|
initialLocale: Locale('de'),
|
|
),
|
|
);
|
|
for (var i = 0; i < 8; i++) {
|
|
await tester.pump(const Duration(milliseconds: 100));
|
|
}
|
|
expect(find.textContaining('0.23.0'), findsOneWidget);
|
|
await tester.tap(find.text('Später'));
|
|
await tester.pump(const Duration(milliseconds: 100));
|
|
expect(find.textContaining('0.23.0'), findsNothing);
|
|
// Dismissal is persisted per version.
|
|
final prefs = await SharedPreferences.getInstance();
|
|
expect(prefs.getString('update.hint.dismissed'), '0.23.0');
|
|
// Drain shell timers (a11y-suite pattern).
|
|
await tester.pumpWidget(const SizedBox.shrink());
|
|
await tester.pump(const Duration(minutes: 1));
|
|
});
|
|
|
|
group('shouldShowUpdateHint', () {
|
|
test('hints once per release version', () {
|
|
expect(
|
|
shouldShowUpdateHint(latestVersion: '0.23.0', dismissedVersion: null),
|
|
isTrue,
|
|
);
|
|
expect(
|
|
shouldShowUpdateHint(
|
|
latestVersion: '0.23.0',
|
|
dismissedVersion: '0.22.0',
|
|
),
|
|
isTrue,
|
|
);
|
|
expect(
|
|
shouldShowUpdateHint(
|
|
latestVersion: '0.23.0',
|
|
dismissedVersion: '0.23.0',
|
|
),
|
|
isFalse,
|
|
);
|
|
expect(
|
|
shouldShowUpdateHint(latestVersion: '', dismissedVersion: null),
|
|
isFalse,
|
|
);
|
|
});
|
|
});
|
|
}
|