Browse Source

fix(nextcloud): add timeout to test setup

Signed-off-by: Nikolas Rimikis <rimikis.nikolas@gmail.com>
Signed-off-by: Nikolas Rimikis <leptopoda@users.noreply.github.com>
pull/603/head
Nikolas Rimikis 1 year ago committed by Nikolas Rimikis
parent
commit
d55a7b74fb
No known key found for this signature in database
GPG Key ID: 85ED1DE9786A4FF2
  1. 302
      packages/nextcloud/test/core_test.dart
  2. 13
      packages/nextcloud/test/helper.dart
  3. 476
      packages/nextcloud/test/news_test.dart
  4. 270
      packages/nextcloud/test/notes_test.dart
  5. 86
      packages/nextcloud/test/notifications_test.dart
  6. 88
      packages/nextcloud/test/provisioning_api_test.dart
  7. 102
      packages/nextcloud/test/uppush_test.dart
  8. 336
      packages/nextcloud/test/user_status_test.dart
  9. 921
      packages/nextcloud/test/webdav_test.dart

302
packages/nextcloud/test/core_test.dart

@ -1,160 +1,162 @@
@Retry(3)
library core_test;
import 'package:nextcloud/nextcloud.dart';
import 'package:test/test.dart';
import 'helper.dart';
void main() {
group('core', () {
late DockerImage image;
setUpAll(() async => image = await getDockerImage());
late DockerContainer container;
late TestNextcloudClient client;
setUp(() async {
container = await getDockerContainer(image);
client = await getTestClient(container);
});
tearDown(() => container.destroy());
test('Is supported from capabilities', () async {
final (supported, _) = client.core.isSupported((await client.core.ocs.getCapabilities()).ocs.data);
expect(supported, isTrue);
});
test('Is supported from status', () async {
final status = await client.core.getStatus();
expect(status.isSupported, isTrue);
});
test('Get status', () async {
final status = await client.core.getStatus();
expect(status.installed, true);
expect(status.maintenance, false);
expect(status.needsDbUpgrade, false);
expect(status.version, startsWith('$coreSupportedVersion.'));
expect(status.versionstring, startsWith('$coreSupportedVersion.'));
expect(status.edition, '');
expect(status.productname, 'Nextcloud');
expect(status.extendedSupport, false);
});
test('Get capabilities', () async {
final capabilities = await client.core.ocs.getCapabilities();
expect(capabilities.ocs.data.version.major, coreSupportedVersion);
expect(capabilities.ocs.data.version.string, startsWith('$coreSupportedVersion.'));
expect(capabilities.ocs.data.capabilities.commentsCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.davCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.filesCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.filesSharingCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.filesTrashbinCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.filesVersionsCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.notesCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.notificationsCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.provisioningApiCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.sharebymailCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.themingPublicCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.userStatusCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.weatherStatusCapabilities, isNotNull);
});
test('Get navigation apps', () async {
final navigationApps = await client.core.navigation.getAppsNavigation();
expect(navigationApps.ocs.data, hasLength(6));
expect(navigationApps.ocs.data[0].id, 'dashboard');
expect(navigationApps.ocs.data[1].id, 'files');
expect(navigationApps.ocs.data[2].id, 'photos');
expect(navigationApps.ocs.data[3].id, 'activity');
expect(navigationApps.ocs.data[4].id, 'notes');
expect(navigationApps.ocs.data[5].id, 'news');
});
test(
'Autocomplete',
() async {
final response = await client.core.autoComplete.$get(
search: '',
itemType: 'call',
itemId: 'new',
shareTypes: [
ShareType.user.index,
ShareType.group.index,
],
);
expect(response.ocs.data, hasLength(3));
expect(response.ocs.data[0].id, 'admin');
expect(response.ocs.data[0].label, 'admin');
expect(response.ocs.data[0].icon, 'icon-user');
expect(response.ocs.data[0].source, 'users');
expect(response.ocs.data[0].status, isEmpty);
expect(response.ocs.data[0].subline, '');
expect(response.ocs.data[0].shareWithDisplayNameUnique, 'admin@example.com');
expect(response.ocs.data[1].id, 'user2');
expect(response.ocs.data[1].label, 'User Two');
expect(response.ocs.data[1].icon, 'icon-user');
expect(response.ocs.data[1].source, 'users');
expect(response.ocs.data[1].status, isEmpty);
expect(response.ocs.data[1].subline, '');
expect(response.ocs.data[1].shareWithDisplayNameUnique, 'user2');
expect(response.ocs.data[2].id, 'admin');
expect(response.ocs.data[2].label, 'admin');
expect(response.ocs.data[2].icon, '');
expect(response.ocs.data[2].source, 'groups');
expect(response.ocs.data[2].status, isEmpty);
expect(response.ocs.data[2].subline, '');
expect(response.ocs.data[2].shareWithDisplayNameUnique, '');
},
skip: true, // TODO: This test only works on 28+ due to a bug fix with the status
);
test('Get preview', () async {
final response = await client.core.preview.getPreview(file: 'Nextcloud.png');
expect(response, isNotEmpty);
});
test('Get avatar', () async {
final response = await client.core.avatar.getAvatar(userId: 'admin', size: 32);
expect(response.data, isNotEmpty);
});
test('Get dark avatar', () async {
final response = await client.core.avatar.getAvatarDark(userId: 'admin', size: 32);
expect(response.data, isNotEmpty);
});
test('Delete app password', () async {
await client.core.appPassword.deleteAppPassword();
expect(
() => client.core.appPassword.deleteAppPassword(),
throwsA(predicate((final e) => (e! as DynamiteApiException).statusCode == 401)),
group(
'core',
() {
late DockerImage image;
setUpAll(() async => image = await getDockerImage());
late DockerContainer container;
late TestNextcloudClient client;
setUp(() async {
container = await getDockerContainer(image);
client = await getTestClient(container);
});
tearDown(() => container.destroy());
test('Is supported from capabilities', () async {
final (supported, _) = client.core.isSupported((await client.core.ocs.getCapabilities()).ocs.data);
expect(supported, isTrue);
});
test('Is supported from status', () async {
final status = await client.core.getStatus();
expect(status.isSupported, isTrue);
});
test('Get status', () async {
final status = await client.core.getStatus();
expect(status.installed, true);
expect(status.maintenance, false);
expect(status.needsDbUpgrade, false);
expect(status.version, startsWith('$coreSupportedVersion.'));
expect(status.versionstring, startsWith('$coreSupportedVersion.'));
expect(status.edition, '');
expect(status.productname, 'Nextcloud');
expect(status.extendedSupport, false);
});
test('Get capabilities', () async {
final capabilities = await client.core.ocs.getCapabilities();
expect(capabilities.ocs.data.version.major, coreSupportedVersion);
expect(capabilities.ocs.data.version.string, startsWith('$coreSupportedVersion.'));
expect(capabilities.ocs.data.capabilities.commentsCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.davCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.filesCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.filesSharingCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.filesTrashbinCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.filesVersionsCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.notesCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.notificationsCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.provisioningApiCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.sharebymailCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.themingPublicCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.userStatusCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.weatherStatusCapabilities, isNotNull);
});
test('Get navigation apps', () async {
final navigationApps = await client.core.navigation.getAppsNavigation();
expect(navigationApps.ocs.data, hasLength(6));
expect(navigationApps.ocs.data[0].id, 'dashboard');
expect(navigationApps.ocs.data[1].id, 'files');
expect(navigationApps.ocs.data[2].id, 'photos');
expect(navigationApps.ocs.data[3].id, 'activity');
expect(navigationApps.ocs.data[4].id, 'notes');
expect(navigationApps.ocs.data[5].id, 'news');
});
test(
'Autocomplete',
() async {
final response = await client.core.autoComplete.$get(
search: '',
itemType: 'call',
itemId: 'new',
shareTypes: [
ShareType.user.index,
ShareType.group.index,
],
);
expect(response.ocs.data, hasLength(3));
expect(response.ocs.data[0].id, 'admin');
expect(response.ocs.data[0].label, 'admin');
expect(response.ocs.data[0].icon, 'icon-user');
expect(response.ocs.data[0].source, 'users');
expect(response.ocs.data[0].status, isEmpty);
expect(response.ocs.data[0].subline, '');
expect(response.ocs.data[0].shareWithDisplayNameUnique, 'admin@example.com');
expect(response.ocs.data[1].id, 'user2');
expect(response.ocs.data[1].label, 'User Two');
expect(response.ocs.data[1].icon, 'icon-user');
expect(response.ocs.data[1].source, 'users');
expect(response.ocs.data[1].status, isEmpty);
expect(response.ocs.data[1].subline, '');
expect(response.ocs.data[1].shareWithDisplayNameUnique, 'user2');
expect(response.ocs.data[2].id, 'admin');
expect(response.ocs.data[2].label, 'admin');
expect(response.ocs.data[2].icon, '');
expect(response.ocs.data[2].source, 'groups');
expect(response.ocs.data[2].status, isEmpty);
expect(response.ocs.data[2].subline, '');
expect(response.ocs.data[2].shareWithDisplayNameUnique, '');
},
skip: true, // TODO: This test only works on 28+ due to a bug fix with the status
);
});
test('Unified search providers', () async {
final response = await client.core.unifiedSearch.getProviders();
expect(response.ocs.data, hasLength(13));
});
test('Get preview', () async {
final response = await client.core.preview.getPreview(file: 'Nextcloud.png');
expect(response, isNotEmpty);
});
test('Get avatar', () async {
final response = await client.core.avatar.getAvatar(userId: 'admin', size: 32);
expect(response.data, isNotEmpty);
});
test('Get dark avatar', () async {
final response = await client.core.avatar.getAvatarDark(userId: 'admin', size: 32);
expect(response.data, isNotEmpty);
});
test('Delete app password', () async {
await client.core.appPassword.deleteAppPassword();
expect(
() => client.core.appPassword.deleteAppPassword(),
throwsA(predicate((final e) => (e! as DynamiteApiException).statusCode == 401)),
);
});
test('Unified search providers', () async {
final response = await client.core.unifiedSearch.getProviders();
expect(response.ocs.data, hasLength(13));
});
test('Unified search', () async {
final response = await client.core.unifiedSearch.search(
providerId: 'settings',
term: 'Personal info',
);
expect(response.ocs.data.name, 'Settings');
expect(response.ocs.data.isPaginated, isFalse);
expect(response.ocs.data.entries, hasLength(1));
expect(response.ocs.data.entries.single.thumbnailUrl, isEmpty);
expect(response.ocs.data.entries.single.title, 'Personal info');
expect(response.ocs.data.entries.single.subline, isEmpty);
expect(response.ocs.data.entries.single.resourceUrl, isNotEmpty);
expect(response.ocs.data.entries.single.icon, 'icon-settings-dark');
expect(response.ocs.data.entries.single.rounded, isFalse);
expect(response.ocs.data.entries.single.attributes, isEmpty);
});
});
test('Unified search', () async {
final response = await client.core.unifiedSearch.search(
providerId: 'settings',
term: 'Personal info',
);
expect(response.ocs.data.name, 'Settings');
expect(response.ocs.data.isPaginated, isFalse);
expect(response.ocs.data.entries, hasLength(1));
expect(response.ocs.data.entries.single.thumbnailUrl, isEmpty);
expect(response.ocs.data.entries.single.title, 'Personal info');
expect(response.ocs.data.entries.single.subline, isEmpty);
expect(response.ocs.data.entries.single.resourceUrl, isNotEmpty);
expect(response.ocs.data.entries.single.icon, 'icon-settings-dark');
expect(response.ocs.data.entries.single.rounded, isFalse);
expect(response.ocs.data.entries.single.attributes, isEmpty);
});
},
retry: retryCount,
timeout: timeout,
);
}

13
packages/nextcloud/test/helper.dart

@ -7,6 +7,9 @@ import 'package:nextcloud/nextcloud.dart';
import 'package:process_run/cmd_run.dart';
import 'package:test/test.dart';
const retryCount = 3;
const timeout = Timeout(Duration(seconds: 30));
class DockerContainer {
DockerContainer({
required this.id,
@ -131,12 +134,18 @@ Future<TestNextcloudClient> getTestClient(
cookieJar: CookieJar(),
);
var i = 0;
while (true) {
// Test will timeout after 30s
try {
await client.core.getStatus();
break;
} catch (_) {}
} on CoreApiException catch (error) {
i++;
await Future.delayed(const Duration(milliseconds: 100));
if (i >= 30) {
throw TimeoutException('Failed to get the status of the Server. $error');
}
}
}
return client;

476
packages/nextcloud/test/news_test.dart

@ -1,6 +1,3 @@
@Retry(3)
library news_test;
import 'dart:async';
import 'dart:io';
@ -10,265 +7,270 @@ import 'package:test/test.dart';
import 'helper.dart';
void main() {
group('news', () {
late DockerImage image;
late HttpServer rssServer;
setUpAll(() async {
image = await getDockerImage();
rssServer = await getRssServer();
});
tearDownAll(() async => rssServer.close(force: true));
late DockerContainer container;
late TestNextcloudClient client;
setUp(() async {
container = await getDockerContainer(image);
client = await getTestClient(container);
});
tearDown(() => container.destroy());
Future<NewsListFeeds> addWikipediaFeed([final int? folderID]) async => client.news.addFeed(
url: 'http://host.docker.internal:${rssServer.port}/wikipedia.xml',
folderId: folderID,
);
Future<NewsListFeeds> addNasaFeed() async => client.news.addFeed(
url: 'http://host.docker.internal:${rssServer.port}/nasa.xml',
group(
'news',
() {
late DockerImage image;
late HttpServer rssServer;
setUpAll(() async {
image = await getDockerImage();
rssServer = await getRssServer();
});
tearDownAll(() async => rssServer.close(force: true));
late DockerContainer container;
late TestNextcloudClient client;
setUp(() async {
container = await getDockerContainer(image);
client = await getTestClient(container);
});
tearDown(() => container.destroy());
Future<NewsListFeeds> addWikipediaFeed([final int? folderID]) async => client.news.addFeed(
url: 'http://host.docker.internal:${rssServer.port}/wikipedia.xml',
folderId: folderID,
);
Future<NewsListFeeds> addNasaFeed() async => client.news.addFeed(
url: 'http://host.docker.internal:${rssServer.port}/nasa.xml',
);
test('Is supported', () async {
final (supported, _) = await client.news.isSupported();
expect(supported, isTrue);
});
test('Add feed', () async {
var response = await client.news.listFeeds();
expect(response.starredCount, 0);
expect(response.newestItemId, null);
expect(response.feeds, hasLength(0));
response = await addWikipediaFeed();
expect(response.starredCount, null);
expect(response.newestItemId, isNotNull);
expect(response.feeds, hasLength(1));
expect(response.feeds[0].url, 'http://host.docker.internal:${rssServer.port}/wikipedia.xml');
response = await client.news.listFeeds();
expect(response.starredCount, 0);
expect(response.newestItemId, isNotNull);
expect(response.feeds, hasLength(1));
expect(response.feeds[0].url, 'http://host.docker.internal:${rssServer.port}/wikipedia.xml');
});
test('Rename feed', () async {
var response = await addWikipediaFeed();
expect(response.feeds[0].title, 'Wikipedia featured articles feed');
await client.news.renameFeed(
feedId: 1,
feedTitle: 'test1',
);
test('Is supported', () async {
final (supported, _) = await client.news.isSupported();
expect(supported, isTrue);
});
test('Add feed', () async {
var response = await client.news.listFeeds();
expect(response.starredCount, 0);
expect(response.newestItemId, null);
expect(response.feeds, hasLength(0));
response = await addWikipediaFeed();
expect(response.starredCount, null);
expect(response.newestItemId, isNotNull);
expect(response.feeds, hasLength(1));
expect(response.feeds[0].url, 'http://host.docker.internal:${rssServer.port}/wikipedia.xml');
response = await client.news.listFeeds();
expect(response.starredCount, 0);
expect(response.newestItemId, isNotNull);
expect(response.feeds, hasLength(1));
expect(response.feeds[0].url, 'http://host.docker.internal:${rssServer.port}/wikipedia.xml');
});
test('Rename feed', () async {
var response = await addWikipediaFeed();
expect(response.feeds[0].title, 'Wikipedia featured articles feed');
await client.news.renameFeed(
feedId: 1,
feedTitle: 'test1',
);
response = await client.news.listFeeds();
expect(response.feeds[0].title, 'test1');
});
response = await client.news.listFeeds();
expect(response.feeds[0].title, 'test1');
});
test('Move feed to folder', () async {
await client.news.createFolder(name: 'test1');
await addWikipediaFeed();
await client.news.moveFeed(
feedId: 1,
folderId: 1,
);
test('Move feed to folder', () async {
await client.news.createFolder(name: 'test1');
await addWikipediaFeed();
await client.news.moveFeed(
feedId: 1,
folderId: 1,
);
final response = await client.news.listFolders();
expect(response.folders, hasLength(1));
expect(response.folders[0].id, 1);
expect(response.folders[0].name, 'test1');
expect(response.folders[0].opened, true);
expect(response.folders[0].feeds, hasLength(0));
});
final response = await client.news.listFolders();
expect(response.folders, hasLength(1));
expect(response.folders[0].id, 1);
expect(response.folders[0].name, 'test1');
expect(response.folders[0].opened, true);
expect(response.folders[0].feeds, hasLength(0));
});
test('Mark feed as read', () async {
final feedsResponse = await addWikipediaFeed();
test('Mark feed as read', () async {
final feedsResponse = await addWikipediaFeed();
var articlesResponse = await client.news.listArticles(type: NewsListType.unread.index);
expect(articlesResponse.items.length, greaterThan(0));
var articlesResponse = await client.news.listArticles(type: NewsListType.unread.index);
expect(articlesResponse.items.length, greaterThan(0));
await client.news.markFeedAsRead(
feedId: feedsResponse.feeds[0].id,
newestItemId: feedsResponse.newestItemId!,
);
await client.news.markFeedAsRead(
feedId: feedsResponse.feeds[0].id,
newestItemId: feedsResponse.newestItemId!,
);
articlesResponse = await client.news.listArticles(type: NewsListType.unread.index);
expect(articlesResponse.items, hasLength(0));
});
articlesResponse = await client.news.listArticles(type: NewsListType.unread.index);
expect(articlesResponse.items, hasLength(0));
});
test('List articles', () async {
var response = await client.news.listArticles();
expect(response.items, hasLength(0));
test('List articles', () async {
var response = await client.news.listArticles();
expect(response.items, hasLength(0));
await addWikipediaFeed();
await addWikipediaFeed();
response = await client.news.listArticles();
expect(response.items.length, greaterThan(0));
expect(response.items[0].body, isNotNull);
expect(response.items[0].feedId, 1);
expect(response.items[0].unread, true);
expect(response.items[0].starred, false);
});
response = await client.news.listArticles();
expect(response.items.length, greaterThan(0));
expect(response.items[0].body, isNotNull);
expect(response.items[0].feedId, 1);
expect(response.items[0].unread, true);
expect(response.items[0].starred, false);
});
test('List updated articles', () async {
// Testing this is not easy, because we can't depend on an external source to update the feed
// Therefore we just add a second feed and check that the articles returned after a certain modified timestamp
// are exactly those of the new feed.
// Now that I think of it, maybe we could host our own feed and update that way, but this works for now.
test('List updated articles', () async {
// Testing this is not easy, because we can't depend on an external source to update the feed
// Therefore we just add a second feed and check that the articles returned after a certain modified timestamp
// are exactly those of the new feed.
// Now that I think of it, maybe we could host our own feed and update that way, but this works for now.
await addWikipediaFeed();
await addWikipediaFeed();
var response = await client.news.listArticles();
final wikipediaArticles = response.items.length;
expect(wikipediaArticles, greaterThan(0));
var response = await client.news.listArticles();
final wikipediaArticles = response.items.length;
expect(wikipediaArticles, greaterThan(0));
await addNasaFeed();
await addNasaFeed();
response = await client.news.listArticles();
final nasaArticles = response.items.length - wikipediaArticles;
expect(nasaArticles, greaterThan(0));
response = await client.news.listArticles();
final nasaArticles = response.items.length - wikipediaArticles;
expect(nasaArticles, greaterThan(0));
response = await client.news.listUpdatedArticles(
lastModified: response.items[response.items.length - 1 - nasaArticles].lastModified,
);
expect(response.items, hasLength(nasaArticles));
});
response = await client.news.listUpdatedArticles(
lastModified: response.items[response.items.length - 1 - nasaArticles].lastModified,
);
expect(response.items, hasLength(nasaArticles));
});
test('Mark article as read', () async {
await addWikipediaFeed();
test('Mark article as read', () async {
await addWikipediaFeed();
var response = await client.news.listArticles(type: NewsListType.unread.index);
final unreadArticles = response.items.length;
expect(unreadArticles, greaterThan(0));
var response = await client.news.listArticles(type: NewsListType.unread.index);
final unreadArticles = response.items.length;
expect(unreadArticles, greaterThan(0));
await client.news.markArticleAsRead(
itemId: response.items[0].id,
);
response = await client.news.listArticles(type: NewsListType.unread.index);
expect(response.items, hasLength(unreadArticles - 1));
});
test('Mark article as unread', () async {
await addWikipediaFeed();
var response = await client.news.listArticles(type: NewsListType.unread.index);
final readArticle = response.items[0];
await client.news.markArticleAsRead(itemId: readArticle.id);
response = await client.news.listArticles(type: NewsListType.unread.index);
final unreadArticles = response.items.length;
expect(unreadArticles, greaterThan(0));
await client.news.markArticleAsUnread(itemId: readArticle.id);
response = await client.news.listArticles(type: NewsListType.unread.index);
expect(response.items, hasLength(unreadArticles + 1));
});
test('Star article', () async {
await addWikipediaFeed();
var response = await client.news.listArticles(type: NewsListType.starred.index);
final starredArticles = response.items.length;
expect(starredArticles, 0);
response = await client.news.listArticles();
await client.news.starArticle(
itemId: response.items[0].id,
);
response = await client.news.listArticles(type: NewsListType.starred.index);
expect(response.items, hasLength(1));
});
await client.news.markArticleAsRead(
itemId: response.items[0].id,
);
response = await client.news.listArticles(type: NewsListType.unread.index);
expect(response.items, hasLength(unreadArticles - 1));
});
test('Mark article as unread', () async {
await addWikipediaFeed();
var response = await client.news.listArticles(type: NewsListType.unread.index);
final readArticle = response.items[0];
await client.news.markArticleAsRead(itemId: readArticle.id);
response = await client.news.listArticles(type: NewsListType.unread.index);
final unreadArticles = response.items.length;
expect(unreadArticles, greaterThan(0));
await client.news.markArticleAsUnread(itemId: readArticle.id);
response = await client.news.listArticles(type: NewsListType.unread.index);
expect(response.items, hasLength(unreadArticles + 1));
});
test('Star article', () async {
await addWikipediaFeed();
var response = await client.news.listArticles(type: NewsListType.starred.index);
final starredArticles = response.items.length;
expect(starredArticles, 0);
response = await client.news.listArticles();
await client.news.starArticle(
itemId: response.items[0].id,
);
response = await client.news.listArticles(type: NewsListType.starred.index);
expect(response.items, hasLength(1));
});
test('Unstar article', () async {
await addWikipediaFeed();
test('Unstar article', () async {
await addWikipediaFeed();
var response = await client.news.listArticles();
final item = response.items[0];
var response = await client.news.listArticles();
final item = response.items[0];
await client.news.starArticle(
itemId: item.id,
);
response = await client.news.listArticles(type: NewsListType.starred.index);
expect(response.items, hasLength(1));
await client.news.starArticle(
itemId: item.id,
);
response = await client.news.listArticles(type: NewsListType.starred.index);
expect(response.items, hasLength(1));
await client.news.unstarArticle(
itemId: item.id,
);
response = await client.news.listArticles(type: NewsListType.starred.index);
expect(response.items, hasLength(0));
});
test('Create folder', () async {
var response = await client.news.listFolders();
expect(response.folders, hasLength(0));
response = await client.news.createFolder(name: 'test1');
expect(response.folders, hasLength(1));
expect(response.folders[0].id, 1);
expect(response.folders[0].name, 'test1');
expect(response.folders[0].opened, true);
expect(response.folders[0].feeds, hasLength(0));
response = await client.news.listFolders();
expect(response.folders, hasLength(1));
expect(response.folders[0].id, 1);
expect(response.folders[0].name, 'test1');
expect(response.folders[0].opened, true);
expect(response.folders[0].feeds, hasLength(0));
});
test('List folders', () async {
var response = await client.news.listFolders();
expect(response.folders, hasLength(0));
await client.news.createFolder(name: 'test1');
await client.news.createFolder(name: 'test2');
response = response = await client.news.listFolders();
expect(response.folders, hasLength(2));
expect(response.folders[0].id, 1);
expect(response.folders[0].name, 'test1');
expect(response.folders[0].opened, true);
expect(response.folders[0].feeds, hasLength(0));
expect(response.folders[1].id, 2);
expect(response.folders[1].name, 'test2');
expect(response.folders[1].opened, true);
expect(response.folders[1].feeds, hasLength(0));
});
test('Add feed to folder', () async {
await client.news.createFolder(name: 'test1');
final response = await addWikipediaFeed(1);
expect(response.starredCount, null);
expect(response.newestItemId, isNotNull);
expect(response.feeds, hasLength(1));
expect(response.feeds[0].folderId, 1);
expect(response.feeds[0].url, 'http://host.docker.internal:${rssServer.port}/wikipedia.xml');
});
test('Mark folder as read', () async {
final foldersResponse = await client.news.createFolder(name: 'test1');
final feedsResponse = await addWikipediaFeed(1);
var articlesResponse = await client.news.listArticles(type: NewsListType.unread.index);
expect(articlesResponse.items.length, greaterThan(0));
await client.news.markFolderAsRead(
folderId: foldersResponse.folders[0].id,
newestItemId: feedsResponse.newestItemId!,
);
await client.news.unstarArticle(
itemId: item.id,
);
response = await client.news.listArticles(type: NewsListType.starred.index);
expect(response.items, hasLength(0));
});
test('Create folder', () async {
var response = await client.news.listFolders();
expect(response.folders, hasLength(0));
response = await client.news.createFolder(name: 'test1');
expect(response.folders, hasLength(1));
expect(response.folders[0].id, 1);
expect(response.folders[0].name, 'test1');
expect(response.folders[0].opened, true);
expect(response.folders[0].feeds, hasLength(0));
response = await client.news.listFolders();
expect(response.folders, hasLength(1));
expect(response.folders[0].id, 1);
expect(response.folders[0].name, 'test1');
expect(response.folders[0].opened, true);
expect(response.folders[0].feeds, hasLength(0));
});
test('List folders', () async {
var response = await client.news.listFolders();
expect(response.folders, hasLength(0));
await client.news.createFolder(name: 'test1');
await client.news.createFolder(name: 'test2');
response = response = await client.news.listFolders();
expect(response.folders, hasLength(2));
expect(response.folders[0].id, 1);
expect(response.folders[0].name, 'test1');
expect(response.folders[0].opened, true);
expect(response.folders[0].feeds, hasLength(0));
expect(response.folders[1].id, 2);
expect(response.folders[1].name, 'test2');
expect(response.folders[1].opened, true);
expect(response.folders[1].feeds, hasLength(0));
});
test('Add feed to folder', () async {
await client.news.createFolder(name: 'test1');
final response = await addWikipediaFeed(1);
expect(response.starredCount, null);
expect(response.newestItemId, isNotNull);
expect(response.feeds, hasLength(1));
expect(response.feeds[0].folderId, 1);
expect(response.feeds[0].url, 'http://host.docker.internal:${rssServer.port}/wikipedia.xml');
});
test('Mark folder as read', () async {
final foldersResponse = await client.news.createFolder(name: 'test1');
final feedsResponse = await addWikipediaFeed(1);
var articlesResponse = await client.news.listArticles(type: NewsListType.unread.index);
expect(articlesResponse.items.length, greaterThan(0));
await client.news.markFolderAsRead(
folderId: foldersResponse.folders[0].id,
newestItemId: feedsResponse.newestItemId!,
);
articlesResponse = await client.news.listArticles(type: NewsListType.unread.index);
expect(articlesResponse.items, hasLength(0));
});
});
articlesResponse = await client.news.listArticles(type: NewsListType.unread.index);
expect(articlesResponse.items, hasLength(0));
});
},
retry: retryCount,
timeout: timeout,
);
}
Future<HttpServer> getRssServer() async {

270
packages/nextcloud/test/notes_test.dart

@ -1,143 +1,145 @@
@Retry(3)
library notes_test;
import 'package:nextcloud/nextcloud.dart';
import 'package:test/test.dart';
import 'helper.dart';
void main() {
group('notes', () {
late DockerImage image;
setUpAll(() async => image = await getDockerImage());
late DockerContainer container;
late TestNextcloudClient client;
setUp(() async {
container = await getDockerContainer(image);
client = await getTestClient(container);
});
tearDown(() => container.destroy());
test('Is supported', () async {
final (supported, _) = client.notes.isSupported((await client.core.ocs.getCapabilities()).ocs.data);
expect(supported, isTrue);
});
test('Create note favorite', () async {
final response = await client.notes.createNote(
title: 'a',
content: 'b',
category: 'c',
favorite: 1,
);
expect(response.id, isPositive);
expect(response.title, 'a');
expect(response.content, 'b');
expect(response.category, 'c');
expect(response.favorite, true);
expect(response.readonly, false);
expect(response.etag, isNotNull);
expect(response.modified, isNotNull);
});
test('Create note not favorite', () async {
final response = await client.notes.createNote(
title: 'a',
content: 'b',
category: 'c',
);
expect(response.id, isPositive);
expect(response.title, 'a');
expect(response.content, 'b');
expect(response.category, 'c');
expect(response.favorite, false);
expect(response.readonly, false);
expect(response.etag, isNotNull);
expect(response.modified, isNotNull);
});
test('Get notes', () async {
await client.notes.createNote(title: 'a');
await client.notes.createNote(title: 'b');
final response = await client.notes.getNotes();
expect(response, hasLength(2));
expect(response[0].title, 'a');
expect(response[1].title, 'b');
});
test('Get note', () async {
final response = await client.notes.getNote(
id: (await client.notes.createNote(title: 'a')).id,
);
expect(response.title, 'a');
});
test('Update note', () async {
final id = (await client.notes.createNote(title: 'a')).id;
await client.notes.updateNote(
id: id,
title: 'b',
);
final response = await client.notes.getNote(id: id);
expect(response.title, 'b');
});
test('Update note fail changed on server', () async {
final response = await client.notes.createNote(title: 'a');
await client.notes.updateNote(
id: response.id,
title: 'b',
ifMatch: '"${response.etag}"',
);
expect(
() => client.notes.updateNote(
group(
'notes',
() {
late DockerImage image;
setUpAll(() async => image = await getDockerImage());
late DockerContainer container;
late TestNextcloudClient client;
setUp(() async {
container = await getDockerContainer(image);
client = await getTestClient(container);
});
tearDown(() => container.destroy());
test('Is supported', () async {
final (supported, _) = client.notes.isSupported((await client.core.ocs.getCapabilities()).ocs.data);
expect(supported, isTrue);
});
test('Create note favorite', () async {
final response = await client.notes.createNote(
title: 'a',
content: 'b',
category: 'c',
favorite: 1,
);
expect(response.id, isPositive);
expect(response.title, 'a');
expect(response.content, 'b');
expect(response.category, 'c');
expect(response.favorite, true);
expect(response.readonly, false);
expect(response.etag, isNotNull);
expect(response.modified, isNotNull);
});
test('Create note not favorite', () async {
final response = await client.notes.createNote(
title: 'a',
content: 'b',
category: 'c',
);
expect(response.id, isPositive);
expect(response.title, 'a');
expect(response.content, 'b');
expect(response.category, 'c');
expect(response.favorite, false);
expect(response.readonly, false);
expect(response.etag, isNotNull);
expect(response.modified, isNotNull);
});
test('Get notes', () async {
await client.notes.createNote(title: 'a');
await client.notes.createNote(title: 'b');
final response = await client.notes.getNotes();
expect(response, hasLength(2));
expect(response[0].title, 'a');
expect(response[1].title, 'b');
});
test('Get note', () async {
final response = await client.notes.getNote(
id: (await client.notes.createNote(title: 'a')).id,
);
expect(response.title, 'a');
});
test('Update note', () async {
final id = (await client.notes.createNote(title: 'a')).id;
await client.notes.updateNote(
id: id,
title: 'b',
);
final response = await client.notes.getNote(id: id);
expect(response.title, 'b');
});
test('Update note fail changed on server', () async {
final response = await client.notes.createNote(title: 'a');
await client.notes.updateNote(
id: response.id,
title: 'c',
title: 'b',
ifMatch: '"${response.etag}"',
),
throwsA(predicate((final e) => (e! as DynamiteApiException).statusCode == 412)),
);
});
test('Delete note', () async {
final id = (await client.notes.createNote(title: 'a')).id;
var response = await client.notes.getNotes();
expect(response, hasLength(1));
await client.notes.deleteNote(id: id);
response = await client.notes.getNotes();
expect(response, hasLength(0));
});
test('Get settings', () async {
final response = await client.notes.getSettings();
expect(response.notesPath, 'Notes');
expect(response.fileSuffix, '.md');
expect(response.noteMode, NotesSettings_NoteMode.rich);
});
test('Update settings', () async {
var response = await client.notes.updateSettings(
settings: NotesSettings(
(final b) => b
..notesPath = 'Test Notes'
..fileSuffix = '.txt'
..noteMode = NotesSettings_NoteMode.preview,
),
);
expect(response.notesPath, 'Test Notes');
expect(response.fileSuffix, '.txt');
expect(response.noteMode, NotesSettings_NoteMode.preview);
response = await client.notes.getSettings();
expect(response.notesPath, 'Test Notes');
expect(response.fileSuffix, '.txt');
expect(response.noteMode, NotesSettings_NoteMode.preview);
});
});
);
expect(
() => client.notes.updateNote(
id: response.id,
title: 'c',
ifMatch: '"${response.etag}"',
),
throwsA(predicate((final e) => (e! as DynamiteApiException).statusCode == 412)),
);
});
test('Delete note', () async {
final id = (await client.notes.createNote(title: 'a')).id;
var response = await client.notes.getNotes();
expect(response, hasLength(1));
await client.notes.deleteNote(id: id);
response = await client.notes.getNotes();
expect(response, hasLength(0));
});
test('Get settings', () async {
final response = await client.notes.getSettings();
expect(response.notesPath, 'Notes');
expect(response.fileSuffix, '.md');
expect(response.noteMode, NotesSettings_NoteMode.rich);
});
test('Update settings', () async {
var response = await client.notes.updateSettings(
settings: NotesSettings(
(final b) => b
..notesPath = 'Test Notes'
..fileSuffix = '.txt'
..noteMode = NotesSettings_NoteMode.preview,
),
);
expect(response.notesPath, 'Test Notes');
expect(response.fileSuffix, '.txt');
expect(response.noteMode, NotesSettings_NoteMode.preview);
response = await client.notes.getSettings();
expect(response.notesPath, 'Test Notes');
expect(response.fileSuffix, '.txt');
expect(response.noteMode, NotesSettings_NoteMode.preview);
});
},
retry: retryCount,
timeout: timeout,
);
}

86
packages/nextcloud/test/notifications_test.dart

@ -1,6 +1,3 @@
@Retry(3)
library notifications_test;
import 'dart:async';
import 'package:nextcloud/nextcloud.dart';
@ -99,43 +96,48 @@ void main() {
});
});
group('push notifications', () {
late DockerImage image;
setUpAll(() async => image = await getDockerImage());
late DockerContainer container;
late TestNextcloudClient client;
setUp(() async {
container = await getDockerContainer(image);
client = await getTestClient(
container,
username: 'admin',
);
});
tearDown(() => container.destroy());
// The key size has to be 2048, other sizes are not accepted by Nextcloud (at the moment at least)
// ignore: avoid_redundant_argument_values
RSAKeypair generateKeypair() => RSAKeypair.fromRandom(keySize: 2048);
test('Register and remove push device', () async {
const pushToken = '789';
final keypair = generateKeypair();
final subscription = (await client.notifications.registerDevice(
pushTokenHash: generatePushTokenHash(pushToken),
devicePublicKey: keypair.publicKey.toFormattedPEM(),
proxyServer: 'https://example.com/',
))
.ocs
.data;
expect(subscription.publicKey, hasLength(451));
RSAPublicKey.fromPEM(subscription.publicKey);
expect(subscription.deviceIdentifier, isNotEmpty);
expect(subscription.signature, isNotEmpty);
expect(subscription.message, isNull);
await client.notifications.removeDevice();
});
});
group(
'push notifications',
() {
late DockerImage image;
setUpAll(() async => image = await getDockerImage());
late DockerContainer container;
late TestNextcloudClient client;
setUp(() async {
container = await getDockerContainer(image);
client = await getTestClient(
container,
username: 'admin',
);
});
tearDown(() => container.destroy());
// The key size has to be 2048, other sizes are not accepted by Nextcloud (at the moment at least)
// ignore: avoid_redundant_argument_values
RSAKeypair generateKeypair() => RSAKeypair.fromRandom(keySize: 2048);
test('Register and remove push device', () async {
const pushToken = '789';
final keypair = generateKeypair();
final subscription = (await client.notifications.registerDevice(
pushTokenHash: generatePushTokenHash(pushToken),
devicePublicKey: keypair.publicKey.toFormattedPEM(),
proxyServer: 'https://example.com/',
))
.ocs
.data;
expect(subscription.publicKey, hasLength(451));
RSAPublicKey.fromPEM(subscription.publicKey);
expect(subscription.deviceIdentifier, isNotEmpty);
expect(subscription.signature, isNotEmpty);
expect(subscription.message, isNull);
await client.notifications.removeDevice();
});
},
retry: retryCount,
timeout: timeout,
);
}

88
packages/nextcloud/test/provisioning_api_test.dart

@ -1,54 +1,56 @@
@Retry(3)
library provisioning_api_test;
import 'package:test/test.dart';
import 'helper.dart';
void main() {
group('provisioning_api', () {
late DockerImage image;
setUpAll(() async => image = await getDockerImage());
late DockerContainer container;
late TestNextcloudClient client;
setUp(() async {
container = await getDockerContainer(image);
client = await getTestClient(
container,
username: 'admin',
);
});
tearDown(() => container.destroy());
group('Users', () {
test('Get current user', () async {
final user = await client.provisioningApi.users.getCurrentUser();
expect(user.ocs.data.id, 'admin');
expect(user.ocs.data.displayName, 'admin');
expect(user.ocs.data.displaynameScope, 'v2-federated');
expect(user.ocs.data.language, 'en');
group(
'provisioning_api',
() {
late DockerImage image;
setUpAll(() async => image = await getDockerImage());
late DockerContainer container;
late TestNextcloudClient client;
setUp(() async {
container = await getDockerContainer(image);
client = await getTestClient(
container,
username: 'admin',
);
});
test('Get user by username', () async {
final user = await client.provisioningApi.users.getUser(userId: 'user1');
expect(user.ocs.data.id, 'user1');
expect(user.ocs.data.displayname, 'User One');
expect(user.ocs.data.displaynameScope, null);
expect(user.ocs.data.language, 'en');
tearDown(() => container.destroy());
group('Users', () {
test('Get current user', () async {
final user = await client.provisioningApi.users.getCurrentUser();
expect(user.ocs.data.id, 'admin');
expect(user.ocs.data.displayName, 'admin');
expect(user.ocs.data.displaynameScope, 'v2-federated');
expect(user.ocs.data.language, 'en');
});
test('Get user by username', () async {
final user = await client.provisioningApi.users.getUser(userId: 'user1');
expect(user.ocs.data.id, 'user1');
expect(user.ocs.data.displayname, 'User One');
expect(user.ocs.data.displaynameScope, null);
expect(user.ocs.data.language, 'en');
});
});
});
group('Apps', () {
test('Get apps', () async {
final response = await client.provisioningApi.apps.getApps();
expect(response.ocs.data.apps, hasLength(39));
group('Apps', () {
test('Get apps', () async {
final response = await client.provisioningApi.apps.getApps();
expect(response.ocs.data.apps, hasLength(39));
for (final id in response.ocs.data.apps) {
final app = await client.provisioningApi.apps.getAppInfo(app: id);
expect(app.ocs.data.id, isNotEmpty);
}
for (final id in response.ocs.data.apps) {
final app = await client.provisioningApi.apps.getAppInfo(app: id);
expect(app.ocs.data.id, isNotEmpty);
}
});
});
});
});
},
retry: retryCount,
timeout: timeout,
);
}

102
packages/nextcloud/test/uppush_test.dart

@ -1,67 +1,69 @@
@Retry(3)
library uppush_test;
import 'package:test/test.dart';
import 'helper.dart';
void main() {
group('uppush', () {
late DockerImage image;
setUpAll(() async => image = await getDockerImage());
group(
'uppush',
() {
late DockerImage image;
setUpAll(() async => image = await getDockerImage());
late DockerContainer container;
late TestNextcloudClient client;
setUp(() async {
container = await getDockerContainer(image);
client = await getTestClient(
container,
username: 'admin',
);
});
tearDown(() => container.destroy());
late DockerContainer container;
late TestNextcloudClient client;
setUp(() async {
container = await getDockerContainer(image);
client = await getTestClient(
container,
username: 'admin',
);
});
tearDown(() => container.destroy());
test('Is installed', () async {
final response = await client.uppush.check();
expect(response.success, isTrue);
});
test('Is installed', () async {
final response = await client.uppush.check();
expect(response.success, isTrue);
});
test('Set keepalive', () async {
final response = await client.uppush.setKeepalive(keepalive: 10);
expect(response.success, isTrue);
});
test('Set keepalive', () async {
final response = await client.uppush.setKeepalive(keepalive: 10);
expect(response.success, isTrue);
});
test('Create device', () async {
final response = await client.uppush.createDevice(deviceName: 'Test');
expect(response.success, isTrue);
expect(response.deviceId, isNotEmpty);
});
test('Create device', () async {
final response = await client.uppush.createDevice(deviceName: 'Test');
expect(response.success, isTrue);
expect(response.deviceId, isNotEmpty);
});
test('Delete device', () async {
final deviceId = (await client.uppush.createDevice(deviceName: 'Test')).deviceId;
test('Delete device', () async {
final deviceId = (await client.uppush.createDevice(deviceName: 'Test')).deviceId;
final response = await client.uppush.deleteDevice(deviceId: deviceId);
expect(response.success, isTrue);
});
final response = await client.uppush.deleteDevice(deviceId: deviceId);
expect(response.success, isTrue);
});
test('Create app', () async {
final deviceId = (await client.uppush.createDevice(deviceName: 'Test')).deviceId;
test('Create app', () async {
final deviceId = (await client.uppush.createDevice(deviceName: 'Test')).deviceId;
final response = await client.uppush.createApp(deviceId: deviceId, appName: 'Test');
expect(response.success, isTrue);
expect(response.token, isNotEmpty);
});
final response = await client.uppush.createApp(deviceId: deviceId, appName: 'Test');
expect(response.success, isTrue);
expect(response.token, isNotEmpty);
});
test('UnifiedPush discovery', () async {
final response = await client.uppush.unifiedpushDiscovery(token: 'example');
expect(response.unifiedpush.version, 1);
});
test('UnifiedPush discovery', () async {
final response = await client.uppush.unifiedpushDiscovery(token: 'example');
expect(response.unifiedpush.version, 1);
});
test('Matrix gateway discovery', () async {
final response = await client.uppush.gatewayMatrixDiscovery();
expect(response.unifiedpush.gateway, 'matrix');
});
test('Matrix gateway discovery', () async {
final response = await client.uppush.gatewayMatrixDiscovery();
expect(response.unifiedpush.gateway, 'matrix');
});
// Deleting an app, sending a notification (also via matrix gateway) or listening for notifications is not possible because redis is not set up
});
// Deleting an app, sending a notification (also via matrix gateway) or listening for notifications is not possible because redis is not set up
},
retry: retryCount,
timeout: timeout,
);
}

336
packages/nextcloud/test/user_status_test.dart

@ -1,174 +1,176 @@
@Retry(3)
library user_status_test;
import 'package:nextcloud/nextcloud.dart';
import 'package:test/test.dart';
import 'helper.dart';
void main() {
group('user_status', () {
late DockerImage image;
setUpAll(() async => image = await getDockerImage());
late DockerContainer container;
late TestNextcloudClient client;
setUp(() async {
container = await getDockerContainer(image);
client = await getTestClient(container);
});
tearDown(() => container.destroy());
test('Find all predefined statuses', () async {
final expectedStatusIDs = ['meeting', 'commuting', 'remote-work', 'sick-leave', 'vacationing'];
final response = await client.userStatus.predefinedStatus.findAll();
expect(response.ocs.data, hasLength(5));
final responseIDs = response.ocs.data.map((final status) => status.id);
expect(expectedStatusIDs.map(responseIDs.contains).contains(false), false);
for (final status in response.ocs.data) {
expect(status.icon, isNotNull);
expect(status.message, isNotNull);
}
final meeting = response.ocs.data.singleWhere((final s) => s.id == 'meeting').clearAt!;
expect(meeting.type, UserStatusClearAt_Type.period);
expect(meeting.time.$int, 3600);
final commuting = response.ocs.data.singleWhere((final s) => s.id == 'commuting').clearAt!;
expect(commuting.type, UserStatusClearAt_Type.period);
expect(commuting.time.$int, 1800);
final remoteWork = response.ocs.data.singleWhere((final s) => s.id == 'remote-work').clearAt!;
expect(remoteWork.type, UserStatusClearAt_Type.endOf);
expect(remoteWork.time.clearAtTimeType, UserStatusClearAtTimeType.day);
final sickLeave = response.ocs.data.singleWhere((final s) => s.id == 'sick-leave').clearAt!;
expect(sickLeave.type, UserStatusClearAt_Type.endOf);
expect(sickLeave.time.clearAtTimeType, UserStatusClearAtTimeType.day);
final vacationing = response.ocs.data.singleWhere((final s) => s.id == 'vacationing').clearAt;
expect(vacationing, null);
});
test('Set status', () async {
final response = await client.userStatus.userStatus.setStatus(statusType: 'online');
expect(response.ocs.data.public.userId, 'user1');
expect(response.ocs.data.public.message, null);
expect(response.ocs.data.private1.messageId, null);
expect(response.ocs.data.private1.messageIsPredefined, false);
expect(response.ocs.data.public.icon, null);
expect(response.ocs.data.public.clearAt, null);
expect(response.ocs.data.public.status, 'online');
expect(response.ocs.data.private1.statusIsUserDefined, true);
});
test('Get status', () async {
// There seems to be a bug in Nextcloud which makes getting the status fail before it has been set once.
// The error message from Nextcloud is "Could not create folder"
await client.userStatus.userStatus.setStatus(statusType: 'online');
final response = await client.userStatus.userStatus.getStatus();
expect(response.ocs.data.public.userId, 'user1');
expect(response.ocs.data.public.message, null);
expect(response.ocs.data.private1.messageId, null);
expect(response.ocs.data.private1.messageIsPredefined, false);
expect(response.ocs.data.public.icon, null);
expect(response.ocs.data.public.clearAt, null);
expect(response.ocs.data.public.status, 'online');
expect(response.ocs.data.private1.statusIsUserDefined, true);
});
test('Find all statuses', () async {
var response = await client.userStatus.statuses.findAll();
expect(response.ocs.data, hasLength(0));
await client.userStatus.userStatus.setStatus(statusType: 'online');
response = await client.userStatus.statuses.findAll();
expect(response.ocs.data, hasLength(1));
expect(response.ocs.data[0].userId, 'user1');
expect(response.ocs.data[0].message, null);
expect(response.ocs.data[0].icon, null);
expect(response.ocs.data[0].clearAt, null);
expect(response.ocs.data[0].status, 'online');
});
test('Find status', () async {
// Same as getting status
await client.userStatus.userStatus.setStatus(statusType: 'online');
final response = await client.userStatus.statuses.find(userId: 'user1');
expect(response.ocs.data.userId, 'user1');
expect(response.ocs.data.message, null);
expect(response.ocs.data.icon, null);
expect(response.ocs.data.clearAt, null);
expect(response.ocs.data.status, 'online');
});
test('Set predefined message', () async {
final clearAt = DateTime.now().millisecondsSinceEpoch ~/ 1000 + 60;
final response = await client.userStatus.userStatus.setPredefinedMessage(
messageId: 'meeting',
clearAt: clearAt,
);
expect(response.ocs.data.public.userId, 'user1');
expect(response.ocs.data.public.message, null);
expect(response.ocs.data.private1.messageId, 'meeting');
expect(response.ocs.data.private1.messageIsPredefined, true);
expect(response.ocs.data.public.icon, null);
expect(response.ocs.data.public.clearAt, clearAt);
expect(response.ocs.data.public.status, 'offline');
expect(response.ocs.data.private1.statusIsUserDefined, false);
});
test('Set custom message', () async {
final clearAt = DateTime.now().millisecondsSinceEpoch ~/ 1000 + 60;
final response = await client.userStatus.userStatus.setCustomMessage(
statusIcon: '😀',
message: 'bla',
clearAt: clearAt,
);
expect(response.ocs.data.public.userId, 'user1');
expect(response.ocs.data.public.message, 'bla');
expect(response.ocs.data.private1.messageId, null);
expect(response.ocs.data.private1.messageIsPredefined, false);
expect(response.ocs.data.public.icon, '😀');
expect(response.ocs.data.public.clearAt, clearAt);
expect(response.ocs.data.public.status, 'offline');
expect(response.ocs.data.private1.statusIsUserDefined, false);
});
test('Clear message', () async {
final clearAt = DateTime.now().millisecondsSinceEpoch ~/ 1000 + 60;
await client.userStatus.userStatus.setCustomMessage(
statusIcon: '😀',
message: 'bla',
clearAt: clearAt,
);
await client.userStatus.userStatus.clearMessage();
final response = await client.userStatus.userStatus.getStatus();
expect(response.ocs.data.public.userId, 'user1');
expect(response.ocs.data.public.message, null);
expect(response.ocs.data.private1.messageId, null);
expect(response.ocs.data.private1.messageIsPredefined, false);
expect(response.ocs.data.public.icon, null);
expect(response.ocs.data.public.clearAt, null);
expect(response.ocs.data.public.status, 'offline');
expect(response.ocs.data.private1.statusIsUserDefined, false);
});
test('Heartbeat', () async {
final response = await client.userStatus.heartbeat.heartbeat(status: 'online');
expect(response.ocs.data.public.userId, 'user1');
expect(response.ocs.data.public.message, null);
expect(response.ocs.data.private1.messageId, null);
expect(response.ocs.data.private1.messageIsPredefined, false);
expect(response.ocs.data.public.icon, null);
expect(response.ocs.data.public.clearAt, null);
expect(response.ocs.data.public.status, 'online');
expect(response.ocs.data.private1.statusIsUserDefined, false);
});
});
group(
'user_status',
() {
late DockerImage image;
setUpAll(() async => image = await getDockerImage());
late DockerContainer container;
late TestNextcloudClient client;
setUp(() async {
container = await getDockerContainer(image);
client = await getTestClient(container);
});
tearDown(() => container.destroy());
test('Find all predefined statuses', () async {
final expectedStatusIDs = ['meeting', 'commuting', 'remote-work', 'sick-leave', 'vacationing'];
final response = await client.userStatus.predefinedStatus.findAll();
expect(response.ocs.data, hasLength(5));
final responseIDs = response.ocs.data.map((final status) => status.id);
expect(expectedStatusIDs.map(responseIDs.contains).contains(false), false);
for (final status in response.ocs.data) {
expect(status.icon, isNotNull);
expect(status.message, isNotNull);
}
final meeting = response.ocs.data.singleWhere((final s) => s.id == 'meeting').clearAt!;
expect(meeting.type, UserStatusClearAt_Type.period);
expect(meeting.time.$int, 3600);
final commuting = response.ocs.data.singleWhere((final s) => s.id == 'commuting').clearAt!;
expect(commuting.type, UserStatusClearAt_Type.period);
expect(commuting.time.$int, 1800);
final remoteWork = response.ocs.data.singleWhere((final s) => s.id == 'remote-work').clearAt!;
expect(remoteWork.type, UserStatusClearAt_Type.endOf);
expect(remoteWork.time.clearAtTimeType, UserStatusClearAtTimeType.day);
final sickLeave = response.ocs.data.singleWhere((final s) => s.id == 'sick-leave').clearAt!;
expect(sickLeave.type, UserStatusClearAt_Type.endOf);
expect(sickLeave.time.clearAtTimeType, UserStatusClearAtTimeType.day);
final vacationing = response.ocs.data.singleWhere((final s) => s.id == 'vacationing').clearAt;
expect(vacationing, null);
});
test('Set status', () async {
final response = await client.userStatus.userStatus.setStatus(statusType: 'online');
expect(response.ocs.data.public.userId, 'user1');
expect(response.ocs.data.public.message, null);
expect(response.ocs.data.private1.messageId, null);
expect(response.ocs.data.private1.messageIsPredefined, false);
expect(response.ocs.data.public.icon, null);
expect(response.ocs.data.public.clearAt, null);
expect(response.ocs.data.public.status, 'online');
expect(response.ocs.data.private1.statusIsUserDefined, true);
});
test('Get status', () async {
// There seems to be a bug in Nextcloud which makes getting the status fail before it has been set once.
// The error message from Nextcloud is "Could not create folder"
await client.userStatus.userStatus.setStatus(statusType: 'online');
final response = await client.userStatus.userStatus.getStatus();
expect(response.ocs.data.public.userId, 'user1');
expect(response.ocs.data.public.message, null);
expect(response.ocs.data.private1.messageId, null);
expect(response.ocs.data.private1.messageIsPredefined, false);
expect(response.ocs.data.public.icon, null);
expect(response.ocs.data.public.clearAt, null);
expect(response.ocs.data.public.status, 'online');
expect(response.ocs.data.private1.statusIsUserDefined, true);
});
test('Find all statuses', () async {
var response = await client.userStatus.statuses.findAll();
expect(response.ocs.data, hasLength(0));
await client.userStatus.userStatus.setStatus(statusType: 'online');
response = await client.userStatus.statuses.findAll();
expect(response.ocs.data, hasLength(1));
expect(response.ocs.data[0].userId, 'user1');
expect(response.ocs.data[0].message, null);
expect(response.ocs.data[0].icon, null);
expect(response.ocs.data[0].clearAt, null);
expect(response.ocs.data[0].status, 'online');
});
test('Find status', () async {
// Same as getting status
await client.userStatus.userStatus.setStatus(statusType: 'online');
final response = await client.userStatus.statuses.find(userId: 'user1');
expect(response.ocs.data.userId, 'user1');
expect(response.ocs.data.message, null);
expect(response.ocs.data.icon, null);
expect(response.ocs.data.clearAt, null);
expect(response.ocs.data.status, 'online');
});
test('Set predefined message', () async {
final clearAt = DateTime.now().millisecondsSinceEpoch ~/ 1000 + 60;
final response = await client.userStatus.userStatus.setPredefinedMessage(
messageId: 'meeting',
clearAt: clearAt,
);
expect(response.ocs.data.public.userId, 'user1');
expect(response.ocs.data.public.message, null);
expect(response.ocs.data.private1.messageId, 'meeting');
expect(response.ocs.data.private1.messageIsPredefined, true);
expect(response.ocs.data.public.icon, null);
expect(response.ocs.data.public.clearAt, clearAt);
expect(response.ocs.data.public.status, 'offline');
expect(response.ocs.data.private1.statusIsUserDefined, false);
});
test('Set custom message', () async {
final clearAt = DateTime.now().millisecondsSinceEpoch ~/ 1000 + 60;
final response = await client.userStatus.userStatus.setCustomMessage(
statusIcon: '😀',
message: 'bla',
clearAt: clearAt,
);
expect(response.ocs.data.public.userId, 'user1');
expect(response.ocs.data.public.message, 'bla');
expect(response.ocs.data.private1.messageId, null);
expect(response.ocs.data.private1.messageIsPredefined, false);
expect(response.ocs.data.public.icon, '😀');
expect(response.ocs.data.public.clearAt, clearAt);
expect(response.ocs.data.public.status, 'offline');
expect(response.ocs.data.private1.statusIsUserDefined, false);
});
test('Clear message', () async {
final clearAt = DateTime.now().millisecondsSinceEpoch ~/ 1000 + 60;
await client.userStatus.userStatus.setCustomMessage(
statusIcon: '😀',
message: 'bla',
clearAt: clearAt,
);
await client.userStatus.userStatus.clearMessage();
final response = await client.userStatus.userStatus.getStatus();
expect(response.ocs.data.public.userId, 'user1');
expect(response.ocs.data.public.message, null);
expect(response.ocs.data.private1.messageId, null);
expect(response.ocs.data.private1.messageIsPredefined, false);
expect(response.ocs.data.public.icon, null);
expect(response.ocs.data.public.clearAt, null);
expect(response.ocs.data.public.status, 'offline');
expect(response.ocs.data.private1.statusIsUserDefined, false);
});
test('Heartbeat', () async {
final response = await client.userStatus.heartbeat.heartbeat(status: 'online');
expect(response.ocs.data.public.userId, 'user1');
expect(response.ocs.data.public.message, null);
expect(response.ocs.data.private1.messageId, null);
expect(response.ocs.data.private1.messageIsPredefined, false);
expect(response.ocs.data.public.icon, null);
expect(response.ocs.data.public.clearAt, null);
expect(response.ocs.data.public.status, 'online');
expect(response.ocs.data.private1.statusIsUserDefined, false);
});
},
retry: retryCount,
timeout: timeout,
);
}

921
packages/nextcloud/test/webdav_test.dart

@ -1,6 +1,3 @@
@Retry(3)
library webdav_test;
import 'dart:convert';
import 'dart:io';
import 'dart:math';
@ -26,508 +23,514 @@ void main() {
expect(() => WebDavClient.constructUri(baseURL), throwsA(isA<AssertionError>()));
});
group('webdav', () {
late DockerImage image;
setUpAll(() async => image = await getDockerImage());
late DockerContainer container;
late TestNextcloudClient client;
setUp(() async {
container = await getDockerContainer(image);
client = await getTestClient(container);
});
tearDown(() => container.destroy());
test('List directory', () async {
final responses = (await client.webdav.propfind(
Uri(path: '/'),
prop: WebDavPropWithoutValues.fromBools(
nchaspreview: true,
davgetcontenttype: true,
davgetlastmodified: true,
ocsize: true,
),
))
.responses;
expect(responses, hasLength(10));
final props =
responses.singleWhere((final response) => response.href!.endsWith('/Nextcloud.png')).propstats.first.prop;
expect(props.nchaspreview, isTrue);
expect(props.davgetcontenttype, 'image/png');
expect(webdavDateFormat.parseUtc(props.davgetlastmodified!).isBefore(DateTime.now()), isTrue);
expect(props.ocsize, 50598);
});
test('List directory recursively', () async {
final responses = (await client.webdav.propfind(
Uri(path: '/'),
depth: WebDavDepth.infinity,
))
.responses;
expect(responses, hasLength(48));
});
test('Get file props', () async {
final response = (await client.webdav.propfind(
Uri(path: 'Nextcloud.png'),
prop: WebDavPropWithoutValues.fromBools(
davgetlastmodified: true,
davgetetag: true,
davgetcontenttype: true,
davgetcontentlength: true,
davresourcetype: true,
ocid: true,
ocfileid: true,
ocfavorite: true,
occommentshref: true,
occommentscount: true,
occommentsunread: true,
ocdownloadurl: true,
ocownerid: true,
ocownerdisplayname: true,
ocsize: true,
ocpermissions: true,
ncnote: true,
ncdatafingerprint: true,
nchaspreview: true,
ncmounttype: true,
ncisencrypted: true,
ncmetadataetag: true,
ncuploadtime: true,
nccreationtime: true,
ncrichworkspace: true,
ocssharepermissions: true,
ocmsharepermissions: true,
),
))
.toWebDavFiles()
.single;
expect(response.path, '/Nextcloud.png');
expect(response.id, isNotEmpty);
expect(response.fileId, isNotEmpty);
expect(response.isCollection, isFalse);
expect(response.mimeType, 'image/png');
expect(response.etag, isNotEmpty);
expect(response.size, 50598);
expect(response.ownerId, 'user1');
expect(response.ownerDisplay, 'User One');
expect(response.lastModified!.isBefore(DateTime.now()), isTrue);
expect(response.isDirectory, isFalse);
expect(response.uploadedDate, DateTime.utc(1970));
expect(response.createdDate, DateTime.utc(1970));
expect(response.favorite, isFalse);
expect(response.hasPreview, isTrue);
expect(response.name, 'Nextcloud.png');
expect(response.isDirectory, isFalse);
expect(webdavDateFormat.parseUtc(response.props.davgetlastmodified!).isBefore(DateTime.now()), isTrue);
expect(response.props.davgetetag, isNotEmpty);
expect(response.props.davgetcontenttype, 'image/png');
expect(response.props.davgetcontentlength, 50598);
expect(response.props.davresourcetype!.collection, isNull);
expect(response.props.ocid, isNotEmpty);
expect(response.props.ocfileid, isNotEmpty);
expect(response.props.ocfavorite, 0);
expect(response.props.occommentshref, isNotEmpty);
expect(response.props.occommentscount, 0);
expect(response.props.occommentsunread, 0);
expect(response.props.ocdownloadurl, isNull);
expect(response.props.ocownerid, 'user1');
expect(response.props.ocownerdisplayname, 'User One');
expect(response.props.ocsize, 50598);
expect(response.props.ocpermissions, 'RGDNVW');
expect(response.props.ncnote, isNull);
expect(response.props.ncdatafingerprint, isNull);
expect(response.props.nchaspreview, isTrue);
expect(response.props.ncmounttype, isNull);
expect(response.props.ncisencrypted, isNull);
expect(response.props.ncmetadataetag, isNull);
expect(response.props.ncuploadtime, 0);
expect(response.props.nccreationtime, 0);
expect(response.props.ncrichworkspace, isNull);
expect(response.props.ocssharepermissions, 19);
expect(json.decode(response.props.ocmsharepermissions!), ['share', 'read', 'write']);
});
test('Get directory props', () async {
final data = utf8.encode('test') as Uint8List;
await client.webdav.mkcol(Uri(path: 'test'));
await client.webdav.put(data, Uri(path: 'test/test.txt'));
final response = (await client.webdav.propfind(
Uri(path: 'test'),
prop: WebDavPropWithoutValues.fromBools(
davgetcontenttype: true,
davgetlastmodified: true,
davresourcetype: true,
ocsize: true,
),
depth: WebDavDepth.zero,
))
.toWebDavFiles()
.single;
expect(response.path, '/test/');
expect(response.isCollection, isTrue);
expect(response.mimeType, isNull);
expect(response.size, data.lengthInBytes);
expectDateInReasonableTimeRange(response.lastModified!, DateTime.now());
expect(response.name, 'test');
expect(response.isDirectory, isTrue);
expect(response.props.davgetcontenttype, isNull);
expectDateInReasonableTimeRange(webdavDateFormat.parseUtc(response.props.davgetlastmodified!), DateTime.now());
expect(response.props.davresourcetype!.collection, isNotNull);
expect(response.props.ocsize, data.lengthInBytes);
});
test('Filter files', () async {
final response = await client.webdav.put(utf8.encode('test') as Uint8List, Uri(path: 'test.txt'));
final id = response.headers['oc-fileid']!.first;
await client.webdav.proppatch(
Uri(path: 'test.txt'),
set: WebDavProp(
ocfavorite: 1,
),
);
final responses = (await client.webdav.report(
Uri(path: '/'),
WebDavOcFilterRules(
ocfavorite: 1,
),
prop: WebDavPropWithoutValues.fromBools(
ocid: true,
ocfavorite: true,
),
))
.responses;
expect(responses, hasLength(1));
final props =
responses.singleWhere((final response) => response.href!.endsWith('/test.txt')).propstats.first.prop;
expect(props.ocid, id);
expect(props.ocfavorite, 1);
});
test('Set properties', () async {
final lastModifiedDate = DateTime.utc(1972, 3);
final createdDate = DateTime.utc(1971, 2);
final uploadTime = DateTime.now();
await client.webdav.put(
utf8.encode('test') as Uint8List,
Uri(path: 'test.txt'),
lastModified: lastModifiedDate,
created: createdDate,
);
final updated = await client.webdav.proppatch(
Uri(path: 'test.txt'),
set: WebDavProp(
ocfavorite: 1,
),
);
expect(updated, isTrue);
final props = (await client.webdav.propfind(
Uri(path: 'test.txt'),
prop: WebDavPropWithoutValues.fromBools(
ocfavorite: true,
davgetlastmodified: true,
nccreationtime: true,
ncuploadtime: true,
),
))
.responses
.single
.propstats
.first
.prop;
expect(props.ocfavorite, 1);
expect(webdavDateFormat.parseUtc(props.davgetlastmodified!), lastModifiedDate);
expect(DateTime.fromMillisecondsSinceEpoch(props.nccreationtime! * 1000).isAtSameMomentAs(createdDate), isTrue);
expectDateInReasonableTimeRange(DateTime.fromMillisecondsSinceEpoch(props.ncuploadtime! * 1000), uploadTime);
});
test('Remove properties', () async {
await client.webdav.put(utf8.encode('test') as Uint8List, Uri(path: 'test.txt'));
var updated = await client.webdav.proppatch(
Uri(path: 'test.txt'),
set: WebDavProp(
ocfavorite: 1,
),
);
expect(updated, isTrue);
var props = (await client.webdav.propfind(
Uri(path: 'test.txt'),
prop: WebDavPropWithoutValues.fromBools(
ocfavorite: true,
nccreationtime: true,
ncuploadtime: true,
),
))
.responses
.single
.propstats
.first
.prop;
expect(props.ocfavorite, 1);
updated = await client.webdav.proppatch(
Uri(path: 'test.txt'),
remove: WebDavPropWithoutValues.fromBools(
ocfavorite: true,
),
);
expect(updated, isFalse);
props = (await client.webdav.propfind(
Uri(path: 'test.txt'),
prop: WebDavPropWithoutValues.fromBools(
ocfavorite: true,
),
))
.responses
.single
.propstats
.first
.prop;
expect(props.ocfavorite, 0);
});
test('Upload and download file', () async {
final destinationDir = Directory.systemTemp.createTempSync();
final destination = File('${destinationDir.path}/test.png');
final source = File('test/files/test.png');
final progressValues = <double>[];
await client.webdav.putFile(
source,
source.statSync(),
Uri(path: 'test.png'),
onProgress: progressValues.add,
);
await client.webdav.getFile(
Uri(path: 'test.png'),
destination,
onProgress: progressValues.add,
);
expect(progressValues, containsAll([1.0, 1.0]));
expect(destination.readAsBytesSync(), source.readAsBytesSync());
destinationDir.deleteSync(recursive: true);
});
group('litmus', () {
group('basic', () {
test('options', () async {
final options = await client.webdav.options();
expect(options.capabilities, contains('1'));
expect(options.capabilities, contains('3'));
// Nextcloud only contains a fake plugin for Class 2 support: https://github.com/nextcloud/server/blob/master/apps/dav/lib/Connector/Sabre/FakeLockerPlugin.php
// It does not actually support locking and is only there for compatibility reasons.
expect(options.capabilities, isNot(contains('2')));
});
group(
'webdav',
() {
late DockerImage image;
setUpAll(() async => image = await getDockerImage());
for (final (name, path) in [
('put_get', 'res'),
('put_get_utf8_segment', 'res-%e2%82%ac'),
]) {
test(name, () async {
final content = utf8.encode('This is a test file') as Uint8List;
late DockerContainer container;
late TestNextcloudClient client;
final response = await client.webdav.put(content, Uri(path: path));
expect(response.statusCode, 201);
setUp(() async {
container = await getDockerContainer(image);
client = await getTestClient(container);
});
tearDown(() => container.destroy());
test('List directory', () async {
final responses = (await client.webdav.propfind(
Uri(path: '/'),
prop: WebDavPropWithoutValues.fromBools(
nchaspreview: true,
davgetcontenttype: true,
davgetlastmodified: true,
ocsize: true,
),
))
.responses;
expect(responses, hasLength(10));
final props =
responses.singleWhere((final response) => response.href!.endsWith('/Nextcloud.png')).propstats.first.prop;
expect(props.nchaspreview, isTrue);
expect(props.davgetcontenttype, 'image/png');
expect(webdavDateFormat.parseUtc(props.davgetlastmodified!).isBefore(DateTime.now()), isTrue);
expect(props.ocsize, 50598);
});
final downloadedContent = await client.webdav.get(Uri(path: path));
expect(downloadedContent, equals(content));
});
}
test('put_no_parent', () async {
expect(
() => client.webdav.put(Uint8List(0), Uri(path: '409me/noparent.txt')),
// https://github.com/nextcloud/server/issues/39625
throwsA(predicate<DynamiteApiException>((final e) => e.statusCode == 409)),
);
});
test('List directory recursively', () async {
final responses = (await client.webdav.propfind(
Uri(path: '/'),
depth: WebDavDepth.infinity,
))
.responses;
expect(responses, hasLength(48));
});
test('delete', () async {
await client.webdav.put(Uint8List(0), Uri(path: 'test.txt'));
test('Get file props', () async {
final response = (await client.webdav.propfind(
Uri(path: 'Nextcloud.png'),
prop: WebDavPropWithoutValues.fromBools(
davgetlastmodified: true,
davgetetag: true,
davgetcontenttype: true,
davgetcontentlength: true,
davresourcetype: true,
ocid: true,
ocfileid: true,
ocfavorite: true,
occommentshref: true,
occommentscount: true,
occommentsunread: true,
ocdownloadurl: true,
ocownerid: true,
ocownerdisplayname: true,
ocsize: true,
ocpermissions: true,
ncnote: true,
ncdatafingerprint: true,
nchaspreview: true,
ncmounttype: true,
ncisencrypted: true,
ncmetadataetag: true,
ncuploadtime: true,
nccreationtime: true,
ncrichworkspace: true,
ocssharepermissions: true,
ocmsharepermissions: true,
),
))
.toWebDavFiles()
.single;
expect(response.path, '/Nextcloud.png');
expect(response.id, isNotEmpty);
expect(response.fileId, isNotEmpty);
expect(response.isCollection, isFalse);
expect(response.mimeType, 'image/png');
expect(response.etag, isNotEmpty);
expect(response.size, 50598);
expect(response.ownerId, 'user1');
expect(response.ownerDisplay, 'User One');
expect(response.lastModified!.isBefore(DateTime.now()), isTrue);
expect(response.isDirectory, isFalse);
expect(response.uploadedDate, DateTime.utc(1970));
expect(response.createdDate, DateTime.utc(1970));
expect(response.favorite, isFalse);
expect(response.hasPreview, isTrue);
expect(response.name, 'Nextcloud.png');
expect(response.isDirectory, isFalse);
expect(webdavDateFormat.parseUtc(response.props.davgetlastmodified!).isBefore(DateTime.now()), isTrue);
expect(response.props.davgetetag, isNotEmpty);
expect(response.props.davgetcontenttype, 'image/png');
expect(response.props.davgetcontentlength, 50598);
expect(response.props.davresourcetype!.collection, isNull);
expect(response.props.ocid, isNotEmpty);
expect(response.props.ocfileid, isNotEmpty);
expect(response.props.ocfavorite, 0);
expect(response.props.occommentshref, isNotEmpty);
expect(response.props.occommentscount, 0);
expect(response.props.occommentsunread, 0);
expect(response.props.ocdownloadurl, isNull);
expect(response.props.ocownerid, 'user1');
expect(response.props.ocownerdisplayname, 'User One');
expect(response.props.ocsize, 50598);
expect(response.props.ocpermissions, 'RGDNVW');
expect(response.props.ncnote, isNull);
expect(response.props.ncdatafingerprint, isNull);
expect(response.props.nchaspreview, isTrue);
expect(response.props.ncmounttype, isNull);
expect(response.props.ncisencrypted, isNull);
expect(response.props.ncmetadataetag, isNull);
expect(response.props.ncuploadtime, 0);
expect(response.props.nccreationtime, 0);
expect(response.props.ncrichworkspace, isNull);
expect(response.props.ocssharepermissions, 19);
expect(json.decode(response.props.ocmsharepermissions!), ['share', 'read', 'write']);
});
final response = await client.webdav.delete(Uri(path: 'test.txt'));
expect(response.statusCode, 204);
});
test('Get directory props', () async {
final data = utf8.encode('test') as Uint8List;
await client.webdav.mkcol(Uri(path: 'test'));
await client.webdav.put(data, Uri(path: 'test/test.txt'));
final response = (await client.webdav.propfind(
Uri(path: 'test'),
prop: WebDavPropWithoutValues.fromBools(
davgetcontenttype: true,
davgetlastmodified: true,
davresourcetype: true,
ocsize: true,
),
depth: WebDavDepth.zero,
))
.toWebDavFiles()
.single;
expect(response.path, '/test/');
expect(response.isCollection, isTrue);
expect(response.mimeType, isNull);
expect(response.size, data.lengthInBytes);
expectDateInReasonableTimeRange(response.lastModified!, DateTime.now());
expect(response.name, 'test');
expect(response.isDirectory, isTrue);
expect(response.props.davgetcontenttype, isNull);
expectDateInReasonableTimeRange(webdavDateFormat.parseUtc(response.props.davgetlastmodified!), DateTime.now());
expect(response.props.davresourcetype!.collection, isNotNull);
expect(response.props.ocsize, data.lengthInBytes);
});
test('delete_null', () async {
expect(
() => client.webdav.delete(Uri(path: 'test.txt')),
throwsA(predicate<DynamiteApiException>((final e) => e.statusCode == 404)),
);
});
test('Filter files', () async {
final response = await client.webdav.put(utf8.encode('test') as Uint8List, Uri(path: 'test.txt'));
final id = response.headers['oc-fileid']!.first;
await client.webdav.proppatch(
Uri(path: 'test.txt'),
set: WebDavProp(
ocfavorite: 1,
),
);
final responses = (await client.webdav.report(
Uri(path: '/'),
WebDavOcFilterRules(
ocfavorite: 1,
),
prop: WebDavPropWithoutValues.fromBools(
ocid: true,
ocfavorite: true,
),
))
.responses;
expect(responses, hasLength(1));
final props =
responses.singleWhere((final response) => response.href!.endsWith('/test.txt')).propstats.first.prop;
expect(props.ocid, id);
expect(props.ocfavorite, 1);
});
// delete_fragment: This test is not applicable because the fragment is already removed on the client side
test('Set properties', () async {
final lastModifiedDate = DateTime.utc(1972, 3);
final createdDate = DateTime.utc(1971, 2);
final uploadTime = DateTime.now();
await client.webdav.put(
utf8.encode('test') as Uint8List,
Uri(path: 'test.txt'),
lastModified: lastModifiedDate,
created: createdDate,
);
final updated = await client.webdav.proppatch(
Uri(path: 'test.txt'),
set: WebDavProp(
ocfavorite: 1,
),
);
expect(updated, isTrue);
final props = (await client.webdav.propfind(
Uri(path: 'test.txt'),
prop: WebDavPropWithoutValues.fromBools(
ocfavorite: true,
davgetlastmodified: true,
nccreationtime: true,
ncuploadtime: true,
),
))
.responses
.single
.propstats
.first
.prop;
expect(props.ocfavorite, 1);
expect(webdavDateFormat.parseUtc(props.davgetlastmodified!), lastModifiedDate);
expect(DateTime.fromMillisecondsSinceEpoch(props.nccreationtime! * 1000).isAtSameMomentAs(createdDate), isTrue);
expectDateInReasonableTimeRange(DateTime.fromMillisecondsSinceEpoch(props.ncuploadtime! * 1000), uploadTime);
});
test('mkcol', () async {
final response = await client.webdav.mkcol(Uri(path: 'test'));
expect(response.statusCode, 201);
});
test('Remove properties', () async {
await client.webdav.put(utf8.encode('test') as Uint8List, Uri(path: 'test.txt'));
var updated = await client.webdav.proppatch(
Uri(path: 'test.txt'),
set: WebDavProp(
ocfavorite: 1,
),
);
expect(updated, isTrue);
var props = (await client.webdav.propfind(
Uri(path: 'test.txt'),
prop: WebDavPropWithoutValues.fromBools(
ocfavorite: true,
nccreationtime: true,
ncuploadtime: true,
),
))
.responses
.single
.propstats
.first
.prop;
expect(props.ocfavorite, 1);
updated = await client.webdav.proppatch(
Uri(path: 'test.txt'),
remove: WebDavPropWithoutValues.fromBools(
ocfavorite: true,
),
);
expect(updated, isFalse);
props = (await client.webdav.propfind(
Uri(path: 'test.txt'),
prop: WebDavPropWithoutValues.fromBools(
ocfavorite: true,
),
))
.responses
.single
.propstats
.first
.prop;
expect(props.ocfavorite, 0);
});
test('mkcol_again', () async {
await client.webdav.mkcol(Uri(path: 'test'));
test('Upload and download file', () async {
final destinationDir = Directory.systemTemp.createTempSync();
final destination = File('${destinationDir.path}/test.png');
final source = File('test/files/test.png');
final progressValues = <double>[];
await client.webdav.putFile(
source,
source.statSync(),
Uri(path: 'test.png'),
onProgress: progressValues.add,
);
await client.webdav.getFile(
Uri(path: 'test.png'),
destination,
onProgress: progressValues.add,
);
expect(progressValues, containsAll([1.0, 1.0]));
expect(destination.readAsBytesSync(), source.readAsBytesSync());
destinationDir.deleteSync(recursive: true);
});
expect(
() => client.webdav.mkcol(Uri(path: 'test')),
throwsA(predicate<DynamiteApiException>((final e) => e.statusCode == 405)),
);
});
group('litmus', () {
group('basic', () {
test('options', () async {
final options = await client.webdav.options();
expect(options.capabilities, contains('1'));
expect(options.capabilities, contains('3'));
// Nextcloud only contains a fake plugin for Class 2 support: https://github.com/nextcloud/server/blob/master/apps/dav/lib/Connector/Sabre/FakeLockerPlugin.php
// It does not actually support locking and is only there for compatibility reasons.
expect(options.capabilities, isNot(contains('2')));
});
test('delete_coll', () async {
var response = await client.webdav.mkcol(Uri(path: 'test'));
for (final (name, path) in [
('put_get', 'res'),
('put_get_utf8_segment', 'res-%e2%82%ac'),
]) {
test(name, () async {
final content = utf8.encode('This is a test file') as Uint8List;
response = await client.webdav.delete(Uri(path: 'test'));
expect(response.statusCode, 204);
});
final response = await client.webdav.put(content, Uri(path: path));
expect(response.statusCode, 201);
test('mkcol_no_parent', () async {
expect(
() => client.webdav.mkcol(Uri(path: '409me/noparent')),
throwsA(predicate<DynamiteApiException>((final e) => e.statusCode == 409)),
);
});
final downloadedContent = await client.webdav.get(Uri(path: path));
expect(downloadedContent, equals(content));
});
}
// mkcol_with_body: This test is not applicable because we only write valid request bodies
});
test('put_no_parent', () async {
expect(
() => client.webdav.put(Uint8List(0), Uri(path: '409me/noparent.txt')),
// https://github.com/nextcloud/server/issues/39625
throwsA(predicate<DynamiteApiException>((final e) => e.statusCode == 409)),
);
});
group('copymove', () {
test('copy_simple', () async {
await client.webdav.mkcol(Uri(path: 'src'));
test('delete', () async {
await client.webdav.put(Uint8List(0), Uri(path: 'test.txt'));
final response = await client.webdav.copy(Uri(path: 'src'), Uri(path: 'dst'));
expect(response.statusCode, 201);
});
final response = await client.webdav.delete(Uri(path: 'test.txt'));
expect(response.statusCode, 204);
});
test('delete_null', () async {
expect(
() => client.webdav.delete(Uri(path: 'test.txt')),
throwsA(predicate<DynamiteApiException>((final e) => e.statusCode == 404)),
);
});
test('copy_overwrite', () async {
await client.webdav.mkcol(Uri(path: 'src'));
await client.webdav.mkcol(Uri(path: 'dst'));
// delete_fragment: This test is not applicable because the fragment is already removed on the client side
expect(
() => client.webdav.copy(Uri(path: 'src'), Uri(path: 'dst')),
throwsA(predicate<DynamiteApiException>((final e) => e.statusCode == 412)),
);
test('mkcol', () async {
final response = await client.webdav.mkcol(Uri(path: 'test'));
expect(response.statusCode, 201);
});
final response = await client.webdav.copy(Uri(path: 'src'), Uri(path: 'dst'), overwrite: true);
expect(response.statusCode, 204);
});
test('mkcol_again', () async {
await client.webdav.mkcol(Uri(path: 'test'));
test('copy_nodestcoll', () async {
await client.webdav.mkcol(Uri(path: 'src'));
expect(
() => client.webdav.mkcol(Uri(path: 'test')),
throwsA(predicate<DynamiteApiException>((final e) => e.statusCode == 405)),
);
});
test('delete_coll', () async {
var response = await client.webdav.mkcol(Uri(path: 'test'));
response = await client.webdav.delete(Uri(path: 'test'));
expect(response.statusCode, 204);
});
test('mkcol_no_parent', () async {
expect(
() => client.webdav.mkcol(Uri(path: '409me/noparent')),
throwsA(predicate<DynamiteApiException>((final e) => e.statusCode == 409)),
);
});
expect(
() => client.webdav.copy(Uri(path: 'src'), Uri(path: 'nonesuch/dst')),
throwsA(predicate<DynamiteApiException>((final e) => e.statusCode == 409)),
);
// mkcol_with_body: This test is not applicable because we only write valid request bodies
});
test('copy_coll', () async {
await client.webdav.mkcol(Uri(path: 'src'));
await client.webdav.mkcol(Uri(path: 'src/sub'));
for (var i = 0; i < 10; i++) {
await client.webdav.put(Uint8List(0), Uri(path: 'src/$i.txt'));
}
await client.webdav.copy(Uri(path: 'src'), Uri(path: 'dst1'));
await client.webdav.copy(Uri(path: 'src'), Uri(path: 'dst2'));
group('copymove', () {
test('copy_simple', () async {
await client.webdav.mkcol(Uri(path: 'src'));
expect(
() => client.webdav.copy(Uri(path: 'src'), Uri(path: 'dst1')),
throwsA(predicate<DynamiteApiException>((final e) => e.statusCode == 412)),
);
final response = await client.webdav.copy(Uri(path: 'src'), Uri(path: 'dst'));
expect(response.statusCode, 201);
});
var response = await client.webdav.copy(Uri(path: 'src'), Uri(path: 'dst2'), overwrite: true);
expect(response.statusCode, 204);
test('copy_overwrite', () async {
await client.webdav.mkcol(Uri(path: 'src'));
await client.webdav.mkcol(Uri(path: 'dst'));
for (var i = 0; i < 10; i++) {
response = await client.webdav.delete(Uri(path: 'dst1/$i.txt'));
expect(
() => client.webdav.copy(Uri(path: 'src'), Uri(path: 'dst')),
throwsA(predicate<DynamiteApiException>((final e) => e.statusCode == 412)),
);
final response = await client.webdav.copy(Uri(path: 'src'), Uri(path: 'dst'), overwrite: true);
expect(response.statusCode, 204);
}
});
response = await client.webdav.delete(Uri(path: 'dst1/sub'));
expect(response.statusCode, 204);
test('copy_nodestcoll', () async {
await client.webdav.mkcol(Uri(path: 'src'));
response = await client.webdav.delete(Uri(path: 'dst2'));
expect(response.statusCode, 204);
});
expect(
() => client.webdav.copy(Uri(path: 'src'), Uri(path: 'nonesuch/dst')),
throwsA(predicate<DynamiteApiException>((final e) => e.statusCode == 409)),
);
});
// copy_shallow: Does not work on litmus, let's wait for https://github.com/nextcloud/server/issues/39627
test('copy_coll', () async {
await client.webdav.mkcol(Uri(path: 'src'));
await client.webdav.mkcol(Uri(path: 'src/sub'));
for (var i = 0; i < 10; i++) {
await client.webdav.put(Uint8List(0), Uri(path: 'src/$i.txt'));
}
await client.webdav.copy(Uri(path: 'src'), Uri(path: 'dst1'));
await client.webdav.copy(Uri(path: 'src'), Uri(path: 'dst2'));
expect(
() => client.webdav.copy(Uri(path: 'src'), Uri(path: 'dst1')),
throwsA(predicate<DynamiteApiException>((final e) => e.statusCode == 412)),
);
var response = await client.webdav.copy(Uri(path: 'src'), Uri(path: 'dst2'), overwrite: true);
expect(response.statusCode, 204);
test('move', () async {
await client.webdav.put(Uint8List(0), Uri(path: 'src1.txt'));
await client.webdav.put(Uint8List(0), Uri(path: 'src2.txt'));
await client.webdav.mkcol(Uri(path: 'coll'));
for (var i = 0; i < 10; i++) {
response = await client.webdav.delete(Uri(path: 'dst1/$i.txt'));
expect(response.statusCode, 204);
}
var response = await client.webdav.move(Uri(path: 'src1.txt'), Uri(path: 'dst.txt'));
expect(response.statusCode, 201);
response = await client.webdav.delete(Uri(path: 'dst1/sub'));
expect(response.statusCode, 204);
expect(
() => client.webdav.move(Uri(path: 'src2.txt'), Uri(path: 'dst.txt')),
throwsA(predicate<DynamiteApiException>((final e) => e.statusCode == 412)),
);
response = await client.webdav.delete(Uri(path: 'dst2'));
expect(response.statusCode, 204);
});
response = await client.webdav.move(Uri(path: 'src2.txt'), Uri(path: 'dst.txt'), overwrite: true);
expect(response.statusCode, 204);
});
// copy_shallow: Does not work on litmus, let's wait for https://github.com/nextcloud/server/issues/39627
test('move_coll', () async {
await client.webdav.mkcol(Uri(path: 'src'));
await client.webdav.mkcol(Uri(path: 'src/sub'));
for (var i = 0; i < 10; i++) {
await client.webdav.put(Uint8List(0), Uri(path: 'src/$i.txt'));
}
await client.webdav.put(Uint8List(0), Uri(path: 'noncoll'));
await client.webdav.copy(Uri(path: 'src'), Uri(path: 'dst2'));
await client.webdav.move(Uri(path: 'src'), Uri(path: 'dst1'));
test('move', () async {
await client.webdav.put(Uint8List(0), Uri(path: 'src1.txt'));
await client.webdav.put(Uint8List(0), Uri(path: 'src2.txt'));
await client.webdav.mkcol(Uri(path: 'coll'));
expect(
() => client.webdav.move(Uri(path: 'dst1'), Uri(path: 'dst2')),
throwsA(predicate<DynamiteApiException>((final e) => e.statusCode == 412)),
);
var response = await client.webdav.move(Uri(path: 'src1.txt'), Uri(path: 'dst.txt'));
expect(response.statusCode, 201);
await client.webdav.move(Uri(path: 'dst2'), Uri(path: 'dst1'), overwrite: true);
await client.webdav.copy(Uri(path: 'dst1'), Uri(path: 'dst2'));
expect(
() => client.webdav.move(Uri(path: 'src2.txt'), Uri(path: 'dst.txt')),
throwsA(predicate<DynamiteApiException>((final e) => e.statusCode == 412)),
);
for (var i = 0; i < 10; i++) {
final response = await client.webdav.delete(Uri(path: 'dst1/$i.txt'));
response = await client.webdav.move(Uri(path: 'src2.txt'), Uri(path: 'dst.txt'), overwrite: true);
expect(response.statusCode, 204);
}
});
final response = await client.webdav.delete(Uri(path: 'dst1/sub'));
expect(response.statusCode, 204);
test('move_coll', () async {
await client.webdav.mkcol(Uri(path: 'src'));
await client.webdav.mkcol(Uri(path: 'src/sub'));
for (var i = 0; i < 10; i++) {
await client.webdav.put(Uint8List(0), Uri(path: 'src/$i.txt'));
}
await client.webdav.put(Uint8List(0), Uri(path: 'noncoll'));
await client.webdav.copy(Uri(path: 'src'), Uri(path: 'dst2'));
await client.webdav.move(Uri(path: 'src'), Uri(path: 'dst1'));
expect(
() => client.webdav.move(Uri(path: 'dst1'), Uri(path: 'dst2')),
throwsA(predicate<DynamiteApiException>((final e) => e.statusCode == 412)),
);
await client.webdav.move(Uri(path: 'dst2'), Uri(path: 'dst1'), overwrite: true);
await client.webdav.copy(Uri(path: 'dst1'), Uri(path: 'dst2'));
for (var i = 0; i < 10; i++) {
final response = await client.webdav.delete(Uri(path: 'dst1/$i.txt'));
expect(response.statusCode, 204);
}
final response = await client.webdav.delete(Uri(path: 'dst1/sub'));
expect(response.statusCode, 204);
expect(
() => client.webdav.move(Uri(path: 'dst2'), Uri(path: 'noncoll')),
throwsA(predicate<DynamiteApiException>((final e) => e.statusCode == 412)),
);
expect(
() => client.webdav.move(Uri(path: 'dst2'), Uri(path: 'noncoll')),
throwsA(predicate<DynamiteApiException>((final e) => e.statusCode == 412)),
);
});
});
});
group('largefile', () {
final largefileSize = pow(10, 9).toInt(); // 1GB
group('largefile', () {
final largefileSize = pow(10, 9).toInt(); // 1GB
// large_put: Already covered by large_get
// large_put: Already covered by large_get
test('large_get', () async {
final response = await client.webdav.put(Uint8List(largefileSize), Uri(path: 'test.txt'));
expect(response.statusCode, 201);
test('large_get', () async {
final response = await client.webdav.put(Uint8List(largefileSize), Uri(path: 'test.txt'));
expect(response.statusCode, 201);
final downloadedContent = await client.webdav.get(Uri(path: 'test.txt'));
expect(downloadedContent, hasLength(largefileSize));
final downloadedContent = await client.webdav.get(Uri(path: 'test.txt'));
expect(downloadedContent, hasLength(largefileSize));
});
});
});
// props: Most of them are either not applicable or hard/impossible to implement because we don't allow just writing any props
});
});
// props: Most of them are either not applicable or hard/impossible to implement because we don't allow just writing any props
});
},
retry: retryCount,
timeout: timeout,
);
}

Loading…
Cancel
Save