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:nextcloud/nextcloud.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'helper.dart'; import 'helper.dart';
void main() { void main() {
group('core', () { group(
late DockerImage image; 'core',
setUpAll(() async => image = await getDockerImage()); () {
late DockerImage image;
late DockerContainer container; setUpAll(() async => image = await getDockerImage());
late TestNextcloudClient client;
setUp(() async { late DockerContainer container;
container = await getDockerContainer(image); late TestNextcloudClient client;
client = await getTestClient(container); setUp(() async {
}); container = await getDockerContainer(image);
tearDown(() => container.destroy()); client = await getTestClient(container);
});
test('Is supported from capabilities', () async { tearDown(() => container.destroy());
final (supported, _) = client.core.isSupported((await client.core.ocs.getCapabilities()).ocs.data);
expect(supported, isTrue); 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('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); test('Get status', () async {
expect(status.maintenance, false); final status = await client.core.getStatus();
expect(status.needsDbUpgrade, false); expect(status.installed, true);
expect(status.version, startsWith('$coreSupportedVersion.')); expect(status.maintenance, false);
expect(status.versionstring, startsWith('$coreSupportedVersion.')); expect(status.needsDbUpgrade, false);
expect(status.edition, ''); expect(status.version, startsWith('$coreSupportedVersion.'));
expect(status.productname, 'Nextcloud'); expect(status.versionstring, startsWith('$coreSupportedVersion.'));
expect(status.extendedSupport, false); 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); test('Get capabilities', () async {
expect(capabilities.ocs.data.version.string, startsWith('$coreSupportedVersion.')); final capabilities = await client.core.ocs.getCapabilities();
expect(capabilities.ocs.data.capabilities.commentsCapabilities, isNotNull); expect(capabilities.ocs.data.version.major, coreSupportedVersion);
expect(capabilities.ocs.data.capabilities.davCapabilities, isNotNull); expect(capabilities.ocs.data.version.string, startsWith('$coreSupportedVersion.'));
expect(capabilities.ocs.data.capabilities.filesCapabilities, isNotNull); expect(capabilities.ocs.data.capabilities.commentsCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.filesSharingCapabilities, isNotNull); expect(capabilities.ocs.data.capabilities.davCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.filesTrashbinCapabilities, isNotNull); expect(capabilities.ocs.data.capabilities.filesCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.filesVersionsCapabilities, isNotNull); expect(capabilities.ocs.data.capabilities.filesSharingCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.notesCapabilities, isNotNull); expect(capabilities.ocs.data.capabilities.filesTrashbinCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.notificationsCapabilities, isNotNull); expect(capabilities.ocs.data.capabilities.filesVersionsCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.provisioningApiCapabilities, isNotNull); expect(capabilities.ocs.data.capabilities.notesCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.sharebymailCapabilities, isNotNull); expect(capabilities.ocs.data.capabilities.notificationsCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.themingPublicCapabilities, isNotNull); expect(capabilities.ocs.data.capabilities.provisioningApiCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.userStatusCapabilities, isNotNull); expect(capabilities.ocs.data.capabilities.sharebymailCapabilities, isNotNull);
expect(capabilities.ocs.data.capabilities.weatherStatusCapabilities, 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)); test('Get navigation apps', () async {
expect(navigationApps.ocs.data[0].id, 'dashboard'); final navigationApps = await client.core.navigation.getAppsNavigation();
expect(navigationApps.ocs.data[1].id, 'files'); expect(navigationApps.ocs.data, hasLength(6));
expect(navigationApps.ocs.data[2].id, 'photos'); expect(navigationApps.ocs.data[0].id, 'dashboard');
expect(navigationApps.ocs.data[3].id, 'activity'); expect(navigationApps.ocs.data[1].id, 'files');
expect(navigationApps.ocs.data[4].id, 'notes'); expect(navigationApps.ocs.data[2].id, 'photos');
expect(navigationApps.ocs.data[5].id, 'news'); expect(navigationApps.ocs.data[3].id, 'activity');
}); expect(navigationApps.ocs.data[4].id, 'notes');
expect(navigationApps.ocs.data[5].id, 'news');
test( });
'Autocomplete',
() async { test(
final response = await client.core.autoComplete.$get( 'Autocomplete',
search: '', () async {
itemType: 'call', final response = await client.core.autoComplete.$get(
itemId: 'new', search: '',
shareTypes: [ itemType: 'call',
ShareType.user.index, itemId: 'new',
ShareType.group.index, shareTypes: [
], ShareType.user.index,
); ShareType.group.index,
expect(response.ocs.data, hasLength(3)); ],
);
expect(response.ocs.data[0].id, 'admin'); expect(response.ocs.data, hasLength(3));
expect(response.ocs.data[0].label, 'admin');
expect(response.ocs.data[0].icon, 'icon-user'); expect(response.ocs.data[0].id, 'admin');
expect(response.ocs.data[0].source, 'users'); expect(response.ocs.data[0].label, 'admin');
expect(response.ocs.data[0].status, isEmpty); expect(response.ocs.data[0].icon, 'icon-user');
expect(response.ocs.data[0].subline, ''); expect(response.ocs.data[0].source, 'users');
expect(response.ocs.data[0].shareWithDisplayNameUnique, 'admin@example.com'); expect(response.ocs.data[0].status, isEmpty);
expect(response.ocs.data[0].subline, '');
expect(response.ocs.data[1].id, 'user2'); expect(response.ocs.data[0].shareWithDisplayNameUnique, 'admin@example.com');
expect(response.ocs.data[1].label, 'User Two');
expect(response.ocs.data[1].icon, 'icon-user'); expect(response.ocs.data[1].id, 'user2');
expect(response.ocs.data[1].source, 'users'); expect(response.ocs.data[1].label, 'User Two');
expect(response.ocs.data[1].status, isEmpty); expect(response.ocs.data[1].icon, 'icon-user');
expect(response.ocs.data[1].subline, ''); expect(response.ocs.data[1].source, 'users');
expect(response.ocs.data[1].shareWithDisplayNameUnique, 'user2'); expect(response.ocs.data[1].status, isEmpty);
expect(response.ocs.data[1].subline, '');
expect(response.ocs.data[2].id, 'admin'); expect(response.ocs.data[1].shareWithDisplayNameUnique, 'user2');
expect(response.ocs.data[2].label, 'admin');
expect(response.ocs.data[2].icon, ''); expect(response.ocs.data[2].id, 'admin');
expect(response.ocs.data[2].source, 'groups'); expect(response.ocs.data[2].label, 'admin');
expect(response.ocs.data[2].status, isEmpty); expect(response.ocs.data[2].icon, '');
expect(response.ocs.data[2].subline, ''); expect(response.ocs.data[2].source, 'groups');
expect(response.ocs.data[2].shareWithDisplayNameUnique, ''); expect(response.ocs.data[2].status, isEmpty);
}, expect(response.ocs.data[2].subline, '');
skip: true, // TODO: This test only works on 28+ due to a bug fix with the status 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)),
); );
});
test('Unified search providers', () async { test('Get preview', () async {
final response = await client.core.unifiedSearch.getProviders(); final response = await client.core.preview.getPreview(file: 'Nextcloud.png');
expect(response.ocs.data, hasLength(13)); 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 { test('Unified search', () async {
final response = await client.core.unifiedSearch.search( final response = await client.core.unifiedSearch.search(
providerId: 'settings', providerId: 'settings',
term: 'Personal info', term: 'Personal info',
); );
expect(response.ocs.data.name, 'Settings'); expect(response.ocs.data.name, 'Settings');
expect(response.ocs.data.isPaginated, isFalse); expect(response.ocs.data.isPaginated, isFalse);
expect(response.ocs.data.entries, hasLength(1)); expect(response.ocs.data.entries, hasLength(1));
expect(response.ocs.data.entries.single.thumbnailUrl, isEmpty); expect(response.ocs.data.entries.single.thumbnailUrl, isEmpty);
expect(response.ocs.data.entries.single.title, 'Personal info'); expect(response.ocs.data.entries.single.title, 'Personal info');
expect(response.ocs.data.entries.single.subline, isEmpty); expect(response.ocs.data.entries.single.subline, isEmpty);
expect(response.ocs.data.entries.single.resourceUrl, isNotEmpty); expect(response.ocs.data.entries.single.resourceUrl, isNotEmpty);
expect(response.ocs.data.entries.single.icon, 'icon-settings-dark'); expect(response.ocs.data.entries.single.icon, 'icon-settings-dark');
expect(response.ocs.data.entries.single.rounded, isFalse); expect(response.ocs.data.entries.single.rounded, isFalse);
expect(response.ocs.data.entries.single.attributes, isEmpty); 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:process_run/cmd_run.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
const retryCount = 3;
const timeout = Timeout(Duration(seconds: 30));
class DockerContainer { class DockerContainer {
DockerContainer({ DockerContainer({
required this.id, required this.id,
@ -131,12 +134,18 @@ Future<TestNextcloudClient> getTestClient(
cookieJar: CookieJar(), cookieJar: CookieJar(),
); );
var i = 0;
while (true) { while (true) {
// Test will timeout after 30s
try { try {
await client.core.getStatus(); await client.core.getStatus();
break; 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; return client;

476
packages/nextcloud/test/news_test.dart

@ -1,6 +1,3 @@
@Retry(3)
library news_test;
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
@ -10,265 +7,270 @@ import 'package:test/test.dart';
import 'helper.dart'; import 'helper.dart';
void main() { void main() {
group('news', () { group(
late DockerImage image; 'news',
late HttpServer rssServer; () {
setUpAll(() async { late DockerImage image;
image = await getDockerImage(); late HttpServer rssServer;
rssServer = await getRssServer(); setUpAll(() async {
}); image = await getDockerImage();
tearDownAll(() async => rssServer.close(force: true)); rssServer = await getRssServer();
});
late DockerContainer container; tearDownAll(() async => rssServer.close(force: true));
late TestNextcloudClient client;
setUp(() async { late DockerContainer container;
container = await getDockerContainer(image); late TestNextcloudClient client;
client = await getTestClient(container); setUp(() async {
}); container = await getDockerContainer(image);
tearDown(() => container.destroy()); client = await getTestClient(container);
});
Future<NewsListFeeds> addWikipediaFeed([final int? folderID]) async => client.news.addFeed( tearDown(() => container.destroy());
url: 'http://host.docker.internal:${rssServer.port}/wikipedia.xml',
folderId: folderID, 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',
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 { response = await client.news.listFeeds();
final (supported, _) = await client.news.isSupported(); expect(response.feeds[0].title, 'test1');
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');
});
test('Move feed to folder', () async { test('Move feed to folder', () async {
await client.news.createFolder(name: 'test1'); await client.news.createFolder(name: 'test1');
await addWikipediaFeed(); await addWikipediaFeed();
await client.news.moveFeed( await client.news.moveFeed(
feedId: 1, feedId: 1,
folderId: 1, folderId: 1,
); );
final response = await client.news.listFolders(); final response = await client.news.listFolders();
expect(response.folders, hasLength(1)); expect(response.folders, hasLength(1));
expect(response.folders[0].id, 1); expect(response.folders[0].id, 1);
expect(response.folders[0].name, 'test1'); expect(response.folders[0].name, 'test1');
expect(response.folders[0].opened, true); expect(response.folders[0].opened, true);
expect(response.folders[0].feeds, hasLength(0)); expect(response.folders[0].feeds, hasLength(0));
}); });
test('Mark feed as read', () async { test('Mark feed as read', () async {
final feedsResponse = await addWikipediaFeed(); final feedsResponse = await addWikipediaFeed();
var articlesResponse = await client.news.listArticles(type: NewsListType.unread.index); var articlesResponse = await client.news.listArticles(type: NewsListType.unread.index);
expect(articlesResponse.items.length, greaterThan(0)); expect(articlesResponse.items.length, greaterThan(0));
await client.news.markFeedAsRead( await client.news.markFeedAsRead(
feedId: feedsResponse.feeds[0].id, feedId: feedsResponse.feeds[0].id,
newestItemId: feedsResponse.newestItemId!, newestItemId: feedsResponse.newestItemId!,
); );
articlesResponse = await client.news.listArticles(type: NewsListType.unread.index); articlesResponse = await client.news.listArticles(type: NewsListType.unread.index);
expect(articlesResponse.items, hasLength(0)); expect(articlesResponse.items, hasLength(0));
}); });
test('List articles', () async { test('List articles', () async {
var response = await client.news.listArticles(); var response = await client.news.listArticles();
expect(response.items, hasLength(0)); expect(response.items, hasLength(0));
await addWikipediaFeed(); await addWikipediaFeed();
response = await client.news.listArticles(); response = await client.news.listArticles();
expect(response.items.length, greaterThan(0)); expect(response.items.length, greaterThan(0));
expect(response.items[0].body, isNotNull); expect(response.items[0].body, isNotNull);
expect(response.items[0].feedId, 1); expect(response.items[0].feedId, 1);
expect(response.items[0].unread, true); expect(response.items[0].unread, true);
expect(response.items[0].starred, false); expect(response.items[0].starred, false);
}); });
test('List updated articles', () async { test('List updated articles', () async {
// Testing this is not easy, because we can't depend on an external source to update the feed // 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 // 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. // 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. // 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(); var response = await client.news.listArticles();
final wikipediaArticles = response.items.length; final wikipediaArticles = response.items.length;
expect(wikipediaArticles, greaterThan(0)); expect(wikipediaArticles, greaterThan(0));
await addNasaFeed(); await addNasaFeed();
response = await client.news.listArticles(); response = await client.news.listArticles();
final nasaArticles = response.items.length - wikipediaArticles; final nasaArticles = response.items.length - wikipediaArticles;
expect(nasaArticles, greaterThan(0)); expect(nasaArticles, greaterThan(0));
response = await client.news.listUpdatedArticles( response = await client.news.listUpdatedArticles(
lastModified: response.items[response.items.length - 1 - nasaArticles].lastModified, lastModified: response.items[response.items.length - 1 - nasaArticles].lastModified,
); );
expect(response.items, hasLength(nasaArticles)); expect(response.items, hasLength(nasaArticles));
}); });
test('Mark article as read', () async { test('Mark article as read', () async {
await addWikipediaFeed(); await addWikipediaFeed();
var response = await client.news.listArticles(type: NewsListType.unread.index); var response = await client.news.listArticles(type: NewsListType.unread.index);
final unreadArticles = response.items.length; final unreadArticles = response.items.length;
expect(unreadArticles, greaterThan(0)); expect(unreadArticles, greaterThan(0));
await client.news.markArticleAsRead( await client.news.markArticleAsRead(
itemId: response.items[0].id, itemId: response.items[0].id,
); );
response = await client.news.listArticles(type: NewsListType.unread.index); response = await client.news.listArticles(type: NewsListType.unread.index);
expect(response.items, hasLength(unreadArticles - 1)); expect(response.items, hasLength(unreadArticles - 1));
}); });
test('Mark article as unread', () async { test('Mark article as unread', () async {
await addWikipediaFeed(); await addWikipediaFeed();
var response = await client.news.listArticles(type: NewsListType.unread.index); var response = await client.news.listArticles(type: NewsListType.unread.index);
final readArticle = response.items[0]; final readArticle = response.items[0];
await client.news.markArticleAsRead(itemId: readArticle.id); await client.news.markArticleAsRead(itemId: readArticle.id);
response = await client.news.listArticles(type: NewsListType.unread.index); response = await client.news.listArticles(type: NewsListType.unread.index);
final unreadArticles = response.items.length; final unreadArticles = response.items.length;
expect(unreadArticles, greaterThan(0)); expect(unreadArticles, greaterThan(0));
await client.news.markArticleAsUnread(itemId: readArticle.id); await client.news.markArticleAsUnread(itemId: readArticle.id);
response = await client.news.listArticles(type: NewsListType.unread.index); response = await client.news.listArticles(type: NewsListType.unread.index);
expect(response.items, hasLength(unreadArticles + 1)); expect(response.items, hasLength(unreadArticles + 1));
}); });
test('Star article', () async { test('Star article', () async {
await addWikipediaFeed(); await addWikipediaFeed();
var response = await client.news.listArticles(type: NewsListType.starred.index); var response = await client.news.listArticles(type: NewsListType.starred.index);
final starredArticles = response.items.length; final starredArticles = response.items.length;
expect(starredArticles, 0); expect(starredArticles, 0);
response = await client.news.listArticles(); response = await client.news.listArticles();
await client.news.starArticle( await client.news.starArticle(
itemId: response.items[0].id, itemId: response.items[0].id,
); );
response = await client.news.listArticles(type: NewsListType.starred.index); response = await client.news.listArticles(type: NewsListType.starred.index);
expect(response.items, hasLength(1)); expect(response.items, hasLength(1));
}); });
test('Unstar article', () async { test('Unstar article', () async {
await addWikipediaFeed(); await addWikipediaFeed();
var response = await client.news.listArticles(); var response = await client.news.listArticles();
final item = response.items[0]; final item = response.items[0];
await client.news.starArticle( await client.news.starArticle(
itemId: item.id, itemId: item.id,
); );
response = await client.news.listArticles(type: NewsListType.starred.index); response = await client.news.listArticles(type: NewsListType.starred.index);
expect(response.items, hasLength(1)); expect(response.items, hasLength(1));
await client.news.unstarArticle( await client.news.unstarArticle(
itemId: item.id, itemId: item.id,
); );
response = await client.news.listArticles(type: NewsListType.starred.index); response = await client.news.listArticles(type: NewsListType.starred.index);
expect(response.items, hasLength(0)); expect(response.items, hasLength(0));
}); });
test('Create folder', () async { test('Create folder', () async {
var response = await client.news.listFolders(); var response = await client.news.listFolders();
expect(response.folders, hasLength(0)); expect(response.folders, hasLength(0));
response = await client.news.createFolder(name: 'test1'); response = await client.news.createFolder(name: 'test1');
expect(response.folders, hasLength(1)); expect(response.folders, hasLength(1));
expect(response.folders[0].id, 1); expect(response.folders[0].id, 1);
expect(response.folders[0].name, 'test1'); expect(response.folders[0].name, 'test1');
expect(response.folders[0].opened, true); expect(response.folders[0].opened, true);
expect(response.folders[0].feeds, hasLength(0)); expect(response.folders[0].feeds, hasLength(0));
response = await client.news.listFolders(); response = await client.news.listFolders();
expect(response.folders, hasLength(1)); expect(response.folders, hasLength(1));
expect(response.folders[0].id, 1); expect(response.folders[0].id, 1);
expect(response.folders[0].name, 'test1'); expect(response.folders[0].name, 'test1');
expect(response.folders[0].opened, true); expect(response.folders[0].opened, true);
expect(response.folders[0].feeds, hasLength(0)); expect(response.folders[0].feeds, hasLength(0));
}); });
test('List folders', () async { test('List folders', () async {
var response = await client.news.listFolders(); var response = await client.news.listFolders();
expect(response.folders, hasLength(0)); expect(response.folders, hasLength(0));
await client.news.createFolder(name: 'test1'); await client.news.createFolder(name: 'test1');
await client.news.createFolder(name: 'test2'); await client.news.createFolder(name: 'test2');
response = response = await client.news.listFolders(); response = response = await client.news.listFolders();
expect(response.folders, hasLength(2)); expect(response.folders, hasLength(2));
expect(response.folders[0].id, 1); expect(response.folders[0].id, 1);
expect(response.folders[0].name, 'test1'); expect(response.folders[0].name, 'test1');
expect(response.folders[0].opened, true); expect(response.folders[0].opened, true);
expect(response.folders[0].feeds, hasLength(0)); expect(response.folders[0].feeds, hasLength(0));
expect(response.folders[1].id, 2); expect(response.folders[1].id, 2);
expect(response.folders[1].name, 'test2'); expect(response.folders[1].name, 'test2');
expect(response.folders[1].opened, true); expect(response.folders[1].opened, true);
expect(response.folders[1].feeds, hasLength(0)); expect(response.folders[1].feeds, hasLength(0));
}); });
test('Add feed to folder', () async { test('Add feed to folder', () async {
await client.news.createFolder(name: 'test1'); await client.news.createFolder(name: 'test1');
final response = await addWikipediaFeed(1); final response = await addWikipediaFeed(1);
expect(response.starredCount, null); expect(response.starredCount, null);
expect(response.newestItemId, isNotNull); expect(response.newestItemId, isNotNull);
expect(response.feeds, hasLength(1)); expect(response.feeds, hasLength(1));
expect(response.feeds[0].folderId, 1); expect(response.feeds[0].folderId, 1);
expect(response.feeds[0].url, 'http://host.docker.internal:${rssServer.port}/wikipedia.xml'); expect(response.feeds[0].url, 'http://host.docker.internal:${rssServer.port}/wikipedia.xml');
}); });
test('Mark folder as read', () async { test('Mark folder as read', () async {
final foldersResponse = await client.news.createFolder(name: 'test1'); final foldersResponse = await client.news.createFolder(name: 'test1');
final feedsResponse = await addWikipediaFeed(1); final feedsResponse = await addWikipediaFeed(1);
var articlesResponse = await client.news.listArticles(type: NewsListType.unread.index); var articlesResponse = await client.news.listArticles(type: NewsListType.unread.index);
expect(articlesResponse.items.length, greaterThan(0)); expect(articlesResponse.items.length, greaterThan(0));
await client.news.markFolderAsRead( await client.news.markFolderAsRead(
folderId: foldersResponse.folders[0].id, folderId: foldersResponse.folders[0].id,
newestItemId: feedsResponse.newestItemId!, newestItemId: feedsResponse.newestItemId!,
); );
articlesResponse = await client.news.listArticles(type: NewsListType.unread.index); articlesResponse = await client.news.listArticles(type: NewsListType.unread.index);
expect(articlesResponse.items, hasLength(0)); expect(articlesResponse.items, hasLength(0));
}); });
}); },
retry: retryCount,
timeout: timeout,
);
} }
Future<HttpServer> getRssServer() async { 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:nextcloud/nextcloud.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'helper.dart'; import 'helper.dart';
void main() { void main() {
group('notes', () { group(
late DockerImage image; 'notes',
setUpAll(() async => image = await getDockerImage()); () {
late DockerImage image;
late DockerContainer container; setUpAll(() async => image = await getDockerImage());
late TestNextcloudClient client;
setUp(() async { late DockerContainer container;
container = await getDockerContainer(image); late TestNextcloudClient client;
client = await getTestClient(container); setUp(() async {
}); container = await getDockerContainer(image);
tearDown(() => container.destroy()); client = await getTestClient(container);
});
test('Is supported', () async { tearDown(() => container.destroy());
final (supported, _) = client.notes.isSupported((await client.core.ocs.getCapabilities()).ocs.data);
expect(supported, isTrue); 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', test('Create note favorite', () async {
content: 'b', final response = await client.notes.createNote(
category: 'c', title: 'a',
favorite: 1, content: 'b',
); category: 'c',
expect(response.id, isPositive); favorite: 1,
expect(response.title, 'a'); );
expect(response.content, 'b'); expect(response.id, isPositive);
expect(response.category, 'c'); expect(response.title, 'a');
expect(response.favorite, true); expect(response.content, 'b');
expect(response.readonly, false); expect(response.category, 'c');
expect(response.etag, isNotNull); expect(response.favorite, true);
expect(response.modified, isNotNull); 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', test('Create note not favorite', () async {
content: 'b', final response = await client.notes.createNote(
category: 'c', title: 'a',
); content: 'b',
expect(response.id, isPositive); category: 'c',
expect(response.title, 'a'); );
expect(response.content, 'b'); expect(response.id, isPositive);
expect(response.category, 'c'); expect(response.title, 'a');
expect(response.favorite, false); expect(response.content, 'b');
expect(response.readonly, false); expect(response.category, 'c');
expect(response.etag, isNotNull); expect(response.favorite, false);
expect(response.modified, isNotNull); 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'); test('Get notes', () async {
await client.notes.createNote(title: 'a');
final response = await client.notes.getNotes(); await client.notes.createNote(title: 'b');
expect(response, hasLength(2));
expect(response[0].title, 'a'); final response = await client.notes.getNotes();
expect(response[1].title, 'b'); 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, test('Get note', () async {
); final response = await client.notes.getNote(
expect(response.title, 'a'); 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( test('Update note', () async {
id: id, final id = (await client.notes.createNote(title: 'a')).id;
title: 'b', await client.notes.updateNote(
); id: id,
title: 'b',
final response = await client.notes.getNote(id: id); );
expect(response.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( test('Update note fail changed on server', () async {
id: response.id, final response = await client.notes.createNote(title: 'a');
title: 'b', await client.notes.updateNote(
ifMatch: '"${response.etag}"',
);
expect(
() => client.notes.updateNote(
id: response.id, id: response.id,
title: 'c', title: 'b',
ifMatch: '"${response.etag}"', ifMatch: '"${response.etag}"',
), );
throwsA(predicate((final e) => (e! as DynamiteApiException).statusCode == 412)), expect(
); () => client.notes.updateNote(
}); id: response.id,
title: 'c',
test('Delete note', () async { ifMatch: '"${response.etag}"',
final id = (await client.notes.createNote(title: 'a')).id; ),
throwsA(predicate((final e) => (e! as DynamiteApiException).statusCode == 412)),
var response = await client.notes.getNotes(); );
expect(response, hasLength(1)); });
await client.notes.deleteNote(id: id); test('Delete note', () async {
final id = (await client.notes.createNote(title: 'a')).id;
response = await client.notes.getNotes();
expect(response, hasLength(0)); var response = await client.notes.getNotes();
}); expect(response, hasLength(1));
test('Get settings', () async { await client.notes.deleteNote(id: id);
final response = await client.notes.getSettings();
expect(response.notesPath, 'Notes'); response = await client.notes.getNotes();
expect(response.fileSuffix, '.md'); expect(response, hasLength(0));
expect(response.noteMode, NotesSettings_NoteMode.rich); });
});
test('Get settings', () async {
test('Update settings', () async { final response = await client.notes.getSettings();
var response = await client.notes.updateSettings( expect(response.notesPath, 'Notes');
settings: NotesSettings( expect(response.fileSuffix, '.md');
(final b) => b expect(response.noteMode, NotesSettings_NoteMode.rich);
..notesPath = 'Test Notes' });
..fileSuffix = '.txt'
..noteMode = NotesSettings_NoteMode.preview, test('Update settings', () async {
), var response = await client.notes.updateSettings(
); settings: NotesSettings(
expect(response.notesPath, 'Test Notes'); (final b) => b
expect(response.fileSuffix, '.txt'); ..notesPath = 'Test Notes'
expect(response.noteMode, NotesSettings_NoteMode.preview); ..fileSuffix = '.txt'
..noteMode = NotesSettings_NoteMode.preview,
response = await client.notes.getSettings(); ),
expect(response.notesPath, 'Test Notes'); );
expect(response.fileSuffix, '.txt'); expect(response.notesPath, 'Test Notes');
expect(response.noteMode, NotesSettings_NoteMode.preview); 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 'dart:async';
import 'package:nextcloud/nextcloud.dart'; import 'package:nextcloud/nextcloud.dart';
@ -99,43 +96,48 @@ void main() {
}); });
}); });
group('push notifications', () { group(
late DockerImage image; 'push notifications',
setUpAll(() async => image = await getDockerImage()); () {
late DockerImage image;
late DockerContainer container; setUpAll(() async => image = await getDockerImage());
late TestNextcloudClient client;
setUp(() async { late DockerContainer container;
container = await getDockerContainer(image); late TestNextcloudClient client;
client = await getTestClient( setUp(() async {
container, container = await getDockerContainer(image);
username: 'admin', 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) tearDown(() => container.destroy());
// ignore: avoid_redundant_argument_values
RSAKeypair generateKeypair() => RSAKeypair.fromRandom(keySize: 2048); // The key size has to be 2048, other sizes are not accepted by Nextcloud (at the moment at least)
// ignore: avoid_redundant_argument_values
test('Register and remove push device', () async { RSAKeypair generateKeypair() => RSAKeypair.fromRandom(keySize: 2048);
const pushToken = '789';
final keypair = generateKeypair(); test('Register and remove push device', () async {
const pushToken = '789';
final subscription = (await client.notifications.registerDevice( final keypair = generateKeypair();
pushTokenHash: generatePushTokenHash(pushToken),
devicePublicKey: keypair.publicKey.toFormattedPEM(), final subscription = (await client.notifications.registerDevice(
proxyServer: 'https://example.com/', pushTokenHash: generatePushTokenHash(pushToken),
)) devicePublicKey: keypair.publicKey.toFormattedPEM(),
.ocs proxyServer: 'https://example.com/',
.data; ))
expect(subscription.publicKey, hasLength(451)); .ocs
RSAPublicKey.fromPEM(subscription.publicKey); .data;
expect(subscription.deviceIdentifier, isNotEmpty); expect(subscription.publicKey, hasLength(451));
expect(subscription.signature, isNotEmpty); RSAPublicKey.fromPEM(subscription.publicKey);
expect(subscription.message, isNull); expect(subscription.deviceIdentifier, isNotEmpty);
expect(subscription.signature, isNotEmpty);
await client.notifications.removeDevice(); 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 'package:test/test.dart';
import 'helper.dart'; import 'helper.dart';
void main() { void main() {
group('provisioning_api', () { group(
late DockerImage image; 'provisioning_api',
setUpAll(() async => image = await getDockerImage()); () {
late DockerImage image;
late DockerContainer container; setUpAll(() async => image = await getDockerImage());
late TestNextcloudClient client;
setUp(() async { late DockerContainer container;
container = await getDockerContainer(image); late TestNextcloudClient client;
client = await getTestClient( setUp(() async {
container, container = await getDockerContainer(image);
username: 'admin', 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');
}); });
tearDown(() => container.destroy());
test('Get user by username', () async {
final user = await client.provisioningApi.users.getUser(userId: 'user1'); group('Users', () {
expect(user.ocs.data.id, 'user1'); test('Get current user', () async {
expect(user.ocs.data.displayname, 'User One'); final user = await client.provisioningApi.users.getCurrentUser();
expect(user.ocs.data.displaynameScope, null); expect(user.ocs.data.id, 'admin');
expect(user.ocs.data.language, 'en'); 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', () { group('Apps', () {
test('Get apps', () async { test('Get apps', () async {
final response = await client.provisioningApi.apps.getApps(); final response = await client.provisioningApi.apps.getApps();
expect(response.ocs.data.apps, hasLength(39)); expect(response.ocs.data.apps, hasLength(39));
for (final id in response.ocs.data.apps) { for (final id in response.ocs.data.apps) {
final app = await client.provisioningApi.apps.getAppInfo(app: id); final app = await client.provisioningApi.apps.getAppInfo(app: id);
expect(app.ocs.data.id, isNotEmpty); 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 'package:test/test.dart';
import 'helper.dart'; import 'helper.dart';
void main() { void main() {
group('uppush', () { group(
late DockerImage image; 'uppush',
setUpAll(() async => image = await getDockerImage()); () {
late DockerImage image;
setUpAll(() async => image = await getDockerImage());
late DockerContainer container; late DockerContainer container;
late TestNextcloudClient client; late TestNextcloudClient client;
setUp(() async { setUp(() async {
container = await getDockerContainer(image); container = await getDockerContainer(image);
client = await getTestClient( client = await getTestClient(
container, container,
username: 'admin', username: 'admin',
); );
}); });
tearDown(() => container.destroy()); tearDown(() => container.destroy());
test('Is installed', () async { test('Is installed', () async {
final response = await client.uppush.check(); final response = await client.uppush.check();
expect(response.success, isTrue); expect(response.success, isTrue);
}); });
test('Set keepalive', () async { test('Set keepalive', () async {
final response = await client.uppush.setKeepalive(keepalive: 10); final response = await client.uppush.setKeepalive(keepalive: 10);
expect(response.success, isTrue); expect(response.success, isTrue);
}); });
test('Create device', () async { test('Create device', () async {
final response = await client.uppush.createDevice(deviceName: 'Test'); final response = await client.uppush.createDevice(deviceName: 'Test');
expect(response.success, isTrue); expect(response.success, isTrue);
expect(response.deviceId, isNotEmpty); expect(response.deviceId, isNotEmpty);
}); });
test('Delete device', () async { test('Delete device', () async {
final deviceId = (await client.uppush.createDevice(deviceName: 'Test')).deviceId; final deviceId = (await client.uppush.createDevice(deviceName: 'Test')).deviceId;
final response = await client.uppush.deleteDevice(deviceId: deviceId); final response = await client.uppush.deleteDevice(deviceId: deviceId);
expect(response.success, isTrue); expect(response.success, isTrue);
}); });
test('Create app', () async { test('Create app', () async {
final deviceId = (await client.uppush.createDevice(deviceName: 'Test')).deviceId; final deviceId = (await client.uppush.createDevice(deviceName: 'Test')).deviceId;
final response = await client.uppush.createApp(deviceId: deviceId, appName: 'Test'); final response = await client.uppush.createApp(deviceId: deviceId, appName: 'Test');
expect(response.success, isTrue); expect(response.success, isTrue);
expect(response.token, isNotEmpty); expect(response.token, isNotEmpty);
}); });
test('UnifiedPush discovery', () async { test('UnifiedPush discovery', () async {
final response = await client.uppush.unifiedpushDiscovery(token: 'example'); final response = await client.uppush.unifiedpushDiscovery(token: 'example');
expect(response.unifiedpush.version, 1); expect(response.unifiedpush.version, 1);
}); });
test('Matrix gateway discovery', () async { test('Matrix gateway discovery', () async {
final response = await client.uppush.gatewayMatrixDiscovery(); final response = await client.uppush.gatewayMatrixDiscovery();
expect(response.unifiedpush.gateway, 'matrix'); 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:nextcloud/nextcloud.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'helper.dart'; import 'helper.dart';
void main() { void main() {
group('user_status', () { group(
late DockerImage image; 'user_status',
setUpAll(() async => image = await getDockerImage()); () {
late DockerImage image;
late DockerContainer container; setUpAll(() async => image = await getDockerImage());
late TestNextcloudClient client;
setUp(() async { late DockerContainer container;
container = await getDockerContainer(image); late TestNextcloudClient client;
client = await getTestClient(container); setUp(() async {
}); container = await getDockerContainer(image);
tearDown(() => container.destroy()); client = await getTestClient(container);
});
test('Find all predefined statuses', () async { tearDown(() => container.destroy());
final expectedStatusIDs = ['meeting', 'commuting', 'remote-work', 'sick-leave', 'vacationing'];
final response = await client.userStatus.predefinedStatus.findAll(); test('Find all predefined statuses', () async {
expect(response.ocs.data, hasLength(5)); final expectedStatusIDs = ['meeting', 'commuting', 'remote-work', 'sick-leave', 'vacationing'];
final responseIDs = response.ocs.data.map((final status) => status.id); final response = await client.userStatus.predefinedStatus.findAll();
expect(expectedStatusIDs.map(responseIDs.contains).contains(false), false); expect(response.ocs.data, hasLength(5));
for (final status in response.ocs.data) { final responseIDs = response.ocs.data.map((final status) => status.id);
expect(status.icon, isNotNull); expect(expectedStatusIDs.map(responseIDs.contains).contains(false), false);
expect(status.message, isNotNull); 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 meeting = response.ocs.data.singleWhere((final s) => s.id == 'meeting').clearAt!;
expect(meeting.type, UserStatusClearAt_Type.period);
final commuting = response.ocs.data.singleWhere((final s) => s.id == 'commuting').clearAt!; expect(meeting.time.$int, 3600);
expect(commuting.type, UserStatusClearAt_Type.period);
expect(commuting.time.$int, 1800); final commuting = response.ocs.data.singleWhere((final s) => s.id == 'commuting').clearAt!;
expect(commuting.type, UserStatusClearAt_Type.period);
final remoteWork = response.ocs.data.singleWhere((final s) => s.id == 'remote-work').clearAt!; expect(commuting.time.$int, 1800);
expect(remoteWork.type, UserStatusClearAt_Type.endOf);
expect(remoteWork.time.clearAtTimeType, UserStatusClearAtTimeType.day); final remoteWork = response.ocs.data.singleWhere((final s) => s.id == 'remote-work').clearAt!;
expect(remoteWork.type, UserStatusClearAt_Type.endOf);
final sickLeave = response.ocs.data.singleWhere((final s) => s.id == 'sick-leave').clearAt!; expect(remoteWork.time.clearAtTimeType, UserStatusClearAtTimeType.day);
expect(sickLeave.type, UserStatusClearAt_Type.endOf);
expect(sickLeave.time.clearAtTimeType, UserStatusClearAtTimeType.day); final sickLeave = response.ocs.data.singleWhere((final s) => s.id == 'sick-leave').clearAt!;
expect(sickLeave.type, UserStatusClearAt_Type.endOf);
final vacationing = response.ocs.data.singleWhere((final s) => s.id == 'vacationing').clearAt; expect(sickLeave.time.clearAtTimeType, UserStatusClearAtTimeType.day);
expect(vacationing, null);
}); 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');
test('Set status', () async {
expect(response.ocs.data.public.userId, 'user1'); final response = await client.userStatus.userStatus.setStatus(statusType: 'online');
expect(response.ocs.data.public.message, null);
expect(response.ocs.data.private1.messageId, null); expect(response.ocs.data.public.userId, 'user1');
expect(response.ocs.data.private1.messageIsPredefined, false); expect(response.ocs.data.public.message, null);
expect(response.ocs.data.public.icon, null); expect(response.ocs.data.private1.messageId, null);
expect(response.ocs.data.public.clearAt, null); expect(response.ocs.data.private1.messageIsPredefined, false);
expect(response.ocs.data.public.status, 'online'); expect(response.ocs.data.public.icon, null);
expect(response.ocs.data.private1.statusIsUserDefined, true); 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" test('Get status', () async {
await client.userStatus.userStatus.setStatus(statusType: 'online'); // 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"
final response = await client.userStatus.userStatus.getStatus(); await client.userStatus.userStatus.setStatus(statusType: 'online');
expect(response.ocs.data.public.userId, 'user1');
expect(response.ocs.data.public.message, null); final response = await client.userStatus.userStatus.getStatus();
expect(response.ocs.data.private1.messageId, null); expect(response.ocs.data.public.userId, 'user1');
expect(response.ocs.data.private1.messageIsPredefined, false); expect(response.ocs.data.public.message, null);
expect(response.ocs.data.public.icon, null); expect(response.ocs.data.private1.messageId, null);
expect(response.ocs.data.public.clearAt, null); expect(response.ocs.data.private1.messageIsPredefined, false);
expect(response.ocs.data.public.status, 'online'); expect(response.ocs.data.public.icon, null);
expect(response.ocs.data.private1.statusIsUserDefined, true); 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)); test('Find all statuses', () async {
var response = await client.userStatus.statuses.findAll();
await client.userStatus.userStatus.setStatus(statusType: 'online'); expect(response.ocs.data, hasLength(0));
response = await client.userStatus.statuses.findAll(); await client.userStatus.userStatus.setStatus(statusType: 'online');
expect(response.ocs.data, hasLength(1));
expect(response.ocs.data[0].userId, 'user1'); response = await client.userStatus.statuses.findAll();
expect(response.ocs.data[0].message, null); expect(response.ocs.data, hasLength(1));
expect(response.ocs.data[0].icon, null); expect(response.ocs.data[0].userId, 'user1');
expect(response.ocs.data[0].clearAt, null); expect(response.ocs.data[0].message, null);
expect(response.ocs.data[0].status, 'online'); 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'); test('Find status', () async {
// Same as getting status
final response = await client.userStatus.statuses.find(userId: 'user1'); await client.userStatus.userStatus.setStatus(statusType: 'online');
expect(response.ocs.data.userId, 'user1');
expect(response.ocs.data.message, null); final response = await client.userStatus.statuses.find(userId: 'user1');
expect(response.ocs.data.icon, null); expect(response.ocs.data.userId, 'user1');
expect(response.ocs.data.clearAt, null); expect(response.ocs.data.message, null);
expect(response.ocs.data.status, 'online'); 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( test('Set predefined message', () async {
messageId: 'meeting', final clearAt = DateTime.now().millisecondsSinceEpoch ~/ 1000 + 60;
clearAt: clearAt, final response = await client.userStatus.userStatus.setPredefinedMessage(
); messageId: 'meeting',
expect(response.ocs.data.public.userId, 'user1'); clearAt: clearAt,
expect(response.ocs.data.public.message, null); );
expect(response.ocs.data.private1.messageId, 'meeting'); expect(response.ocs.data.public.userId, 'user1');
expect(response.ocs.data.private1.messageIsPredefined, true); expect(response.ocs.data.public.message, null);
expect(response.ocs.data.public.icon, null); expect(response.ocs.data.private1.messageId, 'meeting');
expect(response.ocs.data.public.clearAt, clearAt); expect(response.ocs.data.private1.messageIsPredefined, true);
expect(response.ocs.data.public.status, 'offline'); expect(response.ocs.data.public.icon, null);
expect(response.ocs.data.private1.statusIsUserDefined, false); 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( test('Set custom message', () async {
statusIcon: '😀', final clearAt = DateTime.now().millisecondsSinceEpoch ~/ 1000 + 60;
message: 'bla', final response = await client.userStatus.userStatus.setCustomMessage(
clearAt: clearAt, statusIcon: '😀',
); message: 'bla',
expect(response.ocs.data.public.userId, 'user1'); clearAt: clearAt,
expect(response.ocs.data.public.message, 'bla'); );
expect(response.ocs.data.private1.messageId, null); expect(response.ocs.data.public.userId, 'user1');
expect(response.ocs.data.private1.messageIsPredefined, false); expect(response.ocs.data.public.message, 'bla');
expect(response.ocs.data.public.icon, '😀'); expect(response.ocs.data.private1.messageId, null);
expect(response.ocs.data.public.clearAt, clearAt); expect(response.ocs.data.private1.messageIsPredefined, false);
expect(response.ocs.data.public.status, 'offline'); expect(response.ocs.data.public.icon, '😀');
expect(response.ocs.data.private1.statusIsUserDefined, false); 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( test('Clear message', () async {
statusIcon: '😀', final clearAt = DateTime.now().millisecondsSinceEpoch ~/ 1000 + 60;
message: 'bla', await client.userStatus.userStatus.setCustomMessage(
clearAt: clearAt, statusIcon: '😀',
); message: 'bla',
await client.userStatus.userStatus.clearMessage(); clearAt: clearAt,
);
final response = await client.userStatus.userStatus.getStatus(); await client.userStatus.userStatus.clearMessage();
expect(response.ocs.data.public.userId, 'user1');
expect(response.ocs.data.public.message, null); final response = await client.userStatus.userStatus.getStatus();
expect(response.ocs.data.private1.messageId, null); expect(response.ocs.data.public.userId, 'user1');
expect(response.ocs.data.private1.messageIsPredefined, false); expect(response.ocs.data.public.message, null);
expect(response.ocs.data.public.icon, null); expect(response.ocs.data.private1.messageId, null);
expect(response.ocs.data.public.clearAt, null); expect(response.ocs.data.private1.messageIsPredefined, false);
expect(response.ocs.data.public.status, 'offline'); expect(response.ocs.data.public.icon, null);
expect(response.ocs.data.private1.statusIsUserDefined, false); 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'); test('Heartbeat', () async {
expect(response.ocs.data.public.message, null); final response = await client.userStatus.heartbeat.heartbeat(status: 'online');
expect(response.ocs.data.private1.messageId, null); expect(response.ocs.data.public.userId, 'user1');
expect(response.ocs.data.private1.messageIsPredefined, false); expect(response.ocs.data.public.message, null);
expect(response.ocs.data.public.icon, null); expect(response.ocs.data.private1.messageId, null);
expect(response.ocs.data.public.clearAt, null); expect(response.ocs.data.private1.messageIsPredefined, false);
expect(response.ocs.data.public.status, 'online'); expect(response.ocs.data.public.icon, null);
expect(response.ocs.data.private1.statusIsUserDefined, false); 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:convert';
import 'dart:io'; import 'dart:io';
import 'dart:math'; import 'dart:math';
@ -26,508 +23,514 @@ void main() {
expect(() => WebDavClient.constructUri(baseURL), throwsA(isA<AssertionError>())); expect(() => WebDavClient.constructUri(baseURL), throwsA(isA<AssertionError>()));
}); });
group('webdav', () { group(
late DockerImage image; 'webdav',
setUpAll(() async => image = await getDockerImage()); () {
late DockerImage image;
late DockerContainer container; setUpAll(() async => image = await getDockerImage());
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')));
});
for (final (name, path) in [ late DockerContainer container;
('put_get', 'res'), late TestNextcloudClient client;
('put_get_utf8_segment', 'res-%e2%82%ac'),
]) {
test(name, () async {
final content = utf8.encode('This is a test file') as Uint8List;
final response = await client.webdav.put(content, Uri(path: path)); setUp(() async {
expect(response.statusCode, 201); 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)); test('List directory recursively', () async {
expect(downloadedContent, equals(content)); final responses = (await client.webdav.propfind(
}); Uri(path: '/'),
} depth: WebDavDepth.infinity,
))
test('put_no_parent', () async { .responses;
expect( expect(responses, hasLength(48));
() => 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('delete', () async { test('Get file props', () async {
await client.webdav.put(Uint8List(0), Uri(path: 'test.txt')); 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')); test('Get directory props', () async {
expect(response.statusCode, 204); 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 { test('Filter files', () async {
expect( final response = await client.webdav.put(utf8.encode('test') as Uint8List, Uri(path: 'test.txt'));
() => client.webdav.delete(Uri(path: 'test.txt')), final id = response.headers['oc-fileid']!.first;
throwsA(predicate<DynamiteApiException>((final e) => e.statusCode == 404)), 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 { test('Remove properties', () async {
final response = await client.webdav.mkcol(Uri(path: 'test')); await client.webdav.put(utf8.encode('test') as Uint8List, Uri(path: 'test.txt'));
expect(response.statusCode, 201);
}); 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 { test('Upload and download file', () async {
await client.webdav.mkcol(Uri(path: 'test')); 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( group('litmus', () {
() => client.webdav.mkcol(Uri(path: 'test')), group('basic', () {
throwsA(predicate<DynamiteApiException>((final e) => e.statusCode == 405)), 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 { for (final (name, path) in [
var response = await client.webdav.mkcol(Uri(path: 'test')); ('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')); final response = await client.webdav.put(content, Uri(path: path));
expect(response.statusCode, 204); expect(response.statusCode, 201);
});
test('mkcol_no_parent', () async { final downloadedContent = await client.webdav.get(Uri(path: path));
expect( expect(downloadedContent, equals(content));
() => client.webdav.mkcol(Uri(path: '409me/noparent')), });
throwsA(predicate<DynamiteApiException>((final e) => e.statusCode == 409)), }
);
});
// 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('delete', () async {
test('copy_simple', () async { await client.webdav.put(Uint8List(0), Uri(path: 'test.txt'));
await client.webdav.mkcol(Uri(path: 'src'));
final response = await client.webdav.copy(Uri(path: 'src'), Uri(path: 'dst')); final response = await client.webdav.delete(Uri(path: 'test.txt'));
expect(response.statusCode, 201); 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 { // delete_fragment: This test is not applicable because the fragment is already removed on the client side
await client.webdav.mkcol(Uri(path: 'src'));
await client.webdav.mkcol(Uri(path: 'dst'));
expect( test('mkcol', () async {
() => client.webdav.copy(Uri(path: 'src'), Uri(path: 'dst')), final response = await client.webdav.mkcol(Uri(path: 'test'));
throwsA(predicate<DynamiteApiException>((final e) => e.statusCode == 412)), expect(response.statusCode, 201);
); });
final response = await client.webdav.copy(Uri(path: 'src'), Uri(path: 'dst'), overwrite: true); test('mkcol_again', () async {
expect(response.statusCode, 204); await client.webdav.mkcol(Uri(path: 'test'));
});
test('copy_nodestcoll', () async { expect(
await client.webdav.mkcol(Uri(path: 'src')); () => 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( // mkcol_with_body: This test is not applicable because we only write valid request bodies
() => client.webdav.copy(Uri(path: 'src'), Uri(path: 'nonesuch/dst')),
throwsA(predicate<DynamiteApiException>((final e) => e.statusCode == 409)),
);
}); });
test('copy_coll', () async { group('copymove', () {
await client.webdav.mkcol(Uri(path: 'src')); test('copy_simple', () async {
await client.webdav.mkcol(Uri(path: 'src/sub')); await client.webdav.mkcol(Uri(path: 'src'));
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( final response = await client.webdav.copy(Uri(path: 'src'), Uri(path: 'dst'));
() => client.webdav.copy(Uri(path: 'src'), Uri(path: 'dst1')), expect(response.statusCode, 201);
throwsA(predicate<DynamiteApiException>((final e) => e.statusCode == 412)), });
);
var response = await client.webdav.copy(Uri(path: 'src'), Uri(path: 'dst2'), overwrite: true); test('copy_overwrite', () async {
expect(response.statusCode, 204); await client.webdav.mkcol(Uri(path: 'src'));
await client.webdav.mkcol(Uri(path: 'dst'));
for (var i = 0; i < 10; i++) { expect(
response = await client.webdav.delete(Uri(path: 'dst1/$i.txt')); () => 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); expect(response.statusCode, 204);
} });
response = await client.webdav.delete(Uri(path: 'dst1/sub')); test('copy_nodestcoll', () async {
expect(response.statusCode, 204); await client.webdav.mkcol(Uri(path: 'src'));
response = await client.webdav.delete(Uri(path: 'dst2')); expect(
expect(response.statusCode, 204); () => 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 { for (var i = 0; i < 10; i++) {
await client.webdav.put(Uint8List(0), Uri(path: 'src1.txt')); response = await client.webdav.delete(Uri(path: 'dst1/$i.txt'));
await client.webdav.put(Uint8List(0), Uri(path: 'src2.txt')); expect(response.statusCode, 204);
await client.webdav.mkcol(Uri(path: 'coll')); }
var response = await client.webdav.move(Uri(path: 'src1.txt'), Uri(path: 'dst.txt')); response = await client.webdav.delete(Uri(path: 'dst1/sub'));
expect(response.statusCode, 201); expect(response.statusCode, 204);
expect( response = await client.webdav.delete(Uri(path: 'dst2'));
() => client.webdav.move(Uri(path: 'src2.txt'), Uri(path: 'dst.txt')), expect(response.statusCode, 204);
throwsA(predicate<DynamiteApiException>((final e) => e.statusCode == 412)), });
);
response = await client.webdav.move(Uri(path: 'src2.txt'), Uri(path: 'dst.txt'), overwrite: true); // copy_shallow: Does not work on litmus, let's wait for https://github.com/nextcloud/server/issues/39627
expect(response.statusCode, 204);
});
test('move_coll', () async { test('move', () async {
await client.webdav.mkcol(Uri(path: 'src')); await client.webdav.put(Uint8List(0), Uri(path: 'src1.txt'));
await client.webdav.mkcol(Uri(path: 'src/sub')); await client.webdav.put(Uint8List(0), Uri(path: 'src2.txt'));
for (var i = 0; i < 10; i++) { await client.webdav.mkcol(Uri(path: 'coll'));
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( var response = await client.webdav.move(Uri(path: 'src1.txt'), Uri(path: 'dst.txt'));
() => client.webdav.move(Uri(path: 'dst1'), Uri(path: 'dst2')), expect(response.statusCode, 201);
throwsA(predicate<DynamiteApiException>((final e) => e.statusCode == 412)),
);
await client.webdav.move(Uri(path: 'dst2'), Uri(path: 'dst1'), overwrite: true); expect(
await client.webdav.copy(Uri(path: 'dst1'), Uri(path: 'dst2')); () => 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++) { response = await client.webdav.move(Uri(path: 'src2.txt'), Uri(path: 'dst.txt'), overwrite: true);
final response = await client.webdav.delete(Uri(path: 'dst1/$i.txt'));
expect(response.statusCode, 204); expect(response.statusCode, 204);
} });
final response = await client.webdav.delete(Uri(path: 'dst1/sub')); test('move_coll', () async {
expect(response.statusCode, 204); 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( expect(
() => client.webdav.move(Uri(path: 'dst2'), Uri(path: 'noncoll')), () => client.webdav.move(Uri(path: 'dst2'), Uri(path: 'noncoll')),
throwsA(predicate<DynamiteApiException>((final e) => e.statusCode == 412)), throwsA(predicate<DynamiteApiException>((final e) => e.statusCode == 412)),
); );
});
}); });
});
group('largefile', () { group('largefile', () {
final largefileSize = pow(10, 9).toInt(); // 1GB 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 { test('large_get', () async {
final response = await client.webdav.put(Uint8List(largefileSize), Uri(path: 'test.txt')); final response = await client.webdav.put(Uint8List(largefileSize), Uri(path: 'test.txt'));
expect(response.statusCode, 201); expect(response.statusCode, 201);
final downloadedContent = await client.webdav.get(Uri(path: 'test.txt')); final downloadedContent = await client.webdav.get(Uri(path: 'test.txt'));
expect(downloadedContent, hasLength(largefileSize)); 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