From 50133c16dbc13947e98d7b00eb762bade6022471 Mon Sep 17 00:00:00 2001 From: Bryan Oltman Date: Tue, 30 May 2023 15:58:36 -0400 Subject: [PATCH] chore(shorebird_code_push_client): verbose log requests (#563) --- packages/shorebird_cli/lib/src/auth/auth.dart | 35 +++++++++++++++---- packages/shorebird_cli/lib/src/command.dart | 9 ++--- .../shorebird_cli/lib/src/command_runner.dart | 10 +++--- .../test/src/auth/auth_test.dart | 27 ++++++++++++-- .../test/src/commands/command_test.dart | 23 ++++++++++++ 5 files changed, 87 insertions(+), 17 deletions(-) create mode 100644 packages/shorebird_cli/test/src/commands/command_test.dart diff --git a/packages/shorebird_cli/lib/src/auth/auth.dart b/packages/shorebird_cli/lib/src/auth/auth.dart index 84ddbd14..cf33ee5b 100644 --- a/packages/shorebird_cli/lib/src/auth/auth.dart +++ b/packages/shorebird_cli/lib/src/auth/auth.dart @@ -4,6 +4,7 @@ import 'dart:io'; import 'package:cli_util/cli_util.dart'; import 'package:googleapis_auth/auth_io.dart' as oauth2; import 'package:http/http.dart' as http; +import 'package:mason_logger/mason_logger.dart'; import 'package:path/path.dart' as p; import 'package:shorebird_cli/src/auth/jwt.dart'; import 'package:shorebird_cli/src/command.dart'; @@ -45,18 +46,34 @@ typedef OnRefreshCredentials = void Function( oauth2.AccessCredentials credentials, ); -class AuthenticatedClient extends http.BaseClient { - AuthenticatedClient({ - required oauth2.AccessCredentials credentials, +class LoggingClient extends http.BaseClient { + LoggingClient({ required http.Client httpClient, + required Logger logger, + }) : _baseClient = httpClient, + _logger = logger; + + final http.Client _baseClient; + final Logger _logger; + + @override + Future send(http.BaseRequest request) async { + _logger.detail('[HTTP] $request'); + return _baseClient.send(request); + } +} + +class AuthenticatedClient extends LoggingClient { + AuthenticatedClient({ + required super.httpClient, + required super.logger, + required oauth2.AccessCredentials credentials, required OnRefreshCredentials onRefreshCredentials, RefreshCredentials refreshCredentials = oauth2.refreshCredentials, }) : _credentials = credentials, - _baseClient = httpClient, _onRefreshCredentials = onRefreshCredentials, _refreshCredentials = refreshCredentials; - final http.Client _baseClient; final OnRefreshCredentials _onRefreshCredentials; final RefreshCredentials _refreshCredentials; oauth2.AccessCredentials _credentials; @@ -73,17 +90,19 @@ class AuthenticatedClient extends http.BaseClient { } final token = _credentials.idToken; request.headers['Authorization'] = 'Bearer $token'; - return _baseClient.send(request); + return super.send(request); } } class Auth { Auth({ + Logger? logger, http.Client? httpClient, String? credentialsDir, ObtainAccessCredentials? obtainAccessCredentials, CodePushClientBuilder? buildCodePushClient, - }) : _httpClient = httpClient ?? http.Client(), + }) : logger = logger ?? Logger(), + _httpClient = httpClient ?? http.Client(), _credentialsDir = credentialsDir ?? applicationConfigHome(executableName), _obtainAccessCredentials = obtainAccessCredentials ?? @@ -96,6 +115,7 @@ class Auth { final String _credentialsDir; final ObtainAccessCredentials _obtainAccessCredentials; final CodePushClientBuilder _buildCodePushClient; + final Logger logger; String get credentialsFilePath { return p.join(_credentialsDir, 'credentials.json'); @@ -108,6 +128,7 @@ class Auth { credentials: credentials, httpClient: _httpClient, onRefreshCredentials: _flushCredentials, + logger: logger, ); } diff --git a/packages/shorebird_cli/lib/src/command.dart b/packages/shorebird_cli/lib/src/command.dart index 438a45a4..66eeef77 100644 --- a/packages/shorebird_cli/lib/src/command.dart +++ b/packages/shorebird_cli/lib/src/command.dart @@ -37,12 +37,13 @@ abstract class ShorebirdCommand extends Command { Cache? cache, CodePushClientBuilder? buildCodePushClient, List? validators, // For mocking. - }) : auth = auth ?? Auth(), - cache = cache ?? Cache(), + }) : cache = cache ?? Cache(), buildCodePushClient = buildCodePushClient ?? CodePushClient.new, - validators = validators ?? _defaultValidators(); + validators = validators ?? _defaultValidators() { + this.auth = auth ?? Auth(logger: logger); + } - final Auth auth; + late final Auth auth; final Cache cache; final CodePushClientBuilder buildCodePushClient; final Logger logger; diff --git a/packages/shorebird_cli/lib/src/command_runner.dart b/packages/shorebird_cli/lib/src/command_runner.dart index 822df80c..770b47c3 100644 --- a/packages/shorebird_cli/lib/src/command_runner.dart +++ b/packages/shorebird_cli/lib/src/command_runner.dart @@ -27,13 +27,18 @@ class ShorebirdCliCommandRunner extends CompletionCommandRunner { argParser ..addFlag( 'version', - abbr: 'v', negatable: false, help: 'Print the current version.', ) ..addFlag( 'verbose', + abbr: 'v', help: 'Noisy logging, including all shell commands executed.', + callback: (verbose) { + if (verbose) { + _logger.level = Level.verbose; + } + }, ) ..addOption( 'local-engine-src-path', @@ -77,9 +82,6 @@ class ShorebirdCliCommandRunner extends CompletionCommandRunner { Future run(Iterable args) async { try { final topLevelResults = parse(args); - if (topLevelResults['verbose'] == true) { - _logger.level = Level.verbose; - } // Set up our context before running the command. engineConfig = EngineConfig( diff --git a/packages/shorebird_cli/test/src/auth/auth_test.dart b/packages/shorebird_cli/test/src/auth/auth_test.dart index 2d80ec8b..a2814334 100644 --- a/packages/shorebird_cli/test/src/auth/auth_test.dart +++ b/packages/shorebird_cli/test/src/auth/auth_test.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:googleapis_auth/googleapis_auth.dart'; import 'package:http/http.dart' as http; +import 'package:mason_logger/mason_logger.dart'; import 'package:mocktail/mocktail.dart'; import 'package:path/path.dart' as p; import 'package:shorebird_cli/src/auth/auth.dart'; @@ -11,10 +12,12 @@ import 'package:test/test.dart'; class _FakeBaseRequest extends Fake implements http.BaseRequest {} -class _MockHttpClient extends Mock implements http.Client {} - class _MockCodePushClient extends Mock implements CodePushClient {} +class _MockLogger extends Mock implements Logger {} + +class _MockHttpClient extends Mock implements http.Client {} + void main() { group('Auth', () { const idToken = @@ -40,6 +43,7 @@ void main() { late String credentialsDir; late http.Client httpClient; late CodePushClient codePushClient; + late Logger logger; late Auth auth; setUpAll(() { @@ -56,6 +60,7 @@ void main() { obtainAccessCredentials: (clientId, scopes, client, userPrompt) async { return accessCredentials; }, + logger: logger, ); } @@ -68,11 +73,27 @@ void main() { credentialsDir = Directory.systemTemp.createTempSync().path; httpClient = _MockHttpClient(); codePushClient = _MockCodePushClient(); + logger = _MockLogger(); auth = buildAuth(); when(() => codePushClient.getCurrentUser()).thenAnswer((_) async => user); }); + test('uses default logger if none is provided', () { + final auth = Auth( + credentialsDir: credentialsDir, + httpClient: httpClient, + buildCodePushClient: ({Uri? hostedUri, http.Client? httpClient}) { + return codePushClient; + }, + obtainAccessCredentials: (clientId, scopes, client, userPrompt) async { + return accessCredentials; + }, + ); + + expect(auth.logger, isA()); + }); + group('AuthenticatedClient', () { test('refreshes and uses new token when credentials are expired.', () async { @@ -101,6 +122,7 @@ void main() { onRefreshCredentials: onRefreshCredentialsCalls.add, refreshCredentials: (clientId, credentials, client) async => accessCredentials, + logger: logger, ); await client.get(Uri.parse('https://example.com')); @@ -129,6 +151,7 @@ void main() { credentials: accessCredentials, httpClient: httpClient, onRefreshCredentials: onRefreshCredentialsCalls.add, + logger: logger, ); await client.get(Uri.parse('https://example.com')); diff --git a/packages/shorebird_cli/test/src/commands/command_test.dart b/packages/shorebird_cli/test/src/commands/command_test.dart new file mode 100644 index 00000000..6fc21e0b --- /dev/null +++ b/packages/shorebird_cli/test/src/commands/command_test.dart @@ -0,0 +1,23 @@ +import 'package:mason_logger/mason_logger.dart'; +import 'package:shorebird_cli/src/command.dart'; +import 'package:test/test.dart'; + +void main() { + group(ShorebirdCommand, () { + test('passes logger to auth in default builder', () { + final logger = Logger(); + final command = TestCommand(logger: logger); + expect(command.auth.logger, logger); + }); + }); +} + +class TestCommand extends ShorebirdCommand { + TestCommand({required super.logger}); + + @override + String get description => 'A test command'; + + @override + String get name => 'test'; +}