From eff600e22e6e8ea1468b9eaf575d86b722bb31bc Mon Sep 17 00:00:00 2001 From: Nikolas Rimikis Date: Thu, 5 Sep 2024 10:32:44 +0200 Subject: [PATCH] refactor(nextcloud_test): drop dependency on neon_http_client and use fixture interceptor --- .../pubspec_overrides.yaml | 2 +- .../neon_http_client/pubspec_overrides.yaml | 2 +- .../lib/src/fixture_interceptor.dart | 96 +++++++++++++++++++ .../lib/src/proxy_http_client.dart | 69 ------------- .../lib/src/test_target/test_target.dart | 19 ++-- .../packages/nextcloud_test/pubspec.yaml | 6 +- .../nextcloud_test/pubspec_overrides.yaml | 4 +- packages/nextcloud/pubspec_overrides.yaml | 4 +- 8 files changed, 114 insertions(+), 88 deletions(-) create mode 100644 packages/nextcloud/packages/nextcloud_test/lib/src/fixture_interceptor.dart delete mode 100644 packages/nextcloud/packages/nextcloud_test/lib/src/proxy_http_client.dart diff --git a/packages/interceptor_http_client/pubspec_overrides.yaml b/packages/interceptor_http_client/pubspec_overrides.yaml index d949192bd0c..8c5a77e9f0c 100644 --- a/packages/interceptor_http_client/pubspec_overrides.yaml +++ b/packages/interceptor_http_client/pubspec_overrides.yaml @@ -1,4 +1,4 @@ -# melos_managed_dependency_overrides: cookie_store,dynamite_runtime,neon_lints,nextcloud +# melos_managed_dependency_overrides: cookie_store,neon_lints dependency_overrides: cookie_store: path: ../cookie_store diff --git a/packages/neon_framework/packages/neon_http_client/pubspec_overrides.yaml b/packages/neon_framework/packages/neon_http_client/pubspec_overrides.yaml index 84a24926562..e7eb2fb277e 100644 --- a/packages/neon_framework/packages/neon_http_client/pubspec_overrides.yaml +++ b/packages/neon_framework/packages/neon_http_client/pubspec_overrides.yaml @@ -1,4 +1,4 @@ -# melos_managed_dependency_overrides: cookie_store,dynamite_runtime,neon_lints,nextcloud +# melos_managed_dependency_overrides: cookie_store,dynamite_runtime,interceptor_http_client,neon_lints,nextcloud dependency_overrides: cookie_store: path: ../../../cookie_store diff --git a/packages/nextcloud/packages/nextcloud_test/lib/src/fixture_interceptor.dart b/packages/nextcloud/packages/nextcloud_test/lib/src/fixture_interceptor.dart new file mode 100644 index 00000000000..c169fb80175 --- /dev/null +++ b/packages/nextcloud/packages/nextcloud_test/lib/src/fixture_interceptor.dart @@ -0,0 +1,96 @@ +import 'dart:convert'; +import 'dart:io' show HttpHeaders; +import 'dart:typed_data'; + +import 'package:http/http.dart' as http; +import 'package:interceptor_http_client/interceptor_http_client.dart'; + +/// An http interceptor that records every request and adds them to a fixture. +final class FixtureInterceptor implements HttpInterceptor { + /// Creates a new fixture interceptor. + const FixtureInterceptor({ + required this.appendFixture, + }); + + /// Callback for adding a recorded request to the fixture. + final void Function(String fixture) appendFixture; + + @override + bool shouldInterceptRequest(http.BaseRequest request) { + // TODO: use resetFixture and intercept all requests + return request.url.path != '/index.php/csrftoken'; + } + + @override + Future interceptRequest({required http.BaseRequest request}) async { + assert( + shouldInterceptRequest(request), + 'Request should not be intercepted.', + ); + + final bodyBytes = switch (request) { + http.Request() => request.bodyBytes, + _ => await request.finalize().toBytes(), + }; + + final fixture = _formatHttpRequest(request, bodyBytes); + appendFixture(fixture); + + return switch (request) { + http.Request() => request, + _ => http.Request(request.method, request.url) + ..persistentConnection = request.persistentConnection + ..followRedirects = request.followRedirects + ..maxRedirects = request.maxRedirects + ..headers.addAll(request.headers) + ..bodyBytes = bodyBytes, + }; + } + + @override + bool shouldInterceptResponse(http.StreamedResponse response) { + return false; + } + + @override + Never interceptResponse({required http.StreamedResponse response, required Uri url}) { + throw UnsupportedError('Fixtures may not intercept responses.'); + } + + static String _formatHttpRequest(http.BaseRequest request, Uint8List body) { + final buffer = StringBuffer('${request.method.toUpperCase()} ${request.url.replace(port: 80)}'); + + final headers = []; + for (final header in request.headers.entries) { + final name = header.key.toLowerCase(); + var value = header.value; + + if (name == HttpHeaders.hostHeader) { + continue; + } else if (name == HttpHeaders.cookieHeader) { + continue; + } else if (name == HttpHeaders.authorizationHeader) { + value = '${value.split(' ').first} mock'; + } else if (name == 'requesttoken') { + value = 'token'; + } else if (name == 'destination') { + value = Uri.parse(value).replace(port: 80).toString(); + } + + headers.add('\n$name: $value'); + } + + headers.sort(); + buffer.writeAll(headers); + + if (body.isNotEmpty) { + try { + buffer.write('\n${utf8.decode(body)}'); + } catch (_) { + buffer.write('\n${base64.encode(body)}'); + } + } + + return buffer.toString(); + } +} diff --git a/packages/nextcloud/packages/nextcloud_test/lib/src/proxy_http_client.dart b/packages/nextcloud/packages/nextcloud_test/lib/src/proxy_http_client.dart deleted file mode 100644 index 9aaa36ab4f8..00000000000 --- a/packages/nextcloud/packages/nextcloud_test/lib/src/proxy_http_client.dart +++ /dev/null @@ -1,69 +0,0 @@ -// ignore_for_file: invalid_use_of_visible_for_testing_member - -import 'dart:convert'; -import 'dart:typed_data'; - -import 'package:http/http.dart'; -import 'package:http/testing.dart'; -import 'package:universal_io/io.dart'; - -/// Gets a mocked [HttpClient] that proxies the request to a real [HttpClient]. -/// For every requests it calls [onRequest] which contains the formatted request. -BaseClient getProxyHttpClient({ - required void Function(String fixture) onRequest, -}) { - final realClient = Client(); - return MockClient.streaming((baseRequest, bytesStream) async { - final bodyBytes = await bytesStream.toBytes(); - if (baseRequest.url.path != '/index.php/csrftoken') { - final fixture = _formatHttpRequest(baseRequest, bodyBytes); - onRequest(fixture); - } - - final request = Request(baseRequest.method, baseRequest.url) - ..persistentConnection = baseRequest.persistentConnection - ..followRedirects = baseRequest.followRedirects - ..maxRedirects = baseRequest.maxRedirects - ..headers.addAll(baseRequest.headers) - ..bodyBytes = bodyBytes; - - return realClient.send(request); - }); -} - -String _formatHttpRequest(BaseRequest request, Uint8List body) { - final buffer = StringBuffer('${request.method.toUpperCase()} ${request.url.replace(port: 80)}'); - - final headers = []; - for (final header in request.headers.entries) { - final name = header.key.toLowerCase(); - var value = header.value; - - if (name == HttpHeaders.hostHeader) { - continue; - } else if (name == HttpHeaders.cookieHeader) { - continue; - } else if (name == HttpHeaders.authorizationHeader) { - value = '${value.split(' ').first} mock'; - } else if (name == 'requesttoken') { - value = 'token'; - } else if (name == 'destination') { - value = Uri.parse(value).replace(port: 80).toString(); - } - - headers.add('\n$name: $value'); - } - - headers.sort(); - buffer.writeAll(headers); - - if (body.isNotEmpty) { - try { - buffer.write('\n${utf8.decode(body)}'); - } catch (_) { - buffer.write('\n${base64.encode(body)}'); - } - } - - return buffer.toString(); -} diff --git a/packages/nextcloud/packages/nextcloud_test/lib/src/test_target/test_target.dart b/packages/nextcloud/packages/nextcloud_test/lib/src/test_target/test_target.dart index 560f5b78d37..1ea74e3e67d 100644 --- a/packages/nextcloud/packages/nextcloud_test/lib/src/test_target/test_target.dart +++ b/packages/nextcloud/packages/nextcloud_test/lib/src/test_target/test_target.dart @@ -3,12 +3,13 @@ import 'dart:io'; import 'package:built_collection/built_collection.dart'; import 'package:cookie_store/cookie_store.dart'; +import 'package:http/http.dart' as http; +import 'package:interceptor_http_client/interceptor_http_client.dart'; import 'package:meta/meta.dart'; -import 'package:neon_http_client/neon_http_client.dart'; import 'package:nextcloud/nextcloud.dart'; +import 'package:nextcloud_test/src/fixture_interceptor.dart'; import 'package:nextcloud_test/src/fixtures.dart'; import 'package:nextcloud_test/src/models/models.dart'; -import 'package:nextcloud_test/src/proxy_http_client.dart'; import 'package:nextcloud_test/src/test_target/docker_container.dart'; import 'package:nextcloud_test/src/test_target/local.dart'; import 'package:version/version.dart'; @@ -74,12 +75,14 @@ abstract class TestTargetInstance { appPassword = await createAppPassword(username); } - final httpClient = NeonHttpClient( - baseURL: hostURL, - cookieStore: CookieStore(), - client: getProxyHttpClient( - onRequest: appendFixture, - ), + final httpClient = InterceptorHttpClient( + baseClient: http.Client(), + interceptors: BuiltList([ + CookieStoreInterceptor( + cookieStore: CookieStore(), + ), + const FixtureInterceptor(appendFixture: appendFixture), + ]), ); return NextcloudClient( diff --git a/packages/nextcloud/packages/nextcloud_test/pubspec.yaml b/packages/nextcloud/packages/nextcloud_test/pubspec.yaml index 9de5a57e03f..65f0f9f9043 100644 --- a/packages/nextcloud/packages/nextcloud_test/pubspec.yaml +++ b/packages/nextcloud/packages/nextcloud_test/pubspec.yaml @@ -13,11 +13,11 @@ dependencies: path: packages/cookie_store glob: ^2.1.2 http: ^1.2.0 - meta: ^1.0.0 - neon_http_client: + interceptor_http_client: git: url: https://github.com/nextcloud/neon - path: packages/neon_http_client + path: packages/interceptor_http_client + meta: ^1.0.0 nextcloud: ^7.0.0 path: ^1.9.0 process_run: ^1.0.0+1 diff --git a/packages/nextcloud/packages/nextcloud_test/pubspec_overrides.yaml b/packages/nextcloud/packages/nextcloud_test/pubspec_overrides.yaml index 7700aab4d4b..cfe67bc0b7e 100644 --- a/packages/nextcloud/packages/nextcloud_test/pubspec_overrides.yaml +++ b/packages/nextcloud/packages/nextcloud_test/pubspec_overrides.yaml @@ -1,4 +1,4 @@ -# melos_managed_dependency_overrides: cookie_store,dynamite_runtime,interceptor_http_client,neon_http_client,neon_lints,nextcloud +# melos_managed_dependency_overrides: cookie_store,dynamite_runtime,interceptor_http_client,neon_lints,nextcloud dependency_overrides: cookie_store: path: ../../../cookie_store @@ -6,8 +6,6 @@ dependency_overrides: path: ../../../dynamite/packages/dynamite_runtime interceptor_http_client: path: ../../../interceptor_http_client - neon_http_client: - path: ../../../neon_framework/packages/neon_http_client neon_lints: path: ../../../neon_lints nextcloud: diff --git a/packages/nextcloud/pubspec_overrides.yaml b/packages/nextcloud/pubspec_overrides.yaml index 5f17d383195..d31cf22a4a6 100644 --- a/packages/nextcloud/pubspec_overrides.yaml +++ b/packages/nextcloud/pubspec_overrides.yaml @@ -1,4 +1,4 @@ -# melos_managed_dependency_overrides: cookie_store,dynamite,dynamite_runtime,interceptor_http_client,neon_http_client,neon_lints,nextcloud_test +# melos_managed_dependency_overrides: cookie_store,dynamite,dynamite_runtime,interceptor_http_client,neon_lints,nextcloud_test dependency_overrides: cookie_store: path: ../cookie_store @@ -8,8 +8,6 @@ dependency_overrides: path: ../dynamite/packages/dynamite_runtime interceptor_http_client: path: ../interceptor_http_client - neon_http_client: - path: ../neon_framework/packages/neon_http_client neon_lints: path: ../neon_lints nextcloud_test: