Browse Source

feat(nextcloud_test): Init

Signed-off-by: jld3103 <jld3103yt@gmail.com>
pull/1185/head
jld3103 1 year ago
parent
commit
93b43b3e82
No known key found for this signature in database
GPG Key ID: 9062417B9E8EB7B3
  1. 1
      commitlint.yaml
  2. 2
      cspell.json
  3. 1
      packages/nextcloud_test/LICENSE
  4. 3
      packages/nextcloud_test/README.md
  5. 1
      packages/nextcloud_test/analysis_options.yaml
  6. 2
      packages/nextcloud_test/docker/Dockerfile
  7. 0
      packages/nextcloud_test/docker/static/nasa.xml
  8. 0
      packages/nextcloud_test/docker/static/wikipedia.xml
  9. 3
      packages/nextcloud_test/lib/nextcloud_test.dart
  10. 7
      packages/nextcloud_test/lib/src/defaults.dart
  11. 112
      packages/nextcloud_test/lib/src/docker_container.dart
  12. 79
      packages/nextcloud_test/lib/src/test_client.dart
  13. 21
      packages/nextcloud_test/pubspec.yaml
  14. 8
      packages/nextcloud_test/pubspec_overrides.yaml
  15. 2
      tool/build-dev-container.sh

1
commitlint.yaml

@ -25,4 +25,5 @@ rules:
- neon_notifications
- neon_lints
- nextcloud
- nextcloud_test
- sort_box

2
cspell.json

