Server-User (Dustin, Baka, Tinker) melden sich beim Öffnen des YouTube-Bereichs automatisch im Hintergrund mit ihren Navidrome- Zugangsdaten beim Baka-Konto an (BakaAuth.autoAnmelden) — die manuelle Anmeldung bleibt nur für Gäste sichtbar. Schlägt die Auto-Anmeldung fehl, gibt es einen Rückfallweg zur manuellen Anmeldung, statt den User auszusperren. Login-Buttons vergrößert. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CcDiyJdVRqh1TtJk5JiabX
151 lines
4.9 KiB
Dart
151 lines
4.9 KiB
Dart
import 'dart:convert';
|
|
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:http/http.dart' as http;
|
|
import 'package:http/testing.dart';
|
|
import 'package:melo/services/baka_auth.dart';
|
|
|
|
/// Einfacher Speicher im Arbeitsspeicher — FlutterSecureStorage braucht
|
|
/// Plattform-Kanäle und ist im Test nicht verfügbar.
|
|
class _MemorySpeicher implements TokenSpeicher {
|
|
final Map<String, String> werte = {};
|
|
|
|
@override
|
|
Future<String?> lesen(String key) async => werte[key];
|
|
|
|
@override
|
|
Future<void> schreiben(String key, String wert) async => werte[key] = wert;
|
|
|
|
@override
|
|
Future<void> loeschen(String key) async => werte.remove(key);
|
|
}
|
|
|
|
void main() {
|
|
test('Anmeldung mit gültigen Daten speichert den Token', () async {
|
|
final speicher = _MemorySpeicher();
|
|
late String gesendet;
|
|
final client = MockClient((req) async {
|
|
gesendet = req.body;
|
|
return http.Response(jsonEncode({'token': 'jwt-abc'}), 200);
|
|
});
|
|
final auth = BakaAuth(client: client, speicher: speicher);
|
|
|
|
final fehler = await auth.anmelden('Baka', 'geheim');
|
|
|
|
expect(fehler, isNull);
|
|
expect(auth.istAngemeldet, isTrue);
|
|
expect(auth.benutzer, 'Baka');
|
|
expect(speicher.werte['baka_token'], 'jwt-abc');
|
|
expect(jsonDecode(gesendet), {'username': 'Baka', 'password': 'geheim'});
|
|
});
|
|
|
|
test('Auth-Header trägt den Token als Bearer', () async {
|
|
final client = MockClient(
|
|
(_) async => http.Response(jsonEncode({'token': 'jwt-abc'}), 200));
|
|
final auth = BakaAuth(client: client, speicher: _MemorySpeicher());
|
|
await auth.anmelden('Baka', 'geheim');
|
|
|
|
expect(auth.authHeader['Authorization'], 'Bearer jwt-abc');
|
|
});
|
|
|
|
test('Falsches Passwort liefert die Server-Meldung, obwohl HTTP 200 kommt',
|
|
() async {
|
|
// Der Baka-Auth-Server antwortet auch bei Fehlern mit Status 200.
|
|
final client = MockClient((_) async => http.Response(
|
|
jsonEncode({'status': 'error', 'message': 'Falscher Benutzer'}), 200));
|
|
final auth = BakaAuth(client: client, speicher: _MemorySpeicher());
|
|
|
|
final fehler = await auth.anmelden('Baka', 'falsch');
|
|
|
|
expect(fehler, 'Falscher Benutzer');
|
|
expect(auth.istAngemeldet, isFalse);
|
|
});
|
|
|
|
test('Nicht erreichbarer Server meldet einen Verbindungsfehler', () async {
|
|
final client = MockClient((_) async => throw const SocketAusfall());
|
|
final auth = BakaAuth(client: client, speicher: _MemorySpeicher());
|
|
|
|
final fehler = await auth.anmelden('Baka', 'geheim');
|
|
|
|
expect(fehler, 'Keine Verbindung zum Anmelde-Server');
|
|
expect(auth.istAngemeldet, isFalse);
|
|
});
|
|
|
|
test('laden() stellt einen gespeicherten Token wieder her', () async {
|
|
final speicher = _MemorySpeicher();
|
|
speicher.werte['baka_token'] = 'jwt-alt';
|
|
speicher.werte['baka_user'] = 'Baka';
|
|
final auth = BakaAuth(
|
|
client: MockClient((_) async => http.Response('', 500)),
|
|
speicher: speicher);
|
|
|
|
await auth.laden();
|
|
|
|
expect(auth.istAngemeldet, isTrue);
|
|
expect(auth.benutzer, 'Baka');
|
|
});
|
|
|
|
test('autoAnmelden meldet mit den übergebenen Zugangsdaten an', () async {
|
|
late String gesendet;
|
|
final client = MockClient((req) async {
|
|
gesendet = req.body;
|
|
return http.Response(jsonEncode({'token': 'jwt-server'}), 200);
|
|
});
|
|
final auth = BakaAuth(client: client, speicher: _MemorySpeicher());
|
|
|
|
await auth.autoAnmelden('Tinker', 'geheim2');
|
|
|
|
expect(auth.istAngemeldet, isTrue);
|
|
expect(auth.benutzer, 'Tinker');
|
|
expect(jsonDecode(gesendet), {'username': 'Tinker', 'password': 'geheim2'});
|
|
});
|
|
|
|
test('autoAnmelden greift nicht ein, wenn schon angemeldet', () async {
|
|
var aufrufe = 0;
|
|
final client = MockClient((_) async {
|
|
aufrufe++;
|
|
return http.Response(jsonEncode({'token': 'jwt-abc'}), 200);
|
|
});
|
|
final auth = BakaAuth(client: client, speicher: _MemorySpeicher());
|
|
await auth.anmelden('Baka', 'geheim');
|
|
|
|
await auth.autoAnmelden('Tinker', 'geheim2');
|
|
|
|
expect(aufrufe, 1);
|
|
expect(auth.benutzer, 'Baka');
|
|
});
|
|
|
|
test('autoAnmelden tut nichts ohne Zugangsdaten', () async {
|
|
var aufrufe = 0;
|
|
final client = MockClient((_) async {
|
|
aufrufe++;
|
|
return http.Response(jsonEncode({'token': 'jwt'}), 200);
|
|
});
|
|
final auth = BakaAuth(client: client, speicher: _MemorySpeicher());
|
|
|
|
await auth.autoAnmelden('', '');
|
|
|
|
expect(aufrufe, 0);
|
|
expect(auth.istAngemeldet, isFalse);
|
|
});
|
|
|
|
test('Abmelden löscht Token und Benutzer aus dem Speicher', () async {
|
|
final speicher = _MemorySpeicher();
|
|
final auth = BakaAuth(
|
|
client: MockClient(
|
|
(_) async => http.Response(jsonEncode({'token': 'jwt-abc'}), 200)),
|
|
speicher: speicher);
|
|
await auth.anmelden('Baka', 'geheim');
|
|
|
|
await auth.abmelden();
|
|
|
|
expect(auth.istAngemeldet, isFalse);
|
|
expect(speicher.werte, isEmpty);
|
|
});
|
|
}
|
|
|
|
/// Steht im Test für einen Netzwerkausfall.
|
|
class SocketAusfall implements Exception {
|
|
const SocketAusfall();
|
|
}
|