@Tags(['integration', 'postgres']) library; import 'dart:convert'; import 'package:cyberhybridhub_server/firebase_auth.dart'; import 'package:cyberhybridhub_server/handlers/question_source_handler.dart'; import 'package:cyberhybridhub_server/question_source_preferences_db.dart'; import 'package:cyberhybridhub_server/questions_db.dart'; import 'package:postgres/postgres.dart'; import 'package:shelf/shelf.dart'; import 'package:test/test.dart'; import '../helpers/test_db.dart'; class _FakeAuthVerifier extends FirebaseAuthVerifier { _FakeAuthVerifier() : super('test-key'); @override Future verifyBearerToken(String? authorization) async { if (authorization == null || !authorization.startsWith('Bearer ')) { return null; } final String token = authorization.substring('Bearer '.length).trim(); return token.isEmpty ? null : token; } } Future _get( Handler handler, { required String path, String? bearer, }) { return Future.value( handler( Request( 'GET', Uri.parse('http://localhost$path'), headers: { if (bearer != null) 'Authorization': 'Bearer $bearer', }, ), ), ); } Future _put( Handler handler, { required String path, required Map body, String? bearer, }) { return Future.value( handler( Request( 'PUT', Uri.parse('http://localhost$path'), body: jsonEncode(body), headers: { if (bearer != null) 'Authorization': 'Bearer $bearer', 'Content-Type': 'application/json', }, ), ), ); } void main() { TestDb? testDb; late Handler handler; late QuestionSourcePreferencesDb preferencesDb; setUpAll(() async { testDb = await TestDb.open(); if (testDb == null) { return; } preferencesDb = testDb!.questionSourcePreferencesDb; handler = questionSourceHandler( db: preferencesDb, auth: _FakeAuthVerifier(), ); }); tearDown(() async { if (testDb != null) { await testDb!.truncateTradingTables(); } }); tearDownAll(() async { await testDb?.close(); }); test('GET returns defaults for unknown user', () async { if (testDb == null) { markTestSkipped('Set DATABASE_URL or TEST_DATABASE_URL for integration tests'); return; } final Response response = await _get( handler, path: questionSourcesBasePath, bearer: 'prefs-user', ); expect(response.statusCode, 200); final Map body = jsonDecode(await response.readAsString()) as Map; final List sources = body['sources'] as List; expect(sources.length, 2); expect(sources.first['id'], 'market_history'); }); test('PUT persists preferences and GET returns saved mix', () async { if (testDb == null) { markTestSkipped('Set DATABASE_URL or TEST_DATABASE_URL for integration tests'); return; } const String uid = 'prefs-save-user'; await testDb!.seedUser(uid); final Response putResponse = await _put( handler, path: questionSourcesBasePath, bearer: uid, body: { 'sources': >[ {'id': 'market_history', 'enabled': true, 'ratio': 80}, {'id': 'spelling', 'enabled': false, 'ratio': 20}, ], }, ); expect(putResponse.statusCode, 200); final Response getResponse = await _get( handler, path: questionSourcesBasePath, bearer: uid, ); expect(getResponse.statusCode, 200); final Map body = jsonDecode(await getResponse.readAsString()) as Map; final List sources = body['sources'] as List; final Map market = sources.firstWhere( (dynamic source) => source['id'] == 'market_history', ) as Map; expect(market['ratio'], 80); }); test('ensureProspectiveQuestionQueued skips batch when market_history disabled', () async { if (testDb == null) { markTestSkipped('Set DATABASE_URL or TEST_DATABASE_URL for integration tests'); return; } const String uid = 'prefs-disabled-market-user'; await testDb!.seedUser(uid); await preferencesDb.save( uid, >[ {'id': 'market_history', 'enabled': false, 'ratio': 50}, {'id': 'spelling', 'enabled': false, 'ratio': 50}, ], ); final QuestionsDb questionsDb = testDb!.questionsDb; final service = testDb!.questionService(); await questionsDb.ensureUserExists(uid); await service.ensureProspectiveQuestionQueued(uid); final Result rows = await testDb!.connection.execute( Sql.named( ''' SELECT COUNT(*)::int FROM questions WHERE assigned_user_id = @uid ''', ), parameters: {'uid': uid}, ); expect(rows.first[0], 0); }); }