- Umgebungen (Name, API-URL, Keycloak-Issuer) kommen aus assets/hl_server_config.json statt hartcodiertem BackendConfig.prod; Testumgebung 192.168.1.9:3001 ist dort hinterlegt - AppBloc laedt die Config, aktiviert die gespeicherte Wahl (Fallback Default) und registriert das Networking; Wechsel persistiert per SharedPreferences und registriert neu - Bloc-Baum ist pro Umgebung gekeyt: beim Wechsel entstehen alle Blocs mit dem neuen API-Client neu - Login-Screen: Zahnrad oben rechts oeffnet Einstellungen mit Umgebungs- Cards (Name + IP:Port); Hinweis auf aktive Umgebung unter dem Button - Fahrzeugauswahl pro Umgebung getrennt (eigene DB = eigene Car-IDs) - Tests fuer Config-Parsing, Auswahl-Fallback, Card-Wechsel, Re-Registrierung Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
81 lines
2.6 KiB
Dart
81 lines
2.6 KiB
Dart
/// Smoke-Test für den generierten Holzleitner-API-Client.
|
|
///
|
|
/// Läuft als reines Dart-Script (kein Flutter-Engine nötig):
|
|
///
|
|
/// dart run tool/smoke_test_api.dart
|
|
///
|
|
/// Voraussetzungen:
|
|
/// * Backend läuft unter http://127.0.0.1:3000
|
|
/// * Keycloak läuft unter http://127.0.0.1:8080
|
|
/// * Testfahrer (PN 1001) ist im Keycloak-Realm angelegt
|
|
///
|
|
/// Was getestet wird:
|
|
/// 1. /health (ohne Auth)
|
|
/// 2. /me/cars (mit Auth via DevPasswordGrantTokenProvider)
|
|
library;
|
|
|
|
import 'dart:convert';
|
|
import 'dart:io';
|
|
|
|
import 'package:dio/dio.dart';
|
|
import 'package:hl_lieferservice/data/network/backend_environment.dart';
|
|
import 'package:hl_lieferservice/data/network/dev_password_grant_token_provider.dart';
|
|
import 'package:hl_lieferservice/data/network/holzleitner_api_factory.dart';
|
|
|
|
Future<void> main(List<String> args) async {
|
|
// Server kommen aus derselben Config wie in der App. Umgebung per
|
|
// Argument wählbar: `dart run tool/smoke_test_api.dart test`.
|
|
final catalog = ServerCatalog.fromJson(
|
|
jsonDecode(File('assets/hl_server_config.json').readAsStringSync())
|
|
as Map<String, dynamic>,
|
|
);
|
|
final envId = args.isNotEmpty ? args.first : catalog.defaultEnvironmentId;
|
|
final env = catalog.byId(envId);
|
|
if (env == null) {
|
|
print('Unbekannte Umgebung "$envId".');
|
|
return;
|
|
}
|
|
final config = catalog.configFor(env);
|
|
print('Umgebung: ${env.name} (${env.apiBaseUrl})');
|
|
|
|
// Health geht ohne Auth — wir nutzen die generierte API-Klasse trotzdem,
|
|
// um zu zeigen, dass der Aufruf-Pfad funktioniert.
|
|
print('---- 1) GET /health ----');
|
|
final tokenProvider = DevPasswordGrantTokenProvider(
|
|
tokenEndpoint: config.keycloakTokenEndpoint,
|
|
clientId: config.keycloakClientId,
|
|
username: 'testfahrer',
|
|
password: 'test',
|
|
);
|
|
final api = buildHolzleitnerApi(
|
|
config: config,
|
|
tokenProvider: tokenProvider,
|
|
);
|
|
|
|
try {
|
|
final health = await api.getHealthApi().health();
|
|
print(' OK: ${health.data?.length ?? 0} bytes → ${health.data}');
|
|
} on DioException catch (e) {
|
|
print(' FEHLER: ${e.message}');
|
|
print(' Response: ${e.response?.data}');
|
|
return;
|
|
}
|
|
|
|
print('\n---- 2) GET /me/cars (mit Bearer-Token) ----');
|
|
try {
|
|
final response = await api.getCarsApi().listMyCars();
|
|
final cars = response.data?.cars;
|
|
if (cars == null) {
|
|
print(' OK: leerer Body');
|
|
return;
|
|
}
|
|
print(' OK: ${cars.length} Fahrzeug(e)');
|
|
for (final c in cars) {
|
|
print(' • ${c.id} ${c.plate} active=${c.active}');
|
|
}
|
|
} on DioException catch (e) {
|
|
print(' FEHLER: ${e.message}');
|
|
print(' Response: ${e.response?.data}');
|
|
}
|
|
}
|