187 lines
5.1 KiB
Dart
187 lines
5.1 KiB
Dart
@Tags(<String>['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<String?> 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<Response> _get(
|
|
Handler handler, {
|
|
required String path,
|
|
String? bearer,
|
|
}) {
|
|
return Future<Response>.value(
|
|
handler(
|
|
Request(
|
|
'GET',
|
|
Uri.parse('http://localhost$path'),
|
|
headers: <String, String>{
|
|
if (bearer != null) 'Authorization': 'Bearer $bearer',
|
|
},
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Future<Response> _put(
|
|
Handler handler, {
|
|
required String path,
|
|
required Map<String, dynamic> body,
|
|
String? bearer,
|
|
}) {
|
|
return Future<Response>.value(
|
|
handler(
|
|
Request(
|
|
'PUT',
|
|
Uri.parse('http://localhost$path'),
|
|
body: jsonEncode(body),
|
|
headers: <String, String>{
|
|
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<String, dynamic> body =
|
|
jsonDecode(await response.readAsString()) as Map<String, dynamic>;
|
|
final List<dynamic> sources = body['sources'] as List<dynamic>;
|
|
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: <String, dynamic>{
|
|
'sources': <Map<String, dynamic>>[
|
|
<String, dynamic>{'id': 'market_history', 'enabled': true, 'ratio': 80},
|
|
<String, dynamic>{'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<String, dynamic> body =
|
|
jsonDecode(await getResponse.readAsString()) as Map<String, dynamic>;
|
|
final List<dynamic> sources = body['sources'] as List<dynamic>;
|
|
final Map<String, dynamic> market = sources.firstWhere(
|
|
(dynamic source) => source['id'] == 'market_history',
|
|
) as Map<String, dynamic>;
|
|
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,
|
|
<Map<String, dynamic>>[
|
|
<String, dynamic>{'id': 'market_history', 'enabled': false, 'ratio': 50},
|
|
<String, dynamic>{'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: <String, dynamic>{'uid': uid},
|
|
);
|
|
expect(rows.first[0], 0);
|
|
});
|
|
}
|