mirror of
https://github.com/kuhyx/diet-guard.git
synced 2026-11-10 19:27:14 +01:00
Make the sync-account route testable, and cover every branch
Same change todo just took: the route read its own configuration from Platform.environment and $HOME, so only the "disabled" branch was reachable from a test. Both are now constructor parameters defaulting to the environment -- production behaviour unchanged -- and the four outcomes are covered: 404 disabled, 200 with the account, 404 when ~/.config/crdt-sync/ is incomplete, 404 when firebase.json has no usable email. 522 tests, analyzer clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0177xwzcpfpWG2qca8Mr39q9
This commit is contained in:
parent
55fade1e15
commit
19991f3600
@ -35,7 +35,20 @@ class WrapperServer {
|
||||
required this.webRoot,
|
||||
required this.dataDir,
|
||||
required this.gitHubProxy,
|
||||
});
|
||||
bool? serveSyncAccount,
|
||||
String? syncConfigDir,
|
||||
}) : serveSyncAccount =
|
||||
serveSyncAccount ??
|
||||
(Platform.environment[kSyncAccountEnvVar] ?? '').isNotEmpty,
|
||||
syncConfigDir =
|
||||
syncConfigDir ??
|
||||
p.join(Platform.environment['HOME'] ?? '', '.config', 'crdt-sync');
|
||||
|
||||
/// Whether the sync-account route answers; off unless explicitly enabled.
|
||||
final bool serveSyncAccount;
|
||||
|
||||
/// Directory holding `firebase.json` and `password`.
|
||||
final String syncConfigDir;
|
||||
|
||||
/// Directory holding the built Flutter web assets.
|
||||
final String webRoot;
|
||||
@ -114,17 +127,12 @@ class WrapperServer {
|
||||
/// the same reasoning that keeps the GitHub token in [gitHubProxy] instead
|
||||
/// of the browser.
|
||||
Future<void> _syncAccount(HttpRequest request) async {
|
||||
if ((Platform.environment[kSyncAccountEnvVar] ?? '').isEmpty) {
|
||||
if (!serveSyncAccount) {
|
||||
request.response.statusCode = HttpStatus.notFound;
|
||||
return;
|
||||
}
|
||||
final configDir = p.join(
|
||||
Platform.environment['HOME'] ?? '',
|
||||
'.config',
|
||||
'crdt-sync',
|
||||
);
|
||||
final configFile = File(p.join(configDir, 'firebase.json'));
|
||||
final passwordFile = File(p.join(configDir, 'password'));
|
||||
final configFile = File(p.join(syncConfigDir, 'firebase.json'));
|
||||
final passwordFile = File(p.join(syncConfigDir, 'password'));
|
||||
if (!configFile.existsSync() || !passwordFile.existsSync()) {
|
||||
stderr.writeln(
|
||||
'Sync account requested but ~/.config/crdt-sync/ is incomplete — '
|
||||
|
||||
@ -7,6 +7,7 @@ import 'dart:io';
|
||||
|
||||
import 'package:diet_guard_app/desktop/github_proxy.dart';
|
||||
import 'package:diet_guard_app/desktop/wrapper_server.dart';
|
||||
import 'package:crdt_sync/crdt_sync.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:http/testing.dart';
|
||||
@ -20,7 +21,10 @@ void main() {
|
||||
late List<http.Request> outbound;
|
||||
late Map<String, http.Response> canned;
|
||||
|
||||
Future<void> startServer() async {
|
||||
Future<void> startServer({
|
||||
bool serveSyncAccount = false,
|
||||
String? syncConfigDir,
|
||||
}) async {
|
||||
outbound = [];
|
||||
canned = {};
|
||||
final proxy = GitHubProxy(
|
||||
@ -36,6 +40,8 @@ void main() {
|
||||
webRoot: webRoot,
|
||||
dataDir: dataDir,
|
||||
gitHubProxy: proxy,
|
||||
serveSyncAccount: serveSyncAccount,
|
||||
syncConfigDir: syncConfigDir,
|
||||
);
|
||||
await server.start(0);
|
||||
}
|
||||
@ -285,4 +291,59 @@ void main() {
|
||||
expect(typeOf('data.bin').mimeType, 'application/octet-stream');
|
||||
});
|
||||
});
|
||||
|
||||
group('sync-account provisioning', () {
|
||||
/// Writes [files] into a temp config dir and restarts with the route on.
|
||||
Future<String> enableWith(Map<String, String> files) async {
|
||||
final configDir = Directory(p.join(tempDir.path, 'crdt-sync'))
|
||||
..createSync(recursive: true);
|
||||
files.forEach((name, contents) {
|
||||
File(p.join(configDir.path, name)).writeAsStringSync(contents);
|
||||
});
|
||||
await server.stop();
|
||||
await startServer(serveSyncAccount: true, syncConfigDir: configDir.path);
|
||||
return 'http://localhost:${server.port}';
|
||||
}
|
||||
|
||||
test('is 404 when not enabled', () async {
|
||||
// The default, and the whole security posture: a credential route must
|
||||
// not be reachable just because the wrapper is running.
|
||||
final response = await http.get(url(kSyncAccountPath));
|
||||
|
||||
expect(response.statusCode, HttpStatus.notFound);
|
||||
});
|
||||
|
||||
test('serves the account when enabled', () async {
|
||||
final origin = await enableWith({
|
||||
'firebase.json': '{"email":"a@b.c"}',
|
||||
'password': 'pw\n',
|
||||
});
|
||||
|
||||
final response = await http.get(Uri.parse('$origin$kSyncAccountPath'));
|
||||
final account = FirebaseAccount.tryParse(response.body);
|
||||
|
||||
expect(response.statusCode, HttpStatus.ok);
|
||||
expect(account?.email, 'a@b.c');
|
||||
expect(account?.password, 'pw');
|
||||
});
|
||||
|
||||
test('is 404 when the config files are absent', () async {
|
||||
final origin = await enableWith({});
|
||||
|
||||
final response = await http.get(Uri.parse('$origin$kSyncAccountPath'));
|
||||
|
||||
expect(response.statusCode, HttpStatus.notFound);
|
||||
});
|
||||
|
||||
test('is 404 when firebase.json has no usable email', () async {
|
||||
final origin = await enableWith({
|
||||
'firebase.json': '{"apiKey":"x"}',
|
||||
'password': 'pw',
|
||||
});
|
||||
|
||||
final response = await http.get(Uri.parse('$origin$kSyncAccountPath'));
|
||||
|
||||
expect(response.statusCode, HttpStatus.notFound);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user