From 15bbc392987a2e4c462299a5710bd3999c10f0d0 Mon Sep 17 00:00:00 2001 From: xuty <xty50337@hotmail.com> Date: Wed, 18 Aug 2021 13:26:09 +0000 Subject: [PATCH] Add more tests --- .gitignore | 3 + lib/src/minio.dart | 22 +- lib/src/minio_poller.dart | 5 +- test/helpers.dart | 26 ++ test/minio_dart_test.dart | 263 ------------- test/minio_helpers_test.dart | 34 ++ test/minio_models_test.dart | 19 + test/minio_presigned_url_test.dart | 32 ++ test/minio_stream_test.dart | 30 ++ test/minio_test.dart | 602 +++++++++++++++++++++++++++++ test/utils_test.dart | 59 +++ 11 files changed, 822 insertions(+), 273 deletions(-) create mode 100644 test/helpers.dart delete mode 100644 test/minio_dart_test.dart create mode 100644 test/minio_helpers_test.dart create mode 100644 test/minio_models_test.dart create mode 100644 test/minio_presigned_url_test.dart create mode 100644 test/minio_stream_test.dart create mode 100644 test/minio_test.dart create mode 100644 test/utils_test.dart diff --git a/.gitignore b/.gitignore index 56260f1..c80df3c 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,6 @@ doc/api/ # IDE directories .idea/ + +# For debugging purpose +test/main.dart \ No newline at end of file diff --git a/lib/src/minio.dart b/lib/src/minio.dart index e2afb86..d4732f4 100644 --- a/lib/src/minio.dart +++ b/lib/src/minio.dart @@ -466,11 +466,11 @@ class Minio { }) { MinioInvalidBucketNameError.check(bucket); - final listener = - NotificationPoller(_client, bucket, prefix, suffix, events); - listener.start(); + final poller = NotificationPoller(_client, bucket, prefix, suffix, events); - return listener; + poller.start(); + + return poller; } /// List of buckets created. @@ -878,15 +878,15 @@ class Minio { metadata = prependXAMZMeta(metadata ?? <String, String>{}); size ??= maxObjectSize; - size = _calculatePartSize(size); + final partSize = _calculatePartSize(size); - final chunker = BlockStream(size); + final chunker = BlockStream(partSize); final uploader = MinioUploader( this, _client, bucket, object, - size, + partSize, metadata, ); final etag = await data.transform(chunker).pipe(uploader); @@ -894,8 +894,12 @@ class Minio { } /// Remove all bucket notification - Future<void> removeAllBucketNotification(bucket) => setBucketNotification( - bucket, NotificationConfiguration(null, null, null)); + Future<void> removeAllBucketNotification(String bucket) async { + await setBucketNotification( + bucket, + NotificationConfiguration(null, null, null), + ); + } /// Remove a bucket. Future<void> removeBucket(String bucket) async { diff --git a/lib/src/minio_poller.dart b/lib/src/minio_poller.dart index 1801deb..ee20242 100644 --- a/lib/src/minio_poller.dart +++ b/lib/src/minio_poller.dart @@ -23,6 +23,10 @@ class NotificationPoller { bool _stop = true; + bool get isStarted { + return !_stop; + } + /// Starts the polling. void start() async { _stop = false; @@ -57,7 +61,6 @@ class NotificationPoller { final chunk = utf8.decode(resp); if (chunk.trim().isEmpty) continue; - final data = json.decode(chunk); final records = List<Map<String, dynamic>>.from(data['Records']); await _eventStream.addStream(Stream.fromIterable(records)); diff --git a/test/helpers.dart b/test/helpers.dart new file mode 100644 index 0000000..63ca173 --- /dev/null +++ b/test/helpers.dart @@ -0,0 +1,26 @@ +import 'package:minio/minio.dart'; + +/// Initializes an instance of [Minio] with per default valid configuration. +/// +/// Don't worry, these credentials for MinIO are publicly available and +/// connect only to the MinIO demo server at `play.minio.io`. +Minio getMinioClient({ + String endpoint = 'play.minio.io', + int? port = 443, + bool useSSL = true, + String accessKey = 'Q3AM3UQ867SPQQA43P2F', + String secretKey = 'zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG', + String sessionToken = '', + String region = 'us-east-1', + bool enableTrace = false, +}) => + Minio( + endPoint: endpoint, + port: port, + useSSL: useSSL, + accessKey: accessKey, + secretKey: secretKey, + sessionToken: sessionToken, + region: region, + enableTrace: enableTrace, + ); diff --git a/test/minio_dart_test.dart b/test/minio_dart_test.dart deleted file mode 100644 index cf442c0..0000000 --- a/test/minio_dart_test.dart +++ /dev/null @@ -1,263 +0,0 @@ -import 'dart:io'; - -import 'package:minio/io.dart'; -import 'package:minio/minio.dart'; -import 'package:test/test.dart'; - -void main() { - group('listBuckets', () { - test('listBuckets() succeeds', () async { - final minio = _getClient(); - - expect(() async => await minio.listBuckets(), returnsNormally); - }); - - test('listBuckets() fails due to wrong access key', () async { - final minio = _getClient(accessKey: 'incorrect-access-key'); - - expect( - () async => await minio.listBuckets(), - throwsA( - isA<MinioError>().having( - (e) => e.message, - 'message', - 'The Access Key Id you provided does not exist in our records.', - ), - ), - ); - }); - - test('listBuckets() fails due to wrong secret key', () async { - final minio = _getClient(secretKey: 'incorrect-secret-key'); - - expect( - () async => await minio.listBuckets(), - throwsA( - isA<MinioError>().having( - (e) => e.message, - 'message', - 'The request signature we calculated does not match the signature you provided. Check your key and signing method.', - ), - ), - ); - }); - }); - - group('bucketExists', () { - final bucketName = DateTime.now().millisecondsSinceEpoch.toString(); - - setUpAll(() async { - final minio = _getClient(); - await minio.makeBucket(bucketName); - }); - - tearDownAll(() async { - final minio = _getClient(); - await minio.removeBucket(bucketName); - }); - - test('bucketExists() returns true for an existing bucket', () async { - final minio = _getClient(); - expect(await minio.bucketExists(bucketName), equals(true)); - }); - - test('bucketExists() returns false for a non-existent bucket', () async { - final minio = _getClient(); - expect( - await minio.bucketExists('non-existing-bucket-name'), equals(false)); - }); - - test('bucketExists() fails due to wrong access key', () async { - final minio = _getClient(accessKey: 'incorrect-access-key'); - expect( - () async => await minio.bucketExists(bucketName), - throwsA( - isA<MinioError>().having( - (e) => e.message, - 'message', - 'Forbidden', - ), - ), - ); - }); - - test('bucketExists() fails due to wrong secret key', () async { - final minio = _getClient(secretKey: 'incorrect-secret-key'); - expect( - () async => await minio.bucketExists(bucketName), - throwsA( - isA<MinioError>().having( - (e) => e.message, - 'message', - 'Forbidden', - ), - ), - ); - }); - }); - - group('fPutObject', () { - final bucketName = DateTime.now().millisecondsSinceEpoch.toString(); - late Directory tempDir; - late File testFile; - final objectName = 'a.jpg'; - - setUpAll(() async { - tempDir = await Directory.systemTemp.createTemp(); - testFile = await File('${tempDir.path}/$objectName').create(); - await testFile.writeAsString('random bytes'); - - final minio = _getClient(); - await minio.makeBucket(bucketName); - }); - - tearDownAll(() async { - final minio = _getClient(); - await minio.removeObject(bucketName, objectName); - await tempDir.delete(recursive: true); - }); - - test('fPutObject() inserts content-type to metadata', () async { - final minio = _getClient(); - await minio.fPutObject(bucketName, objectName, testFile.path); - - final stat = await minio.statObject(bucketName, objectName); - expect(stat.metaData!['content-type'], equals('image/jpeg')); - }); - - test('fPutObject() adds user-defined object metadata w/ prefix', () async { - final prefix = 'x-amz-meta-'; - final userDefinedMetadataKey = '${prefix}user-defined-metadata-key-1'; - final userDefinedMetadataValue = 'custom value 1'; - final metadata = { - userDefinedMetadataKey: userDefinedMetadataValue, - }; - - final minio = _getClient(); - await minio.fPutObject(bucketName, objectName, testFile.path, metadata); - - final stat = await minio.statObject(bucketName, objectName); - expect( - stat.metaData![userDefinedMetadataKey.substring(prefix.length)], - equals(userDefinedMetadataValue), - ); - }); - - test('fPutObject() adds user-defined object metadata w/o prefix', () async { - final userDefinedMetadataKey = 'user-defined-metadata-key-2'; - final userDefinedMetadataValue = 'custom value 2'; - final metadata = { - userDefinedMetadataKey: userDefinedMetadataValue, - }; - - final minio = _getClient(); - await minio.fPutObject(bucketName, objectName, testFile.path, metadata); - - final stat = await minio.statObject(bucketName, objectName); - expect(stat.metaData![userDefinedMetadataKey], - equals(userDefinedMetadataValue)); - }); - - test('fPutObject() with empty file', () async { - final objectName = 'empty.txt'; - final emptyFile = await File('${tempDir.path}/$objectName').create(); - await emptyFile.writeAsString(''); - - final minio = _getClient(); - await minio.fPutObject(bucketName, objectName, emptyFile.path); - - final stat = await minio.statObject(bucketName, objectName); - expect(stat.size, equals(0)); - }); - }); - - group( - 'setObjectACL', - () { - late String bucketName; - late Directory tempDir; - File testFile; - final objectName = 'a.jpg'; - - setUpAll(() async { - bucketName = DateTime.now().millisecondsSinceEpoch.toString(); - - tempDir = await Directory.systemTemp.createTemp(); - testFile = await File('${tempDir.path}/$objectName').create(); - await testFile.writeAsString('random bytes'); - - final minio = _getClient(); - await minio.makeBucket(bucketName); - - await minio.fPutObject(bucketName, objectName, testFile.path); - }); - - tearDownAll(() async { - await tempDir.delete(recursive: true); - }); - - test('setObjectACL() set objects acl', () async { - final minio = _getClient(); - await minio.setObjectACL(bucketName, objectName, 'public-read'); - }); - }, - ); - - group( - 'getObjectACL', - () { - late String bucketName; - late Directory tempDir; - File testFile; - final objectName = 'a.jpg'; - - setUpAll(() async { - bucketName = DateTime.now().millisecondsSinceEpoch.toString(); - - tempDir = await Directory.systemTemp.createTemp(); - testFile = await File('${tempDir.path}/$objectName').create(); - await testFile.writeAsString('random bytes'); - - final minio = _getClient(); - await minio.makeBucket(bucketName); - - await minio.fPutObject(bucketName, objectName, testFile.path); - }); - - tearDownAll(() async { - await tempDir.delete(recursive: true); - }); - - test('getObjectACL() fetch objects acl', () async { - final minio = _getClient(); - var acl = await minio.getObjectACL(bucketName, objectName); - expect(acl.grants!.permission, equals(null)); - }); - }, - ); -} - -/// Initializes an instance of [Minio] with per default valid configuration. -/// -/// Don't worry, these credentials for MinIO are publicly available and -/// connect only to the MinIO demo server at `play.minio.io`. -Minio _getClient({ - String endpoint = 'play.minio.io', - int port = 443, - bool useSSL = true, - String accessKey = 'Q3AM3UQ867SPQQA43P2F', - String secretKey = 'zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG', - String sessionToken = '', - String region = 'us-east-1', - bool enableTrace = false, -}) => - Minio( - endPoint: endpoint, - port: port, - useSSL: useSSL, - accessKey: accessKey, - secretKey: secretKey, - sessionToken: sessionToken, - region: region, - enableTrace: enableTrace, - ); diff --git a/test/minio_helpers_test.dart b/test/minio_helpers_test.dart new file mode 100644 index 0000000..a73f55f --- /dev/null +++ b/test/minio_helpers_test.dart @@ -0,0 +1,34 @@ +import 'package:minio/src/minio_helpers.dart'; +import 'package:test/test.dart'; + +void main() { + group('helpers', () { + test('should validate for s3 endpoint', () { + expect(isValidEndpoint('s3.amazonaws.com'), isTrue); + }); + test('should validate for s3 china', () { + expect(isValidEndpoint('s3.cn-north-1.amazonaws.com.cn'), isTrue); + }); + test('should validate for us-west-2', () { + expect(isValidEndpoint('s3-us-west-2.amazonaws.com'), isTrue); + }); + test('should fail for invalid endpoint characters', () { + expect(isValidEndpoint('111.#2.11'), isFalse); + }); + test('should validate for valid ip', () { + expect(isValidIPv4('1.1.1.1'), isTrue); + }); + test('should fail for invalid ip', () { + expect(isValidIPv4('1.1.1'), isFalse); + }); + test('should make date short', () { + final date = DateTime.parse('2012-12-03T17:25:36.331Z'); + expect(makeDateShort(date), '20121203'); + }); + test('should make date long', () { + final date = DateTime.parse('2017-08-11T17:26:34.935Z'); + expect(makeDateLong(date), '20170811T172634Z'); + }); + }); + ; +} diff --git a/test/minio_models_test.dart b/test/minio_models_test.dart new file mode 100644 index 0000000..1e2d07c --- /dev/null +++ b/test/minio_models_test.dart @@ -0,0 +1,19 @@ +import 'package:minio/models.dart'; +import 'package:test/test.dart'; + +void main() { + final date = DateTime.utc(2017, 8, 11, 19, 34, 18); + final dateString = 'Fri, 11 Aug 2017 19:34:18 GMT'; + + test('CopyConditions.setModified() works', () { + final cc = CopyConditions(); + cc.setModified(date); + expect(cc.modified, equals(dateString)); + }); + + test('CopyConditions.setUnmodified() works', () { + final cc = CopyConditions(); + cc.setUnmodified(date); + expect(cc.unmodified, dateString); + }); +} diff --git a/test/minio_presigned_url_test.dart b/test/minio_presigned_url_test.dart new file mode 100644 index 0000000..7821e50 --- /dev/null +++ b/test/minio_presigned_url_test.dart @@ -0,0 +1,32 @@ +import 'package:minio/minio.dart'; +import 'package:test/test.dart'; + +import 'helpers.dart'; + +void main() { + test('Minio.presignedGetObject() works', () async { + final minio = getMinioClient(); + await minio.presignedGetObject('bucket', 'object'); + }); + + test('Minio.presignedGetObject() throws when [expires] < 0', () async { + final minio = getMinioClient(); + expect( + () => minio.presignedGetObject('bucket', 'object', expires: -1), + throwsA(isA<MinioError>()), + ); + }); + + test('Minio.presignedPutObject() works', () async { + final minio = getMinioClient(); + await minio.presignedPutObject('bucket', 'object'); + }); + + test('Minio.presignedPutObject() throws when [expires] < 0', () async { + final minio = getMinioClient(); + expect( + () => minio.presignedPutObject('bucket', 'object', expires: -1), + throwsA(isA<MinioError>()), + ); + }); +} diff --git a/test/minio_stream_test.dart b/test/minio_stream_test.dart new file mode 100644 index 0000000..8c74cd8 --- /dev/null +++ b/test/minio_stream_test.dart @@ -0,0 +1,30 @@ +import 'package:test/test.dart'; + +import 'helpers.dart'; + +void main() { + group('MinioByteStream', () { + final bucketName = DateTime.now().millisecondsSinceEpoch.toString(); + final objectName = 'content-length-test'; + final testData = [1, 2, 3, 4, 5]; + + setUpAll(() async { + final minio = getMinioClient(); + await minio.makeBucket(bucketName); + await minio.putObject(bucketName, objectName, Stream.value(testData)); + }); + + tearDownAll(() async { + final minio = getMinioClient(); + await minio.removeObject(bucketName, objectName); + await minio.removeBucket(bucketName); + }); + + test('contains content length', () async { + final minio = getMinioClient(); + final stream = await minio.getObject(bucketName, objectName); + expect(stream.contentLength, equals(testData.length)); + await stream.drain(); + }); + }); +} diff --git a/test/minio_test.dart b/test/minio_test.dart new file mode 100644 index 0000000..fdf5770 --- /dev/null +++ b/test/minio_test.dart @@ -0,0 +1,602 @@ +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:minio/io.dart'; +import 'package:minio/minio.dart'; +import 'package:minio/src/minio_models_generated.dart'; +import 'package:test/test.dart'; + +import 'helpers.dart'; + +void main() { + // testConstruct(); + // testListBuckets(); + // testBucketExists(); + // testFPutObject(); + // testGetObjectACL(); + // testSetObjectACL(); + // testGetObject(); + // testPutObject(); + // testGetBucketNotification(); + // testSetBucketNotification(); + // testRemoveAllBucketNotification(); + // testListenBucketNotification(); + // testStatObject(); + // testMakeBucket(); + // testRemoveBucket(); + // testRemoveObject(); +} + +void testConstruct() { + test('Minio() implies http port', () { + final client = getMinioClient(port: null, useSSL: false); + expect(client.port, equals(80)); + }); + + test('Minio() implies https port', () { + final client = getMinioClient(port: null, useSSL: true); + expect(client.port, equals(443)); + }); + + test('Minio() overrides port with http', () { + final client = getMinioClient(port: 1234, useSSL: false); + expect(client.port, equals(1234)); + }); + + test('Minio() overrides port with https', () { + final client = getMinioClient(port: 1234, useSSL: true); + expect(client.port, equals(1234)); + }); + + test('Minio() throws when endPoint is url', () { + expect( + () => getMinioClient(endpoint: 'http://play.min.io'), + throwsA(isA<MinioError>()), + ); + }); + + test('Minio() throws when port is invalid', () { + expect( + () => getMinioClient(port: -1), + throwsA(isA<MinioError>()), + ); + + expect( + () => getMinioClient(port: 65536), + throwsA(isA<MinioError>()), + ); + }); +} + +void testListBuckets() { + test('listBuckets() succeeds', () async { + final minio = getMinioClient(); + + expect(() async => await minio.listBuckets(), returnsNormally); + }); + + test('listBuckets() can list buckets', () async { + final minio = getMinioClient(); + final bucketName1 = DateTime.now().millisecondsSinceEpoch.toString(); + await minio.makeBucket(bucketName1); + + final bucketName2 = DateTime.now().millisecondsSinceEpoch.toString(); + await minio.makeBucket(bucketName2); + + final buckets = await minio.listBuckets(); + expect(buckets.any((b) => b.name == bucketName1), isTrue); + expect(buckets.any((b) => b.name == bucketName2), isTrue); + + await minio.removeBucket(bucketName1); + await minio.removeBucket(bucketName2); + }); + + test('listBuckets() fails due to wrong access key', () async { + final minio = getMinioClient(accessKey: 'incorrect-access-key'); + + expect( + () async => await minio.listBuckets(), + throwsA( + isA<MinioError>().having( + (e) => e.message, + 'message', + 'The Access Key Id you provided does not exist in our records.', + ), + ), + ); + }); + + test('listBuckets() fails due to wrong secret key', () async { + final minio = getMinioClient(secretKey: 'incorrect-secret-key'); + + expect( + () async => await minio.listBuckets(), + throwsA( + isA<MinioError>().having( + (e) => e.message, + 'message', + 'The request signature we calculated does not match the signature you provided. Check your key and signing method.', + ), + ), + ); + }); +} + +void testBucketExists() { + group('bucketExists', () { + final bucketName = DateTime.now().millisecondsSinceEpoch.toString(); + + setUpAll(() async { + final minio = getMinioClient(); + await minio.makeBucket(bucketName); + }); + + tearDownAll(() async { + final minio = getMinioClient(); + await minio.removeBucket(bucketName); + }); + + test('bucketExists() returns true for an existing bucket', () async { + final minio = getMinioClient(); + expect(await minio.bucketExists(bucketName), equals(true)); + }); + + test('bucketExists() returns false for a non-existent bucket', () async { + final minio = getMinioClient(); + expect( + await minio.bucketExists('non-existing-bucket-name'), equals(false)); + }); + + test('bucketExists() fails due to wrong access key', () async { + final minio = getMinioClient(accessKey: 'incorrect-access-key'); + expect( + () async => await minio.bucketExists(bucketName), + throwsA( + isA<MinioError>().having( + (e) => e.message, + 'message', + 'Forbidden', + ), + ), + ); + }); + + test('bucketExists() fails due to wrong secret key', () async { + final minio = getMinioClient(secretKey: 'incorrect-secret-key'); + expect( + () async => await minio.bucketExists(bucketName), + throwsA( + isA<MinioError>().having( + (e) => e.message, + 'message', + 'Forbidden', + ), + ), + ); + }); + }); +} + +void testFPutObject() { + group('fPutObject', () { + final bucketName = DateTime.now().millisecondsSinceEpoch.toString(); + late Directory tempDir; + late File testFile; + final objectName = 'a.jpg'; + + setUpAll(() async { + tempDir = await Directory.systemTemp.createTemp(); + testFile = await File('${tempDir.path}/$objectName').create(); + await testFile.writeAsString('random bytes'); + + final minio = getMinioClient(); + await minio.makeBucket(bucketName); + }); + + tearDownAll(() async { + final minio = getMinioClient(); + await minio.removeObject(bucketName, objectName); + await tempDir.delete(recursive: true); + }); + + test('fPutObject() inserts content-type to metadata', () async { + final minio = getMinioClient(); + await minio.fPutObject(bucketName, objectName, testFile.path); + + final stat = await minio.statObject(bucketName, objectName); + expect(stat.metaData!['content-type'], equals('image/jpeg')); + }); + + test('fPutObject() adds user-defined object metadata w/ prefix', () async { + final prefix = 'x-amz-meta-'; + final userDefinedMetadataKey = '${prefix}user-defined-metadata-key-1'; + final userDefinedMetadataValue = 'custom value 1'; + final metadata = { + userDefinedMetadataKey: userDefinedMetadataValue, + }; + + final minio = getMinioClient(); + await minio.fPutObject(bucketName, objectName, testFile.path, metadata); + + final stat = await minio.statObject(bucketName, objectName); + expect( + stat.metaData![userDefinedMetadataKey.substring(prefix.length)], + equals(userDefinedMetadataValue), + ); + }); + + test('fPutObject() adds user-defined object metadata w/o prefix', () async { + final userDefinedMetadataKey = 'user-defined-metadata-key-2'; + final userDefinedMetadataValue = 'custom value 2'; + final metadata = { + userDefinedMetadataKey: userDefinedMetadataValue, + }; + + final minio = getMinioClient(); + await minio.fPutObject(bucketName, objectName, testFile.path, metadata); + + final stat = await minio.statObject(bucketName, objectName); + expect(stat.metaData![userDefinedMetadataKey], + equals(userDefinedMetadataValue)); + }); + + test('fPutObject() with empty file', () async { + final objectName = 'empty.txt'; + final emptyFile = await File('${tempDir.path}/$objectName').create(); + await emptyFile.writeAsString(''); + + final minio = getMinioClient(); + await minio.fPutObject(bucketName, objectName, emptyFile.path); + + final stat = await minio.statObject(bucketName, objectName); + expect(stat.size, equals(0)); + }); + }); +} + +void testSetObjectACL() { + group('setObjectACL', () { + late String bucketName; + late Directory tempDir; + File testFile; + final objectName = 'a.jpg'; + + setUpAll(() async { + bucketName = DateTime.now().millisecondsSinceEpoch.toString(); + + tempDir = await Directory.systemTemp.createTemp(); + testFile = await File('${tempDir.path}/$objectName').create(); + await testFile.writeAsString('random bytes'); + + final minio = getMinioClient(); + await minio.makeBucket(bucketName); + + await minio.fPutObject(bucketName, objectName, testFile.path); + }); + + tearDownAll(() async { + await tempDir.delete(recursive: true); + }); + + test('setObjectACL() set objects acl', () async { + final minio = getMinioClient(); + await minio.setObjectACL(bucketName, objectName, 'public-read'); + }); + }); +} + +void testGetObjectACL() { + group('getObjectACL', () { + late String bucketName; + late Directory tempDir; + File testFile; + final objectName = 'a.jpg'; + + setUpAll(() async { + bucketName = DateTime.now().millisecondsSinceEpoch.toString(); + + tempDir = await Directory.systemTemp.createTemp(); + testFile = await File('${tempDir.path}/$objectName').create(); + await testFile.writeAsString('random bytes'); + + final minio = getMinioClient(); + await minio.makeBucket(bucketName); + + await minio.fPutObject(bucketName, objectName, testFile.path); + }); + + tearDownAll(() async { + await tempDir.delete(recursive: true); + }); + + test('getObjectACL() fetch objects acl', () async { + final minio = getMinioClient(); + var acl = await minio.getObjectACL(bucketName, objectName); + expect(acl.grants!.permission, equals(null)); + }); + }); +} + +void testGetObject() { + group('getObject()', () { + final minio = getMinioClient(); + final bucketName = DateTime.now().millisecondsSinceEpoch.toString(); + final objectName = DateTime.now().microsecondsSinceEpoch.toString(); + final objectData = Uint8List.fromList([1, 2, 3]); + + setUpAll(() async { + await minio.makeBucket(bucketName); + await minio.putObject(bucketName, objectName, Stream.value(objectData)); + }); + + tearDownAll(() async { + await minio.removeObject(bucketName, objectName); + await minio.removeBucket(bucketName); + }); + + test('succeeds', () async { + final stream = await minio.getObject(bucketName, objectName); + final buffer = BytesBuilder(); + await stream.forEach((data) => buffer.add(data)); + expect(stream.contentLength, equals(objectData.length)); + expect(buffer.takeBytes(), equals(objectData)); + }); + + test('fails on invalid bucket', () { + expect( + () async => await minio.getObject('$bucketName-invalid', objectName), + throwsA(isA<MinioError>()), + ); + }); + + test('fails on invalid object', () { + expect( + () async => await minio.getObject(bucketName, '$objectName-invalid'), + throwsA(isA<MinioError>()), + ); + }); + }); +} + +void testPutObject() { + group('putObject()', () { + final minio = getMinioClient(); + final bucketName = DateTime.now().millisecondsSinceEpoch.toString(); + final objectName = DateTime.now().microsecondsSinceEpoch.toString(); + final objectData = Uint8List.fromList([1, 2, 3]); + + setUpAll(() async { + await minio.makeBucket(bucketName); + }); + + tearDownAll(() async { + await minio.removeBucket(bucketName); + }); + + test('succeeds', () async { + await minio.putObject(bucketName, objectName, Stream.value(objectData)); + final stat = await minio.statObject(bucketName, objectName); + expect(stat.size, equals(objectData.length)); + await minio.removeObject(bucketName, objectName); + }); + }); +} + +void testGetBucketNotification() { + group('getBucketNotification()', () { + final minio = getMinioClient(); + final bucketName = DateTime.now().millisecondsSinceEpoch.toString(); + + setUpAll(() async { + await minio.makeBucket(bucketName); + }); + + tearDownAll(() async { + await minio.removeBucket(bucketName); + }); + + test('succeeds', () async { + await minio.getBucketNotification(bucketName); + }); + }); +} + +void testSetBucketNotification() { + group('setBucketNotification()', () { + final minio = getMinioClient(); + final bucketName = DateTime.now().millisecondsSinceEpoch.toString(); + + setUpAll(() async { + await minio.makeBucket(bucketName); + }); + + tearDownAll(() async { + await minio.removeBucket(bucketName); + }); + + test('succeeds', () async { + await minio.setBucketNotification( + bucketName, + NotificationConfiguration(null, null, null), + ); + }); + }); +} + +void testRemoveAllBucketNotification() { + group('removeAllBucketNotification()', () { + final minio = getMinioClient(); + final bucketName = DateTime.now().millisecondsSinceEpoch.toString(); + + setUpAll(() async { + await minio.makeBucket(bucketName); + }); + + tearDownAll(() async { + await minio.removeBucket(bucketName); + }); + + test('succeeds', () async { + await minio.removeAllBucketNotification(bucketName); + }); + }); +} + +void testListenBucketNotification() { + group('listenBucketNotification()', () { + final minio = getMinioClient(); + final bucketName = DateTime.now().millisecondsSinceEpoch.toString(); + // final objectName = DateTime.now().microsecondsSinceEpoch.toString(); + + setUpAll(() async { + await minio.makeBucket(bucketName); + }); + + tearDownAll(() async { + await minio.removeBucket(bucketName); + }); + + test('succeeds', () async { + final poller = minio.listenBucketNotification(bucketName); + expect(poller.isStarted, isTrue); + poller.stop(); + }); + + // test('can receive notification', () async { + // final poller = minio.listenBucketNotification( + // bucketName, + // events: ['s3:ObjectCreated:*'], + // ); + + // final receivedEvents = []; + // poller.stream.listen((event) => receivedEvents.add(event)); + // expect(receivedEvents, isEmpty); + + // await minio.putObject(bucketName, objectName, Stream.value([0])); + // await minio.removeObject(bucketName, objectName); + + // // FIXME: Needs sleep here + // expect(receivedEvents, isNotEmpty); + + // poller.stop(); + // }); + }); +} + +void testStatObject() { + group('statObject()', () { + final minio = getMinioClient(); + final bucketName = DateTime.now().millisecondsSinceEpoch.toString(); + final objectName = DateTime.now().microsecondsSinceEpoch.toString(); + final data = [1, 2, 3, 4, 5]; + + setUpAll(() async { + await minio.makeBucket(bucketName); + await minio.putObject(bucketName, objectName, Stream.value(data)); + }); + + tearDownAll(() async { + await minio.removeObject(bucketName, objectName); + await minio.removeBucket(bucketName); + }); + + test('succeeds', () async { + final stats = await minio.statObject(bucketName, objectName); + expect(stats.lastModified, isNotNull); + expect(stats.lastModified!.isBefore(DateTime.now()), isTrue); + expect(stats.size, isNotNull); + expect(stats.size, equals(data.length)); + }); + + test('fails on invalid bucket', () { + expect( + () async => await minio.statObject('$bucketName-invalid', objectName), + throwsA(isA<MinioError>()), + ); + }); + + test('fails on invalid object', () { + expect( + () async => await minio.statObject(bucketName, '$objectName-invalid'), + throwsA(isA<MinioError>()), + ); + }); + }); +} + +void testMakeBucket() { + group('makeBucket()', () { + final minio = getMinioClient(); + final bucketName = DateTime.now().millisecondsSinceEpoch.toString(); + + setUpAll(() async { + await minio.makeBucket(bucketName); + }); + + tearDownAll(() async { + await minio.removeBucket(bucketName); + }); + + test('succeeds', () async { + final buckets = await minio.listBuckets(); + final bucketNames = buckets.map((b) => b.name).toList(); + expect(bucketNames, contains(bucketName)); + }); + }); +} + +void testRemoveBucket() { + group('removeBucket()', () { + final minio = getMinioClient(); + final bucketName = DateTime.now().millisecondsSinceEpoch.toString(); + + test('succeeds', () async { + await minio.makeBucket(bucketName); + await minio.removeBucket(bucketName); + }); + + test('fails on invalid bucket name', () { + expect( + () async => await minio.removeBucket('$bucketName-invalid'), + throwsA(isA<MinioError>()), + ); + }); + }); +} + +void testRemoveObject() { + group('removeObject()', () { + final minio = getMinioClient(); + final bucketName = DateTime.now().millisecondsSinceEpoch.toString(); + final objectName = DateTime.now().microsecondsSinceEpoch.toString(); + final data = [1, 2, 3, 4, 5]; + + setUpAll(() async { + await minio.makeBucket(bucketName); + }); + + tearDownAll(() async { + await minio.removeBucket(bucketName); + }); + + test('succeeds', () async { + await minio.putObject(bucketName, objectName, Stream.value(data)); + await minio.removeObject(bucketName, objectName); + + await for (var chunk in minio.listObjects(bucketName)) { + expect(chunk.objects.contains(objectName), isFalse); + } + }); + + test('fails on invalid bucket', () { + expect( + () async => await minio.removeObject('$bucketName-invalid', objectName), + throwsA(isA<MinioError>()), + ); + }); + + test('does not throw on invalid object', () async { + await minio.removeObject(bucketName, '$objectName-invalid'); + }); + }); +} diff --git a/test/utils_test.dart b/test/utils_test.dart new file mode 100644 index 0000000..a37d9fe --- /dev/null +++ b/test/utils_test.dart @@ -0,0 +1,59 @@ +import 'package:minio/src/utils.dart'; +import 'package:test/test.dart'; + +void main() { + testRfc7231Time(); + testBlockStream(); +} + +void testRfc7231Time() { + final time = DateTime(2017, 8, 11, 19, 34, 18); + final timeString = 'Fri, 11 Aug 2017 19:34:18'; + + final timeUtc = DateTime.utc(2017, 8, 11, 19, 34, 18); + final timeStringUtc = 'Fri, 11 Aug 2017 19:34:18 GMT'; + + group('parseRfc7231Time', () { + test('works', () { + expect(parseRfc7231Time(timeString), equals(time)); + expect(parseRfc7231Time(timeString).isUtc, isFalse); + }); + + test('works for GMT time', () { + expect(parseRfc7231Time(timeStringUtc), equals(timeUtc)); + expect(parseRfc7231Time(timeStringUtc).isUtc, isTrue); + }); + }); + + group('toRfc7231Time', () { + test('works', () { + expect(toRfc7231Time(time), equals(timeString)); + }); + + test('works for GMT time', () { + expect(toRfc7231Time(timeUtc), equals(timeStringUtc)); + }); + }); +} + +void testBlockStream() { + test('BlockStream can split chunks to blocks', () async { + final streamData = [ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], + [10, 11, 12], + ]; + + final stream = Stream.fromIterable(streamData).transform(BlockStream(5)); + + expect( + await stream.toList(), + equals([ + [1, 2, 3, 4, 5], + [6, 7, 8, 9, 10], + [11, 12] + ]), + ); + }); +} -- GitLab