chore(shorebird_code_push_client): verbose log requests (#563)

This commit is contained in:
Bryan Oltman
2023-05-30 15:58:36 -04:00
committed by GitHub
parent 6abe32b956
commit 50133c16db
5 changed files with 87 additions and 17 deletions
+28 -7
View File
@@ -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<http.StreamedResponse> 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,
);
}
+5 -4
View File
@@ -37,12 +37,13 @@ abstract class ShorebirdCommand extends Command<int> {
Cache? cache,
CodePushClientBuilder? buildCodePushClient,
List<Validator>? 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;
@@ -27,13 +27,18 @@ class ShorebirdCliCommandRunner extends CompletionCommandRunner<int> {
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<int> {
Future<int> run(Iterable<String> 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(
@@ -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<Logger>());
});
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'));
@@ -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';
}