diff --git a/Minio.Examples/Cases/ListenNotifications.cs b/Minio.Examples/Cases/ListenNotifications.cs index 1470338e6..a023e8d6c 100644 --- a/Minio.Examples/Cases/ListenNotifications.cs +++ b/Minio.Examples/Cases/ListenNotifications.cs @@ -32,7 +32,7 @@ public static void Run(IMinioClient minio, Console.WriteLine(); events ??= new List { EventType.BucketCreatedAll }; var args = new ListenBucketNotificationsArgs().WithEvents(events); - var observable = minio.ListenNotificationsAsync(events); + var observable = minio.ListenNotifications(args); subscription = observable.Subscribe( notification => Console.WriteLine($"Notification: {notification.Json}"), diff --git a/Minio.Functional.Tests/FunctionalTest.cs b/Minio.Functional.Tests/FunctionalTest.cs index c5eed42ae..84f02cb53 100644 --- a/Minio.Functional.Tests/FunctionalTest.cs +++ b/Minio.Functional.Tests/FunctionalTest.cs @@ -84,7 +84,7 @@ public static class FunctionalTest "IObservable ListenBucketNotificationsAsync(ListenBucketNotificationsArgs args, CancellationToken cancellationToken = default(CancellationToken))"; private const string listenNotificationsSignature = - "IObservable ListenNotificationsAsync(IList events, CancellationToken cancellationToken = default(CancellationToken))"; + "IObservable ListenNotifications(ListenBucketNotificationsArgs args, CancellationToken cancellationToken = default(CancellationToken))"; private const string copyObjectSignature = "Task CopyObjectAsync(CopyObjectArgs args, CancellationToken cancellationToken = default(CancellationToken))"; @@ -1041,13 +1041,11 @@ internal static async Task CreateBucket_Tester(IMinioClient minio, string { // Create a new bucket await minio.MakeBucketAsync(new MakeBucketArgs().WithBucket(bucketName)).ConfigureAwait(false); + await Task.Delay(800).ConfigureAwait(false); // Verify the bucket exists - var bucketExists = await minio.BucketExistsAsync(new BucketExistsArgs().WithBucket(bucketName)) + return await minio.BucketExistsAsync(new BucketExistsArgs().WithBucket(bucketName)) .ConfigureAwait(false); - Assert.IsTrue(bucketExists, $"Bucket {bucketName} was not created successfully."); - - return bucketExists; } internal static async Task StatObject_Test1(IMinioClient minio) @@ -1282,7 +1280,7 @@ internal static async Task RemoveObjects_Test3(IMinioClient minio) .WithBucket(bucketName) .WithObjectsVersions(objVersions); - await minio.RemoveObjectsAsync(removeObjectsArgs).ConfigureAwait(false); + _ = await minio.RemoveObjectsAsync(removeObjectsArgs).ConfigureAwait(false); await TearDown(minio, bucketName).ConfigureAwait(false); @@ -2639,7 +2637,7 @@ await ListObjects_Test(minio, bucketName, singleObjectName, 1, headers: extractH #region Global Notifications - internal static async Task ListenNotificationsAsync_Test1(IMinioClient minio) + internal static async Task ListenNotifications_Test1(IMinioClient minio) { var startTime = DateTime.Now; var bucketName = GetRandomName(15); @@ -2648,61 +2646,54 @@ internal static async Task ListenNotificationsAsync_Test1(IMinioClient minio) try { var received = new List(); - var eventsList = new List { EventType.BucketCreatedAll }; - var events = minio.ListenNotificationsAsync(eventsList); - var subscription = events.Subscribe( - received.Add, - ex => Console.WriteLine($"OnError: {ex}"), - () => Console.WriteLine("Stopped listening for bucket notifications\n")); - - // Ensure the subscription is established - await Task.Delay(1000).ConfigureAwait(false); - - // Trigger the event by creating a new bucket - var isBucketCreated1 = await CreateBucket_Tester(minio, bucketName).ConfigureAwait(false); - + // No need to define a new "ListenNotificationArgs" + // "ListenBucketNotificationsArgs" is good here + var listenArgs = new ListenBucketNotificationsArgs() + .WithEvents(eventsList); + var events = minio.ListenNotifications(listenArgs); var eventDetected = false; + using (var subscription = events.Subscribe( + received.Add, + _ => { }, + () => { })) + { + await Task.Delay(200).ConfigureAwait(false); + // Trigger the event by creating a new bucket + _ = await CreateBucket_Tester(minio, bucketName).ConfigureAwait(false); + } + for (var attempt = 0; attempt < 20; attempt++) - { - if (received.Count > 0) + // Check if there is a caught event + if (received.Count == 1) { var notification = JsonSerializer.Deserialize(received[0].Json); if (notification.Records is not null) { Assert.AreEqual(1, notification.Records.Count); + Assert.IsTrue(notification.Records[0].EventName + .Contains("s3:BucketCreated:*", StringComparison.OrdinalIgnoreCase)); eventDetected = true; break; } } - await Task.Delay(500).ConfigureAwait(false); // Delay between attempts - } - - subscription.Dispose(); - if (!eventDetected) - throw new UnexpectedMinioException("Failed to detect the expected bucket notification event."); - - new MintLogger(nameof(ListenNotificationsAsync_Test1), - listenNotificationsSignature, - "Tests whether ListenNotifications passes", - TestStatus.PASS, DateTime.Now - startTime, args: args).Log(); - } - catch (NotImplementedException ex) - { - new MintLogger(nameof(ListenNotificationsAsync_Test1), - listenNotificationsSignature, - "Tests whether ListenNotifications passes", - TestStatus.NA, DateTime.Now - startTime, ex.Message, - ex.ToString(), args: args).Log(); + if (eventDetected) + new MintLogger(nameof(ListenNotifications_Test1), + listenNotificationsSignature, + "Tests whether ListenNotifications notifies user about \"BucketCreatedAll\" event", + TestStatus.PASS, DateTime.Now - startTime, args: args).Log(); + else + throw new UnexpectedMinioException( + "Failed to detect the expected notification event, \"BucketCreatedAll\"."); } catch (Exception ex) { - new MintLogger(nameof(ListenNotificationsAsync_Test1), + new MintLogger(nameof(ListenNotifications_Test1), listenNotificationsSignature, - "Tests whether ListenNotifications passes", + "Tests whether ListenNotifications notifies user about \"BucketCreatedAll\" event", TestStatus.FAIL, DateTime.Now - startTime, ex.Message, ex.ToString(), args: args).Log(); throw; @@ -2738,57 +2729,26 @@ internal static async Task ListenBucketNotificationsAsync_Test1(IMinioClient min var received = new List(); var eventsList = new List { EventType.ObjectCreatedAll }; + var eventDetected = false; var listenArgs = new ListenBucketNotificationsArgs() .WithBucket(bucketName) .WithEvents(eventsList); var events = minio.ListenBucketNotificationsAsync(listenArgs); - var subscription = events.Subscribe( - received.Add, - ex => { }, - () => { } - ); - - - _ = await PutObject_Tester(minio, bucketName, objectName, null, contentType, - 0, null, rsg.GenerateStreamFromSeed(1 * KB)).ConfigureAwait(false); + using (var subscription = events.Subscribe( + received.Add, + _ => { }, + () => { })) + { + _ = await PutObject_Tester(minio, bucketName, objectName, null, contentType, + 0, null, rsg.GenerateStreamFromSeed(1 * KB)).ConfigureAwait(false); + } - // wait for notifications - var eventDetected = false; - for (var attempt = 0; attempt < 10; attempt++) - if (received.Count > 0) + for (var attempt = 0; attempt < 20; attempt++) + // Check if there is a caught event + if (received.Count == 1) { - // Check if there is any unexpected error returned - // and captured in the receivedJson list, like - // "NotImplemented" api error. If so, we throw an exception - // and skip running this test - if (received.Count > 1 && - received[1].Json.StartsWith("", StringComparison.OrdinalIgnoreCase)) - { - // Although the attribute is called "json", - // returned data in list "received" is in xml - // format and it is an error.Here, we convert xml - // into json format. - var receivedJson = XmlStrToJsonStr(received[1].Json); - - // Cleanup the "Error" key encapsulating "receivedJson" - // data. This is required to match and convert json data - // "receivedJson" into class "ErrorResponse" - var len = "{'Error':".Length; - var trimmedFront = receivedJson[len..]; - var trimmedFull = trimmedFront[..^1]; - - var err = JsonSerializer.Deserialize(trimmedFull); - - Exception ex = new UnexpectedMinioException(err.Message); - if (string.Equals(err.Code, "NotImplemented", StringComparison.OrdinalIgnoreCase)) - ex = new NotImplementedException(err.Message); - await TearDown(minio, bucketName).ConfigureAwait(false); - throw ex; - } - var notification = JsonSerializer.Deserialize(received[0].Json); - if (notification.Records is not null) { Assert.AreEqual(1, notification.Records.Count); @@ -2804,20 +2764,19 @@ internal static async Task ListenBucketNotificationsAsync_Test1(IMinioClient min } } - // subscription.Dispose(); - if (!eventDetected) + if (eventDetected) + new MintLogger(nameof(ListenBucketNotificationsAsync_Test1), + listenBucketNotificationsSignature, + "Tests whether ListenBucketNotifications passes for small object", + TestStatus.PASS, DateTime.Now - startTime, args: args).Log(); + else throw new UnexpectedMinioException("Failed to detect the expected bucket notification event."); - - new MintLogger(nameof(ListenBucketNotificationsAsync_Test1), - listenBucketNotificationsSignature, - "Tests whether ListenBucketNotifications passes for small object", - TestStatus.PASS, DateTime.Now - startTime, args: args).Log(); } catch (NotImplementedException ex) { new MintLogger(nameof(ListenBucketNotificationsAsync_Test1), listenBucketNotificationsSignature, - "Tests whether ListenBucketNotifications passes for small object", + "Tests whether ListenBucketNotifications generates notification for a newly created object.", TestStatus.NA, DateTime.Now - startTime, ex.Message, ex.ToString(), args: args).Log(); } @@ -2841,14 +2800,14 @@ static bool isAWS(string endPoint) // This is a PASS new MintLogger(nameof(ListenBucketNotificationsAsync_Test1), listenBucketNotificationsSignature, - "Tests whether ListenBucketNotifications passes for small object", + "Tests whether ListenBucketNotifications generates notification for a newly created object.", TestStatus.PASS, DateTime.Now - startTime, args: args).Log(); } else { new MintLogger(nameof(ListenBucketNotificationsAsync_Test1), listenBucketNotificationsSignature, - "Tests whether ListenBucketNotifications passes for small object", + "Tests whether ListenBucketNotifications generates notification for a newly created object.", TestStatus.FAIL, DateTime.Now - startTime, ex.Message, ex.ToString(), args: args).Log(); throw; diff --git a/Minio.Functional.Tests/Program.cs b/Minio.Functional.Tests/Program.cs index b033cae2e..5fc6ed93a 100644 --- a/Minio.Functional.Tests/Program.cs +++ b/Minio.Functional.Tests/Program.cs @@ -108,7 +108,7 @@ public static async Task Main(string[] args) ConcurrentBag functionalTestTasks = new(); // Global Notification - await FunctionalTest.ListenNotificationsAsync_Test1(minioClient).ConfigureAwait(false); + await FunctionalTest.ListenNotifications_Test1(minioClient).ConfigureAwait(false); // Try catch as 'finally' section needs to run in the Functional Tests // Bucket notification is a minio specific feature. diff --git a/Minio/ApiEndpoints/BucketOperations.cs b/Minio/ApiEndpoints/BucketOperations.cs index d66db8d25..3614bf58a 100644 --- a/Minio/ApiEndpoints/BucketOperations.cs +++ b/Minio/ApiEndpoints/BucketOperations.cs @@ -762,13 +762,12 @@ await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, /// /// Subscribes to global change notifications (a Minio-only extension) /// - /// Events to listen for + /// ListenBucketNotificationsArgs to listen events /// Optional cancellation token to cancel the operation /// An observable of JSON-based notification events - public IObservable ListenNotificationsAsync(IList events, + public IObservable ListenNotifications(ListenBucketNotificationsArgs args, CancellationToken cancellationToken = default) { - var args = new ListenBucketNotificationsArgs().WithEvents(events); return ListenBucketNotificationsAsync(args, cancellationToken); } diff --git a/Minio/ApiEndpoints/IBucketOperations.cs b/Minio/ApiEndpoints/IBucketOperations.cs index db6ad41b7..00abc537c 100644 --- a/Minio/ApiEndpoints/IBucketOperations.cs +++ b/Minio/ApiEndpoints/IBucketOperations.cs @@ -379,7 +379,7 @@ Task GetBucketReplicationAsync(GetBucketReplicationArg Task GetPolicyAsync(GetPolicyArgs args, CancellationToken cancellationToken = default); - IObservable ListenNotificationsAsync(IList events, + IObservable ListenNotifications(ListenBucketNotificationsArgs args, CancellationToken cancellationToken = default); IObservable ListenBucketNotificationsAsync(string bucketName, IList events, diff --git a/Minio/Minio.csproj b/Minio/Minio.csproj index 0739aa784..1d12e522f 100644 --- a/Minio/Minio.csproj +++ b/Minio/Minio.csproj @@ -25,7 +25,7 @@ - +