@ -14,7 +14,7 @@
"packages/dynamite/dynamite_petstore_example/lib",
"packages/file_icons/lib/src/data.dart",
"packages/neon_lints/lib",
"tool/dev/static"
"packages/nextcloud_test/docker/static"
],
"dictionaries": [
"bash",

1
packages/nextcloud_test/LICENSE

@ -0,0 +1 @@
../../assets/AGPL-3.0.txt

3
packages/nextcloud_test/README.md

@ -0,0 +1,3 @@
# nextcloud_test
A helper package for running tests in the [nextcloud](../nextcloud) package.

1
packages/nextcloud_test/analysis_options.yaml

@ -0,0 +1 @@
include: package:neon_lints/dart.yaml

2
tool/Dockerfile.dev → packages/nextcloud_test/docker/Dockerfile

@ -18,7 +18,7 @@ RUN (sh /entrypoint.sh php -S 0.0.0.0:80 &) && \
# Do not setup the demo user here
for user in admin user1 user2; do curl -u "$user:$user" -H "ocs-apirequest: true" -s -o /dev/null http://localhost/ocs/v2.php/cloud/user; done
COPY dev/static /usr/src/nextcloud/static
COPY static /usr/src/nextcloud/static
ENV PHP_CLI_SERVER_WORKERS=10
CMD ["php", "-S", "0.0.0.0:80"]

0
tool/dev/static/nasa.xml → packages/nextcloud_test/docker/static/nasa.xml

0
tool/dev/static/wikipedia.xml → packages/nextcloud_test/docker/static/wikipedia.xml

3
packages/nextcloud_test/lib/nextcloud_test.dart

@ -0,0 +1,3 @@
export 'src/defaults.dart';
export 'src/docker_container.dart';
export 'src/test_client.dart';

7
packages/nextcloud_test/lib/src/defaults.dart

@ -0,0 +1,7 @@
import 'package:test/test.dart';
/// Default retry count for test groups.
const retryCount = 3;
/// Default timeout for test groups.
const timeout = Timeout(Duration(seconds: 30));

112
packages/nextcloud_test/lib/src/docker_container.dart

@ -0,0 +1,112 @@
import 'dart:async';
import 'dart:convert';
import 'dart:math';
import 'package:process_run/process_run.dart';
int _randomPort() => 1024 + Random().nextInt(65535 - 1024);
/// Represents a docker container on the system.
class DockerContainer {
DockerContainer._({
required this.id,
required this.port,
});
/// Creates a new docker container and returns its representation.
static Future<DockerContainer> create() async {
const dockerImageName = 'ghcr.io/nextcloud/neon/dev';
var result = await runExecutableArguments(
'docker',
[
'images',
'-q',
dockerImageName,
],
);
if (result.exitCode != 0) {
throw Exception('Querying docker image failed: ${result.stderr}');
}
if (result.stdout.toString().isEmpty) {
throw Exception('Missing docker image $dockerImageName. Please build it using ./tool/build-dev-container.sh');
}
late int port;
while (true) {
port = _randomPort();
result = await runExecutableArguments(
'docker',
[
'run',
'--rm',
'-d',
'--add-host',
'host.docker.internal:host-gateway',
'-p',
'$port:80',
dockerImageName,
],
);
// 125 means the docker run command itself has failed which indicated the port is already used
if (result.exitCode != 125) {
break;
}
}
if (result.exitCode != 0) {
throw Exception('Failed to run docker container: ${result.stderr}');
}
return DockerContainer._(
id: result.stdout.toString().replaceAll('\n', ''),
port: port,
);
}
/// ID of the docker container.
final String id;
/// Assigned port of docker container.
final int port;
/// Removes the docker container from the system.
void destroy() => unawaited(
runExecutableArguments(
'docker',
[
'kill',
id,
],
),
);
/// Reads the server logs.
Future<String> serverLogs() async => (await runExecutableArguments(
'docker',
[
'logs',
id,
],
stdoutEncoding: utf8,
))
.stdout as String;
/// Reads the Nextcloud logs.
Future<String> nextcloudLogs() async => (await runExecutableArguments(
'docker',
[
'exec',
id,
'cat',
'data/nextcloud.log',
],
stdoutEncoding: utf8,
))
.stdout as String;
/// Reads all logs.
///
/// Combines the output of [serverLogs] and [nextcloudLogs].
Future<String> allLogs() async => '${await serverLogs()}\n\n${await nextcloudLogs()}';
}

79
packages/nextcloud_test/lib/src/test_client.dart

@ -0,0 +1,79 @@
import 'dart:async';
import 'dart:convert';
import 'package:nextcloud/core.dart';
import 'package:nextcloud/nextcloud.dart';
import 'package:nextcloud_test/src/docker_container.dart';
import 'package:process_run/process_run.dart';
import 'package:universal_io/io.dart';
/// An extension for creating [NextcloudClient]s based on [DockerContainer]s.
extension TestNextcloudClient on NextcloudClient {
/// Creates a new [NextcloudClient] for a given [container] and [username].
///
/// It is expected that the password of the user matches the its [username].
/// This is the case for the available test docker containers.
static Future<NextcloudClient> create(
final DockerContainer container, {
final String? username = 'user1',
}) async {
String? appPassword;
if (username != null) {
final inputStream = StreamController<List<int>>();
final process = runExecutableArguments(
'docker',
[
'exec',
'-i',
container.id,
'php',
'-f',
'occ',
'user:add-app-password',
username,
],
stdin: inputStream.stream,
);
inputStream.add(utf8.encode(username));
await inputStream.close();
final result = await process;
if (result.exitCode != 0) {
throw Exception('Failed to run generate app password command\n${result.stderr}\n${result.stdout}');
}
appPassword = (result.stdout as String).split('\n')[1];
}
final client = NextcloudClient(
Uri(
scheme: 'http',
host: 'localhost',
port: container.port,
),
loginName: username,
password: username,
appPassword: appPassword,
cookieJar: CookieJar(),
);
var i = 0;
while (true) {
try {
await client.core.getStatus();
break;
} catch (error) {
if (error is HttpException || error is DynamiteApiException) {
i++;
await Future<void>.delayed(const Duration(milliseconds: 100));
if (i >= 300) {
throw TimeoutException('Failed to get the status of the Server. $error');
}
} else {
rethrow;
}
}
}
return client;
}
}

21
packages/nextcloud_test/pubspec.yaml

@ -0,0 +1,21 @@
name: nextcloud_test
version: 1.0.0
publish_to: none
environment:
sdk: '>=3.1.0 <4.0.0'
dependencies:
nextcloud:
git:
url: https://github.com/nextcloud/neon
path: packages/nextcloud
process_run: ^0.13.0
test: ^1.24.0
universal_io: ^2.0.0
dev_dependencies:
neon_lints:
git:
url: https://github.com/nextcloud/neon
path: packages/neon_lints

8
packages/nextcloud_test/pubspec_overrides.yaml

@ -0,0 +1,8 @@
# melos_managed_dependency_overrides: dynamite_runtime,neon_lints,nextcloud
dependency_overrides:
dynamite_runtime:
path: ../dynamite/dynamite_runtime
neon_lints:
path: ../neon_lints
nextcloud:
path: ../nextcloud

2
tool/build-dev-container.sh

@ -6,4 +6,4 @@ source tool/common.sh
tag="$(image_tag "dev:latest")"
# shellcheck disable=SC2046
docker buildx build --tag "$tag" $(cache_build_args "$tag") -f - ./tool < tool/Dockerfile.dev
docker buildx build --tag "$tag" $(cache_build_args "$tag") -f - ./packages/nextcloud_test/docker < packages/nextcloud_test/docker/Dockerfile

Loading…
Cancel
Save