Skip to content

Commit

Permalink
feat(nextcloud_test): Add local test target
Browse files Browse the repository at this point in the history
Signed-off-by: provokateurin <kate@provokateurin.de>
  • Loading branch information
provokateurin committed Jul 28, 2024
1 parent 3135832 commit 377246b
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 5 deletions.
5 changes: 0 additions & 5 deletions packages/nextcloud/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,6 @@ They can be accessed using getters on the `NextcloudClient`.

For an example checkout the [example](https://github.com/nextcloud/neon/blob/main/packages/nextcloud/example/example.dart).

## Development

Except for WebDAV all client code is generated using OpenAPI specifications which can be found in the `lib/src/api/` folder.
These OpenAPI specifications are [generated](https://github.com/nextcloud/openapi-extractor) from the PHP source code.

## Compatibility/Support policy

| Component | Supported versions (1) |
Expand Down
41 changes: 41 additions & 0 deletions packages/nextcloud/doc/development.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Development

Except for WebDAV all client code is generated using OpenAPI specifications which can be found in the `lib/src/api/` folder.
These OpenAPI specifications are [generated](https://github.com/nextcloud/openapi-extractor) from the PHP source code.

## Checking test do not interfere with each other

All tests should be standalone and never affect any other tests.
With enough caution this is feasible to implement, but to verify the tests do not depend on the order of execution they should be run multiple times with different seeds:

```sh
for i in {0..4}; do fvm flutter test --test-randomize-ordering-seed $i; done
```

## Testing against development versions

Make sure to have the following apps in your server development setup and the appropriate versions you want to test checked out:

- https://codeberg.org/NextPush/uppush
- https://framagit.org/framasoft/nextcloud/drop_account
- https://github.com/nextcloud/cookbook
- https://github.com/nextcloud/news
- https://github.com/nextcloud/notes
- https://github.com/nextcloud/notifications
- https://github.com/nextcloud/password_policy
- https://github.com/nextcloud/spreed
- https://github.com/nextcloud/tables
- https://github.com/nextcloud/text

To run the tests against development versions follow these steps:

```sh
cd /path/to/server
/path/to/neon/packages/nextcloud_test/docker/local.sh

# Open a second terminal
cd /path/to/neon/packages/nextcloud
URL="http://localhost:8080" DIR="/path/to/server" fvm dart test --concurrency=1
```

Forcing the serial execution of all tests is necessary because the used SQLite database can be locked which results in tests blocking and failing other concurrent tests.
27 changes: 27 additions & 0 deletions packages/nextcloud_test/docker/local.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/bin/sh
set -eux

rm -rf data config/config.php static

"$(dirname "$0")/pre.sh"

PHP_CLI_SERVER_WORKERS=10 php -S 0.0.0.0:8080 &
pid="$!"
cleanup() {
kill "$pid"
}
trap cleanup EXIT

until curl -s -o /dev/null http://localhost:8080/status.php; do true; done

cp -r "$(dirname "$0")/static" .
for user in admin user1 user2; do
curl -u "$user:$user" -H "ocs-apirequest: true" -s -o /dev/null http://localhost:8080/ocs/v2.php/cloud/user
cp -r "$(dirname "$0")/assets/Recipes" "data/$user/files"
done
./occ files:scan --all

"$(dirname "$0")/post.sh" --force

echo "Ready!"
sleep infinity
114 changes: 114 additions & 0 deletions packages/nextcloud_test/lib/src/test_target/local.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:nextcloud_test/src/presets.dart';
import 'package:nextcloud_test/src/test_target/test_target.dart';
import 'package:process_run/process_run.dart';
import 'package:version/version.dart';

/// Factory for running tests against a local instance.
class LocalFactory implements TestTargetFactory<LocalInstance> {
@override
LocalInstance spawn(Preset? preset) => LocalInstance();

@override
Map<String, List<Version>> getPresets() {
final presets = <String, List<Version>>{};
final regex = RegExp(' - (.*): (.*)');

final dir = Platform.environment['DIR']!;

var result = runExecutableArgumentsSync(
'php',
[
'-f',
'./occ',
'app:list',
'--enabled',
],
workingDirectory: dir,
);
if (result.exitCode != 0) {
throw Exception('Failed to list apps\n${result.stderr}\n${result.stdout}');
}

for (final line in (result.stdout as String).split('\n')) {
final matches = regex.allMatches(line);

if (matches.isNotEmpty) {
final match = matches.single;

presets[match.group(1)!] = [Version.parse(match.group(2)!)];
}
}

result = runExecutableArgumentsSync(
'php',
[
'-f',
'./occ',
'status',
],
workingDirectory: dir,
);
if (result.exitCode != 0) {
throw Exception('Failed to get status\n${result.stderr}\n${result.stdout}');
}

for (final line in (result.stdout as String).split('\n')) {
final matches = regex.allMatches(line);

if (matches.isNotEmpty) {
final match = matches.single;
if (match.group(1)! != 'version') {
continue;
}

presets['server'] = [Version.parse(match.group(2)!)];
break;
}
}

return presets;
}
}

/// Test target representing a local instance.
class LocalInstance extends TestTargetInstance {
@override
void destroy() {}

@override
Uri hostURL = Uri.parse(Platform.environment['URL']!);

@override
late Uri targetURL = hostURL;

@override
FutureOr<String> createAppPassword(String username) async {
final dir = Platform.environment['DIR']!;

final inputStream = StreamController<List<int>>();
final process = runExecutableArguments(
'php',
[
'-f',
'occ',
'user:add-app-password',
username,
],
stdin: inputStream.stream,
workingDirectory: dir,
);
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}');
}

return (result.stdout as String).split('\n')[1];
}
}
8 changes: 8 additions & 0 deletions packages/nextcloud_test/lib/src/test_target/test_target.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:io';

import 'package:cookie_store/cookie_store.dart';
import 'package:neon_http_client/neon_http_client.dart';
Expand All @@ -7,12 +8,19 @@ import 'package:nextcloud_test/nextcloud_test.dart';
import 'package:nextcloud_test/src/fixtures.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';

/// Factory for creating [TestTargetInstance]s.
abstract interface class TestTargetFactory<T extends TestTargetInstance> {
/// Creates a new [TestTargetFactory].
static TestTargetFactory create() {
final url = Platform.environment['URL'];
final dir = Platform.environment['DIR'];
if (url != null && url.isNotEmpty && dir != null && dir.isNotEmpty) {
return LocalFactory();
}

return DockerContainerFactory();
}

Expand Down

0 comments on commit 377246b

Please sign in to comment.