Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(nextcloud_test,nextcloud): run tests on web #2484

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions commitlint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ rules:
- news_app
- nextcloud
- nextcloud_test
- nextcloud_test_api
- nextcloud_test_presets
- notes_app
- notifications_app
Expand Down
16 changes: 16 additions & 0 deletions packages/nextcloud/dart_test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
platforms:
- vm
- chrome

define_platforms:
chromium:
name: Chromium
extends: chrome
settings:
executable: chromium

override_platforms:
chrome:
settings:
arguments: --disable-web-security
executable: chromium
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
export 'src/fixtures.dart' hide appendFixture;
export 'src/presets.dart';
/// Nextcloud test library.
///
/// Handles the server setup and allows to run tests against different test presets.
/// All http requests of a test will be validated against predefined fixtures.
library;

export 'src/nextcloud_test.dart' show NextcloudTester, NextcloudTesterCallback, closeFixture, presets, resetFixture;

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export 'nextcloud_test/fixture_interceptor.dart';
export 'nextcloud_test/fixtures.dart';
export 'nextcloud_test/nextcloud_tester.dart';
export 'nextcloud_test/presets.dart';
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import 'dart:typed_data';

import 'package:http/http.dart' as http;
import 'package:interceptor_http_client/interceptor_http_client.dart';
import 'package:meta/meta.dart';

/// An http interceptor that records every request and adds them to a fixture.
@internal
final class FixtureInterceptor implements HttpInterceptor {
/// Creates a new fixture interceptor.
const FixtureInterceptor({
Expand Down Expand Up @@ -65,16 +67,19 @@ final class FixtureInterceptor implements HttpInterceptor {
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();
switch (name) {
case HttpHeaders.hostHeader:
case HttpHeaders.cookieHeader:
continue;

case HttpHeaders.authorizationHeader:
value = '${value.split(' ').first} mock';

case 'requesttoken':
value = 'token';

case 'destination':
value = Uri.parse(value).replace(port: 80).toString();
}

headers.add('\n$name: $value');
Expand All @@ -86,7 +91,7 @@ final class FixtureInterceptor implements HttpInterceptor {
if (body.isNotEmpty) {
try {
buffer.write('\n${utf8.decode(body)}');
} catch (_) {
} on FormatException catch (_) {
buffer.write('\n${base64.encode(body)}');
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import 'package:built_collection/built_collection.dart';
import 'package:nextcloud/webdav.dart';
import 'package:nextcloud_test/src/models/models.dart';
import 'package:meta/meta.dart';
import 'package:nextcloud_test_api/client.dart';
import 'package:test/expect.dart';
// ignore: implementation_imports
import 'package:test_api/src/backend/invoker.dart';
import 'package:universal_io/io.dart';

var _closed = false;
final _fixture = <String>[];

/// Appends some [data] to the current fixture.
@internal
void appendFixture(String data) {
if (!_closed) {
_fixture.add(data);
Expand All @@ -29,8 +29,9 @@ void resetFixture() {

/// Validates that the requests match the stored fixtures.
///
/// If there is no stored fixture a new one is created.
void validateFixture(NextcloudTester tester) {
/// If there is no stored fixture an empty one is created.
@internal
Future<void> validateFixture(NextcloudTestApiClient client, Preset preset) async {
if (_fixture.isEmpty) {
return;
}
Expand All @@ -52,37 +53,31 @@ void validateFixture(NextcloudTester tester) {

// Remove the groups that are the preset name and the preset version and the app is kept.
for (var i = 0; i <= 2; i++) {
if (groups[i] == '${tester.version.major}.${tester.version.minor}') {
if (groups[i] == '${preset.version.major}.${preset.version.minor}') {
groups.removeAt(i);
break;
}
}

final fixturesPath = PathUri(
isAbsolute: false,
isDirectory: true,
pathSegments: BuiltList.from([
'test',
'fixtures',
...groups.map(_formatName),
]),
final fixtureName = _formatName(Invoker.current!.liveTest.individualName);

final fixturePath = [
...groups.map(_formatName),
'$fixtureName.regexp',
];

final response = await client.validateFixture(
fixturePath: fixturePath,
);
final fixturesDir = Directory(fixturesPath.path);
if (!fixturesDir.existsSync()) {
fixturesDir.createSync(recursive: true);
}
final pattern = response.fixture;

final fixtureName = _formatName(Invoker.current!.liveTest.individualName.toLowerCase());
final fixtureFile = File(fixturesPath.join(PathUri.parse('$fixtureName.regexp')).path);
if (fixtureFile.existsSync()) {
final pattern = fixtureFile.readAsStringSync();
final hasMatch = RegExp('^$pattern\$').hasMatch(data);
if (!hasMatch) {
throw Exception('$data\ndoes not match\n$pattern');
}
} else {
fixtureFile.writeAsStringSync(RegExp.escape(data));
throw Exception('Missing fixture $fixtureFile');
if (pattern == null) {
fail(
'Missing fixture: '
'$data',
);
} else if (!RegExp('^$pattern\$').hasMatch(data)) {
fail('$data\ndoes not match\n$pattern');
}

_closed = false;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import 'dart:async';

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:nextcloud/nextcloud.dart';
import 'package:nextcloud_test/src/nextcloud_test.dart';
import 'package:nextcloud_test_api/client.dart';

/// The shared base http client.
///
/// Both the nextcloud communication and the communication to the test manager
/// are handled through this client.
@internal
final http.Client httpClient = http.Client();

/// Class that manages the creation of nextcloud api clients and the test environment.
final class NextcloudTester {
/// Creates a new Nextcloud tester for the given [preset] with the initial [username].
NextcloudTester({
required NextcloudTestApiClient testClient,
required Preset preset,
required String username,
}) : _preset = preset,
_username = username,
_testClient = testClient;

Preset _preset;

final String _username;

final NextcloudTestApiClient _testClient;

late Uri _hostURL;

/// URL where the target is available from itself.
late Uri targetURL;

/// The Nextcloud api client for the default user.
///
/// Use [createClient] to create a separate one.
late NextcloudClient client;

/// The app version tested.
Version get version => _preset.version;

/// Creates a new [NextcloudClient] for a given [username].
///
/// It is expected that the password of the user matches its [username].
Future<NextcloudClient> createClient({String username = 'user1'}) async {
final appPassword = await _testClient.createAppPassword(
preset: _preset,
username: username,
);

final interceptedClient = InterceptorHttpClient(
baseClient: httpClient,
interceptors: BuiltList([
CookieStoreInterceptor(
cookieStore: CookieStore(),
),
const FixtureInterceptor(appendFixture: appendFixture),
]),
);

return NextcloudClient(
_hostURL,
loginName: username,
password: username,
appPassword: appPassword,
httpClient: interceptedClient,
);
}

/// Initializes the tester creating the target and default client.
Future<void> init(String platform) async {
_preset = _preset.rebuild((b) {
b.platform = platform;
});

final response = await _testClient.setup(
preset: _preset,
);
_hostURL = response.hostURL;
targetURL = response.targetURL;

client = await createClient(username: _username);
}

/// Closes the tester.
Future<void> close() async {
await _testClient.tearDown(
preset: _preset,
);
}
}
Loading
Loading