From 31aa9623b85b4bc0e491ad21bcc3e7a0a809b316 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Luthi?= Date: Mon, 30 Jan 2023 21:28:19 +0100 Subject: [PATCH] Automatically run MongoDB during the tests (with EphemeralMongo) (#337) Also remove the mongodb service in GitHub actions. --- .github/workflows/build.yml | 5 - .github/workflows/release.yml | 5 - .../ExpirationManagerFacts.cs | 23 +- .../Hangfire.Mongo.Tests.csproj | 6 +- .../Migration/Mongo/MigrationFacts.cs | 32 +-- .../Migration/Mongo/MongoDatabaseFiller.cs | 17 +- .../Migration/Version15MigrationStepFacts.cs | 68 +++--- .../Migration/Version16MigrationStepFacts.cs | 22 +- .../Migration/Version18MigrationStepFacts.cs | 14 +- .../Migration/Version19MigrationStepFacts.cs | 11 +- .../Migration/Version20MigrationStepFacts.cs | 5 +- .../MongoConnectionFacts.cs | 197 +++++++++--------- .../MongoDiscriminatorTests.cs | 6 +- .../MongoDistributedLockFacts.cs | 27 ++- .../MongoFetchedJobFacts.cs | 20 +- .../MongoJobQueueFacts.cs | 47 +++-- .../MongoMonitoringApiFacts.cs | 92 ++++---- .../MongoNotificationObserverErrorFacts.cs | 18 +- .../MongoNotificationObserverFacts.cs | 16 +- .../MongoRunServerFacts.cs | 10 +- src/Hangfire.Mongo.Tests/MongoStorageFacts.cs | 22 +- .../MongoVersionHelperFacts.cs | 15 +- src/Hangfire.Mongo.Tests/MongoWatcherFacts.cs | 13 +- .../MongoWriteOnlyTransactionFacts.cs | 53 +---- .../MultipleServersFacts.cs | 16 +- .../Utils/CleanDatabaseAttribute.cs | 64 ------ .../Utils/ConnectionUtils.cs | 50 ----- .../Utils/DatabaseCollection.cs | 9 + .../Utils/MongoDbFixture.cs | 81 +++++++ src/Hangfire.Mongo.Tests/xunit.runner.json | 4 + 30 files changed, 479 insertions(+), 489 deletions(-) delete mode 100644 src/Hangfire.Mongo.Tests/Utils/CleanDatabaseAttribute.cs delete mode 100644 src/Hangfire.Mongo.Tests/Utils/ConnectionUtils.cs create mode 100644 src/Hangfire.Mongo.Tests/Utils/DatabaseCollection.cs create mode 100644 src/Hangfire.Mongo.Tests/Utils/MongoDbFixture.cs create mode 100644 src/Hangfire.Mongo.Tests/xunit.runner.json diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 76ff097c..31aca3a1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,11 +10,6 @@ jobs: build: runs-on: ubuntu-latest - services: - mongodb: - image: mongo - ports: - - 27017:27017 steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 79d2afb3..b1f6ea6e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,11 +16,6 @@ jobs: build_release: name: create release runs-on: ubuntu-latest - services: - mongodb: - image: mongo - ports: - - 27017:27017 steps: - uses: actions/checkout@v2 diff --git a/src/Hangfire.Mongo.Tests/ExpirationManagerFacts.cs b/src/Hangfire.Mongo.Tests/ExpirationManagerFacts.cs index 5d682e2f..f6f9bfba 100644 --- a/src/Hangfire.Mongo.Tests/ExpirationManagerFacts.cs +++ b/src/Hangfire.Mongo.Tests/ExpirationManagerFacts.cs @@ -17,14 +17,15 @@ public class ExpirationManagerFacts : IDisposable private readonly HangfireDbContext _dbContext; private readonly CancellationToken _token; - public ExpirationManagerFacts() + public ExpirationManagerFacts(MongoDbFixture fixture) { - _dbContext = ConnectionUtils.CreateDbContext(); + fixture.CleanDatabase(); + _dbContext = fixture.CreateDbContext(); _token = new CancellationToken(true); } - [Fact, CleanDatabase] + [Fact] public void Execute_RemovesOutdatedRecords() { CreateExpirationEntries(_dbContext, DateTime.UtcNow.AddMonths(-1)); @@ -35,7 +36,7 @@ public void Execute_RemovesOutdatedRecords() Assert.True(IsEntryExpired(_dbContext)); } - [Fact, CleanDatabase] + [Fact] public void Execute_DoesNotRemoveEntries_WithNoExpirationTimeSet() { CreateExpirationEntries(_dbContext, null); @@ -46,7 +47,7 @@ public void Execute_DoesNotRemoveEntries_WithNoExpirationTimeSet() Assert.False(IsEntryExpired(_dbContext)); } - [Fact, CleanDatabase] + [Fact] public void Execute_DoesNotRemoveEntries_WithFreshExpirationTime() { CreateExpirationEntries(_dbContext, DateTime.UtcNow.AddMonths(1)); @@ -58,7 +59,7 @@ public void Execute_DoesNotRemoveEntries_WithFreshExpirationTime() Assert.False(IsEntryExpired(_dbContext)); } - [Fact, CleanDatabase] + [Fact] public void Execute_Processes_CounterTable() { // Arrange @@ -80,7 +81,7 @@ public void Execute_Processes_CounterTable() Assert.Equal(0, count); } - [Fact, CleanDatabase] + [Fact] public void Execute_Processes_JobTable() { // Arrange @@ -103,7 +104,7 @@ public void Execute_Processes_JobTable() Assert.Equal(0, count); } - [Fact, CleanDatabase] + [Fact] public void Execute_Processes_ListTable() { // Arrange @@ -126,7 +127,7 @@ public void Execute_Processes_ListTable() Assert.Equal(0, count); } - [Fact, CleanDatabase] + [Fact] public void Execute_Processes_SetTable() { // Arrange @@ -151,7 +152,7 @@ public void Execute_Processes_SetTable() Assert.Equal(0, count); } - [Fact, CleanDatabase] + [Fact] public void Execute_Processes_HashTable() { // Arrange @@ -176,7 +177,7 @@ public void Execute_Processes_HashTable() } - [Fact, CleanDatabase] + [Fact] public void Execute_Processes_AggregatedCounterTable() { // Arrange diff --git a/src/Hangfire.Mongo.Tests/Hangfire.Mongo.Tests.csproj b/src/Hangfire.Mongo.Tests/Hangfire.Mongo.Tests.csproj index 312ec729..741bb82b 100644 --- a/src/Hangfire.Mongo.Tests/Hangfire.Mongo.Tests.csproj +++ b/src/Hangfire.Mongo.Tests/Hangfire.Mongo.Tests.csproj @@ -1,4 +1,4 @@ - + net6.0 $(NoWarn);CS0618 @@ -26,6 +26,7 @@ + @@ -41,6 +42,9 @@ + + + PreserveNewest diff --git a/src/Hangfire.Mongo.Tests/Migration/Mongo/MigrationFacts.cs b/src/Hangfire.Mongo.Tests/Migration/Mongo/MigrationFacts.cs index d5057210..bbed4c81 100644 --- a/src/Hangfire.Mongo.Tests/Migration/Mongo/MigrationFacts.cs +++ b/src/Hangfire.Mongo.Tests/Migration/Mongo/MigrationFacts.cs @@ -22,6 +22,14 @@ namespace Hangfire.Mongo.Tests.Migration.Mongo [Collection("Database")] public class MigrationFacts { + private readonly MongoDbFixture _fixture; + + public MigrationFacts(MongoDbFixture fixture) + { + fixture.CleanDatabase(); + _fixture = fixture; + } + [Theory] [InlineData(null, false)] [InlineData("Hangfire-Mongo-Schema-004.zip", false)] @@ -43,7 +51,7 @@ public class MigrationFacts public void Migrate_Full_Success(string seedFile, bool assertCollectionHasItems) { - var dbContext = ConnectionUtils.CreateDbContext("Hangfire-Mongo-Migration-Tests"); + var dbContext = _fixture.CreateDbContext("Hangfire-Mongo-Migration-Tests"); // ARRANGE dbContext.Client.DropDatabase(dbContext.Database.DatabaseNamespace.DatabaseName); @@ -51,7 +59,7 @@ public void Migrate_Full_Success(string seedFile, bool assertCollectionHasItems) { SeedCollectionFromZipArchive(dbContext, Path.Combine("Migration", seedFile)); } - + var storageOptions = new MongoStorageOptions { MigrationOptions = new MongoMigrationOptions @@ -70,10 +78,10 @@ public void Migrate_Full_Success(string seedFile, bool assertCollectionHasItems) AssertDataIntegrity(dbContext, assertCollectionHasItems); } - [Fact, CleanDatabase] + [Fact] public void Migrate_MultipleInstances_ThereCanBeOnlyOne() { - var dbContext = ConnectionUtils.CreateDbContext(); + var dbContext = _fixture.CreateDbContext(); // ARRANGE dbContext.Database.DropCollection(dbContext.Schema.CollectionNamespace.CollectionName); var storageOptions = new MongoStorageOptions @@ -114,12 +122,12 @@ public void Migrate_MultipleInstances_ThereCanBeOnlyOne() // ASSERT Assert.True(tasks.Select(t => t.Result).Single(b => b)); } - + [Fact] public void Migrate_DropNoBackup_Success() { - var dbContext = ConnectionUtils.CreateDbContext("Hangfire-Mongo-Migration-Tests"); - + var dbContext = _fixture.CreateDbContext("Hangfire-Mongo-Migration-Tests"); + // ARRANGE dbContext.Client.DropDatabase(dbContext.Database.DatabaseNamespace.DatabaseName); SeedCollectionFromZipArchive(dbContext, Path.Combine("Migration", "Hangfire-Mongo-Schema-006.zip")); @@ -146,14 +154,14 @@ private static void AssertDataIntegrity(HangfireDbContext dbContext, bool assert var locks = dbContext.DistributedLock.Find(new BsonDocument()).ToList(); var schema = dbContext.Schema.Find(new BsonDocument()).ToList(); var servers = dbContext.Server.Find(new BsonDocument()).ToList(); - + if (assertCollectionHasItems) { AssertCollectionNotEmpty(jobGraphDtos, nameof(dbContext.JobGraph)); AssertCollectionNotEmpty(locks, nameof(dbContext.DistributedLock)); AssertCollectionNotEmpty(schema, nameof(dbContext.Schema)); - AssertCollectionNotEmpty(servers, nameof(dbContext.Server)); + AssertCollectionNotEmpty(servers, nameof(dbContext.Server)); } } @@ -161,7 +169,7 @@ private static void AssertCollectionNotEmpty(IEnumerable collection, str { Assert.True(collection.Any(), $"Expected '{collectionName}' to have items"); } - + #region Private Helper Methods private static void SeedCollectionFromZipArchive(HangfireDbContext connection, string fileName) @@ -204,10 +212,10 @@ private static void SeedCollectionFromJson(HangfireDbContext connection, string catch (Exception e) { Console.WriteLine($"Error seeding collection {collectionName}: {e}"); - + throw; } - + } } diff --git a/src/Hangfire.Mongo.Tests/Migration/Mongo/MongoDatabaseFiller.cs b/src/Hangfire.Mongo.Tests/Migration/Mongo/MongoDatabaseFiller.cs index 89e2bf7d..e06006eb 100644 --- a/src/Hangfire.Mongo.Tests/Migration/Mongo/MongoDatabaseFiller.cs +++ b/src/Hangfire.Mongo.Tests/Migration/Mongo/MongoDatabaseFiller.cs @@ -19,11 +19,18 @@ namespace Hangfire.Mongo.Tests.Migration.Mongo [Collection("Database")] public class MongoDatabaseFiller { + private readonly MongoDbFixture _fixture; + + public MongoDatabaseFiller(MongoDbFixture fixture) + { + _fixture = fixture; + } + //[Fact, Trait("Category", "DataGeneration")] public void Clean_Database_Filled() { var databaseName = "Mongo-Hangfire-Filled"; - var context = ConnectionUtils.CreateDbContext(databaseName); + var context = _fixture.CreateDbContext(databaseName); // Make sure we start from scratch context.Database.Client.DropDatabase(databaseName); @@ -40,8 +47,8 @@ public void Clean_Database_Filled() { ShutdownTimeout = TimeSpan.FromSeconds(15) }; - - JobStorage.Current = ConnectionUtils.CreateStorage(databaseName); + + JobStorage.Current = _fixture.CreateStorage(databaseName); using (new BackgroundJobServer(serverOptions)) { @@ -93,7 +100,7 @@ public void Clean_Database_Filled() if (MongoMigrationManager.RequiredSchemaVersion >= MongoSchema.Version09 && MongoMigrationManager.RequiredSchemaVersion <= MongoSchema.Version15) { - // Signal collection work was initiated in schema version 9, + // Signal collection work was initiated in schema version 9, // and still not put to use in schema version 15. allowedEmptyCollections.Add($@"{storageOptions.Prefix}.signal"); } @@ -106,7 +113,7 @@ private void BackupDatabaseToStream(string databaseName, Stream stream, params s { using (var archive = new ZipArchive(stream, ZipArchiveMode.Create, true)) { - var context = ConnectionUtils.CreateDbContext(databaseName); + var context = _fixture.CreateDbContext(databaseName); foreach (var collectionName in context.Database.ListCollections().ToList() .Select(c => c["name"].AsString)) { diff --git a/src/Hangfire.Mongo.Tests/Migration/Version15MigrationStepFacts.cs b/src/Hangfire.Mongo.Tests/Migration/Version15MigrationStepFacts.cs index dc46337d..41ab46f2 100644 --- a/src/Hangfire.Mongo.Tests/Migration/Version15MigrationStepFacts.cs +++ b/src/Hangfire.Mongo.Tests/Migration/Version15MigrationStepFacts.cs @@ -18,14 +18,14 @@ public class Version15MigrationStepFacts private readonly HangfireDbContext _dbContext; private readonly Mock _mongoMigrationBagMock; private readonly IMongoDatabase _database; - - public Version15MigrationStepFacts() + + public Version15MigrationStepFacts(MongoDbFixture fixture) { - _dbContext = ConnectionUtils.CreateDbContext(); + _dbContext = fixture.CreateDbContext(); _database = _dbContext.Database; _mongoMigrationBagMock = new Mock(MockBehavior.Strict); } - + [Fact] public void ExecuteStep00_ValidExistingLockDto_Success() { @@ -48,7 +48,7 @@ public void ExecuteStep00_ValidExistingLockDto_Success() // ACT var result = new CreateUniqueLockIndex().Execute(_dbContext.Database, new MongoStorageOptions(), _mongoMigrationBagMock.Object); - + // ASSERT var indexes = collection.Indexes.List().ToList(); AssertIndex(indexes, "Resource", true); @@ -69,11 +69,11 @@ public void ExecuteStep01_ValidExistingServerDto_Success() var collection = _database.GetCollection("hangfire.server"); collection.DeleteOne(new BsonDocument("_id", "test-server")); collection.InsertOne(originalServerDto); - + // ACT var result = new MakeServerDataEmbeddedDocument().Execute(_database, new MongoStorageOptions(), _mongoMigrationBagMock.Object); - + // ASSERT var migratedServerDto = collection.Find(new BsonDocument()).Single(); Assert.True(result, "Expected migration to be successful, reported 'false'"); @@ -99,16 +99,16 @@ public void ExecuteStep02_ValidExistingSetDto_Success() }; collection.DeleteMany(new BsonDocument("_t", "SetDto")); collection.InsertOne(originalSetDto); - + // ACT var result = new CreateCompositeKeys().Execute(_database, new MongoStorageOptions(), _mongoMigrationBagMock.Object); - + // ASSERT var migratedSetDto = collection.Find(new BsonDocument("_t", "SetDto")).Single(); Assert.True(result, "Expected migration to be successful, reported 'false'"); Assert.Equal("Key:Value", migratedSetDto["Key"].AsString); } - + [Fact] public void ExecuteStep03_MultipleCountersNotDeleted_OldCountersDeleted() { @@ -116,7 +116,7 @@ public void ExecuteStep03_MultipleCountersNotDeleted_OldCountersDeleted() var collection = _database.GetCollection("hangfire.jobGraph"); collection.Indexes.DropAll(); collection.DeleteMany(new BsonDocument("_t", "CounterDto")); - + var counters = new List(); foreach (var i in Enumerable.Range(0, 5)) { @@ -140,16 +140,16 @@ public void ExecuteStep03_MultipleCountersNotDeleted_OldCountersDeleted() }; counters.Add(mergedCounter); collection.InsertMany(counters); - + // ACT var result = new RemoveMergedCounters().Execute(_database, new MongoStorageOptions(), _mongoMigrationBagMock.Object); - + // ASSERT var remainingCounter = collection.Find(new BsonDocument("_t", "CounterDto")).Single(); Assert.True(result, "Expected migration to be successful, reported 'false'"); Assert.Equal(5, remainingCounter["Value"].AsInt64); } - + [Fact] public void ExecuteStep03_MultipleCountersDifferentValues_CountersMerged() { @@ -157,7 +157,7 @@ public void ExecuteStep03_MultipleCountersDifferentValues_CountersMerged() var collection = _database.GetCollection("hangfire.jobGraph"); collection.Indexes.DropAll(); collection.DeleteMany(new BsonDocument("_t", "CounterDto")); - + var counters = new List(); foreach (var i in Enumerable.Range(0, 5)) { @@ -190,22 +190,22 @@ public void ExecuteStep03_MultipleCountersDifferentValues_CountersMerged() counters.Add(mergedCounter); counters.Add(aggregatedCounter); collection.InsertMany(counters); - + // ACT var result = new RemoveMergedCounters().Execute(_database, new MongoStorageOptions(), _mongoMigrationBagMock.Object); - + // ASSERT var remainingCounter = collection.Find(new BsonDocument("_t", "CounterDto")).Single(); Assert.True(result, "Expected migration to be successful, reported 'false'"); Assert.Equal(10, remainingCounter["Value"].AsInt64); } - + [Fact] public void ExecuteStep03_OneCounter_Nothing() { // ARRANGE var collection = _database.GetCollection("hangfire.jobGraph"); - + collection.DeleteMany(new BsonDocument("Key", "stats:succeeded")); collection.InsertOne(new BsonDocument { @@ -215,16 +215,16 @@ public void ExecuteStep03_OneCounter_Nothing() ["ExpireAt"] = BsonNull.Value, ["_t"] = "CounterDto" }); - + // ACT var result = new RemoveMergedCounters().Execute(_database, new MongoStorageOptions(), _mongoMigrationBagMock.Object); - + // ASSERT var remainingCounter = collection.Find(new BsonDocument("_t", "CounterDto")).Single(); Assert.NotNull(remainingCounter); Assert.True(result, "Expected migration to be successful, reported 'false'"); } - + [Fact] public void ExecuteStep03_TwoCountersSameValue_NewestChosen() { @@ -248,25 +248,25 @@ public void ExecuteStep03_TwoCountersSameValue_NewestChosen() ["ExpireAt"] = BsonNull.Value, ["_t"] = "CounterDto" }; - + collection.InsertOne(expectedDoc); - + // ACT var result = new RemoveMergedCounters().Execute(_database, new MongoStorageOptions(), _mongoMigrationBagMock.Object); - + // ASSERT var remainingCounter = collection.Find(new BsonDocument("_t", "CounterDto")).Single(); Assert.NotNull(remainingCounter); Assert.True(result, "Expected migration to be successful, reported 'false'"); Assert.Equal(expectedDoc["_id"], remainingCounter["_id"]); } - + [Fact] public void ExecuteStep04_UpdateListDtoKeySchema_Success() { // ARRANGE var collection = _database.GetCollection("hangfire.jobGraph"); - + collection.DeleteMany(new BsonDocument("_t", "ListDto")); collection.InsertOne(new BsonDocument { @@ -276,10 +276,10 @@ public void ExecuteStep04_UpdateListDtoKeySchema_Success() ["ExpireAt"] = BsonNull.Value, ["_t"] = "ListDto" }); - + // ACT var result = new UpdateListDtoKeySchema().Execute(_database, new MongoStorageOptions(), _mongoMigrationBagMock.Object); - + // ASSERT var listDto = collection.Find(new BsonDocument("_t", "ListDto")).Single(); Assert.NotNull(listDto); @@ -288,18 +288,18 @@ public void ExecuteStep04_UpdateListDtoKeySchema_Success() Assert.False(listDto.Contains("Key")); Assert.Equal(BsonArray.Create(new[]{"BaseJobDto", "ExpiringJobDto", "ListDto"}), listDto["_t"]); } - + [Fact] public void ExecuteStep05_UpdateIndexes_Success() { // ARRANGE var collection = _database.GetCollection("hangfire.jobGraph"); - + collection.Indexes.DropAll(); - + // ACT var result = new UpdateIndexes().Execute(_database, new MongoStorageOptions(), _mongoMigrationBagMock.Object); - + // ASSERT Assert.True(result, "Expected migration to be successful, reported 'false'"); var indexes = collection.Indexes.List().ToList(); @@ -332,6 +332,6 @@ private static void AssertIndex(IList indexes, string indexName, b Assert.True(index["key"][indexName].AsInt32 == 1, "Expected index to be 'Descending'"); } } - + } } \ No newline at end of file diff --git a/src/Hangfire.Mongo.Tests/Migration/Version16MigrationStepFacts.cs b/src/Hangfire.Mongo.Tests/Migration/Version16MigrationStepFacts.cs index 3aa118be..a888720f 100644 --- a/src/Hangfire.Mongo.Tests/Migration/Version16MigrationStepFacts.cs +++ b/src/Hangfire.Mongo.Tests/Migration/Version16MigrationStepFacts.cs @@ -17,14 +17,14 @@ public class Version16MigrationStepFacts private readonly HangfireDbContext _dbContext; private readonly Mock _mongoMigrationBagMock; private readonly IMongoDatabase _database; - - public Version16MigrationStepFacts() + + public Version16MigrationStepFacts(MongoDbFixture fixture) { - _dbContext = ConnectionUtils.CreateDbContext(); + _dbContext = fixture.CreateDbContext(); _database = _dbContext.Database; _mongoMigrationBagMock = new Mock(MockBehavior.Strict); } - + [Fact] public void ExecuteStep00_SetDtoNotContainingValue_Success() { @@ -40,19 +40,19 @@ public void ExecuteStep00_SetDtoNotContainingValue_Success() 'Score' : 0.0, 'Value' : null }"; - + collection.InsertOne(BsonDocument.Parse(setDtoJson)); - + // ACT var result = new UpdateSetDtoKeyAndValueField().Execute(_dbContext.Database, new MongoStorageOptions(), _mongoMigrationBagMock.Object); - + // ASSERT var migratedSetDto = collection.Find(_ => true).Single(); Assert.Equal("recurring-jobs", migratedSetDto["Key"].AsString); Assert.Equal("HomeController.PrintToDebug", migratedSetDto["Value"].AsString); } - + [Fact] public void ExecuteStep00_SetDtoNotCompositeKey_Success() { @@ -68,13 +68,13 @@ public void ExecuteStep00_SetDtoNotCompositeKey_Success() 'Score' : 0.0, 'Value' : 'HomeController.PrintToDebug' }"; - + collection.InsertOne(BsonDocument.Parse(setDtoJson)); - + // ACT var result = new UpdateSetDtoKeyAndValueField().Execute(_dbContext.Database, new MongoStorageOptions(), _mongoMigrationBagMock.Object); - + // ASSERT var migratedSetDto = collection.Find(_ => true).Single(); Assert.Equal("recurring-jobs", migratedSetDto["Key"].AsString); diff --git a/src/Hangfire.Mongo.Tests/Migration/Version18MigrationStepFacts.cs b/src/Hangfire.Mongo.Tests/Migration/Version18MigrationStepFacts.cs index 047b4a7d..80e56213 100644 --- a/src/Hangfire.Mongo.Tests/Migration/Version18MigrationStepFacts.cs +++ b/src/Hangfire.Mongo.Tests/Migration/Version18MigrationStepFacts.cs @@ -18,10 +18,10 @@ public class Version18MigrationStepFacts { private readonly Mock _mongoMigrationBagMock; private readonly IMongoDatabase _database; - - public Version18MigrationStepFacts() + + public Version18MigrationStepFacts(MongoDbFixture fixture) { - var dbContext = ConnectionUtils.CreateDbContext(); + var dbContext = fixture.CreateDbContext(); _database = dbContext.Database; _mongoMigrationBagMock = new Mock(MockBehavior.Strict); } @@ -31,12 +31,12 @@ public void ExecuteStep01_UpdateIndexes_Success() { // ARRANGE var collection = _database.GetCollection("hangfire.jobGraph"); - + collection.Indexes.DropAll(); - + // ACT var result = new UpdateIndexes().Execute(_database, new MongoStorageOptions(), _mongoMigrationBagMock.Object); - + // ASSERT Assert.True(result, "Expected migration to be successful, reported 'false'"); var indexes = collection.Indexes.List().ToList(); @@ -62,6 +62,6 @@ private static void AssertIndex(IList indexes, string indexName, b Assert.True(index["key"][indexName].AsInt32 == 1, "Expected index to be 'Descending'"); } } - + } } \ No newline at end of file diff --git a/src/Hangfire.Mongo.Tests/Migration/Version19MigrationStepFacts.cs b/src/Hangfire.Mongo.Tests/Migration/Version19MigrationStepFacts.cs index c4222df8..f8a9e1bb 100644 --- a/src/Hangfire.Mongo.Tests/Migration/Version19MigrationStepFacts.cs +++ b/src/Hangfire.Mongo.Tests/Migration/Version19MigrationStepFacts.cs @@ -10,15 +10,16 @@ namespace Hangfire.Mongo.Tests.Migration { + [Collection("Database")] public class Version19MigrationStepFacts { private readonly Mock _mongoMigrationBagMock; private readonly IMongoDatabase _database; private readonly Random _random; private readonly AddTypeToSetDto _addTypeToSetDto; - public Version19MigrationStepFacts() + public Version19MigrationStepFacts(MongoDbFixture fixture) { - var dbContext = ConnectionUtils.CreateDbContext(); + var dbContext = fixture.CreateDbContext(); _database = dbContext.Database; _mongoMigrationBagMock = new Mock(MockBehavior.Strict); _random = new Random(); @@ -30,7 +31,7 @@ public void ExecuteStep01_AddTypeToSetDto_Success() { // ARRANGE var collection = _database.GetCollection("hangfire.jobGraph"); - + collection.Indexes.DropAll(); collection.InsertMany(new [] { @@ -41,7 +42,7 @@ public void ExecuteStep01_AddTypeToSetDto_Success() }); // ACT var result = _addTypeToSetDto.Execute(_database, new MongoStorageOptions(), _mongoMigrationBagMock.Object); - + // ASSERT Assert.True(result, "Expected migration to be successful, reported 'false'"); var migrated = collection.Find(new BsonDocument("_t", "SetDto")).ToList(); @@ -49,7 +50,7 @@ public void ExecuteStep01_AddTypeToSetDto_Success() { Assert.True(doc.Contains("SetType")); } - + var index = collection.Indexes.List().ToList().FirstOrDefault(b => b["name"].AsString == "SetType"); Assert.NotNull(index); } diff --git a/src/Hangfire.Mongo.Tests/Migration/Version20MigrationStepFacts.cs b/src/Hangfire.Mongo.Tests/Migration/Version20MigrationStepFacts.cs index c008243a..4b021aab 100644 --- a/src/Hangfire.Mongo.Tests/Migration/Version20MigrationStepFacts.cs +++ b/src/Hangfire.Mongo.Tests/Migration/Version20MigrationStepFacts.cs @@ -12,15 +12,16 @@ namespace Hangfire.Mongo.Tests.Migration { + [Collection("Database")] public class Version20MigrationStepFacts { private readonly Mock _mongoMigrationBagMock; private readonly IMongoDatabase _database; private readonly Random _random; private readonly IMongoMigrationStep _migration; - public Version20MigrationStepFacts() + public Version20MigrationStepFacts(MongoDbFixture fixture) { - var dbContext = ConnectionUtils.CreateDbContext(); + var dbContext = fixture.CreateDbContext(); _database = dbContext.Database; _mongoMigrationBagMock = new Mock(MockBehavior.Strict); _random = new Random(); diff --git a/src/Hangfire.Mongo.Tests/MongoConnectionFacts.cs b/src/Hangfire.Mongo.Tests/MongoConnectionFacts.cs index 70379680..f26e0ada 100644 --- a/src/Hangfire.Mongo.Tests/MongoConnectionFacts.cs +++ b/src/Hangfire.Mongo.Tests/MongoConnectionFacts.cs @@ -24,15 +24,16 @@ public class MongoConnectionFacts private readonly MongoConnection _connection; private readonly Mock _jobQueueSemaphoreMock; - public MongoConnectionFacts() + public MongoConnectionFacts(MongoDbFixture fixture) { _jobQueueSemaphoreMock = new Mock(MockBehavior.Strict); var storageOptions = new MongoStorageOptions {Factory = {JobQueueSemaphore = _jobQueueSemaphoreMock.Object}}; - _dbContext = ConnectionUtils.CreateDbContext(); + fixture.CleanDatabase(); + _dbContext = fixture.CreateDbContext(); _connection = new MongoConnection(_dbContext, storageOptions); } - + [Fact] public void Ctor_ThrowsAnException_WhenConnectionIsNull() { @@ -42,7 +43,7 @@ public void Ctor_ThrowsAnException_WhenConnectionIsNull() Assert.Equal("database", exception.ParamName); } - [Fact, CleanDatabase] + [Fact] public void Ctor_ThrowsAnException_WhenProvidersCollectionIsNull() { var exception = Assert.Throws( @@ -51,7 +52,7 @@ public void Ctor_ThrowsAnException_WhenProvidersCollectionIsNull() Assert.Equal("storageOptions", exception.ParamName); } - [Fact, CleanDatabase] + [Fact] public void FetchNextJob_DelegatesItsExecution_ToTheQueue() { var token = new CancellationToken(); @@ -65,29 +66,29 @@ public void FetchNextJob_DelegatesItsExecution_ToTheQueue() _jobQueueSemaphoreMock.Setup(m => m.WaitNonBlock("default")).Returns(true); var serializedJob = jobDto.Serialize(); _dbContext.JobGraph.InsertOne(serializedJob); - + var fetchedJob = _connection.FetchNextJob(queues, token); Assert.Equal(fetchedJob.JobId, jobDto.Id.ToString()); - + _jobQueueSemaphoreMock.Verify(m => m.WaitNonBlock("default"), Times.Once); } - [Fact, CleanDatabase] + [Fact] public void CreateWriteTransaction_ReturnsNonNullInstance() { var transaction = _connection.CreateWriteTransaction(); Assert.NotNull(transaction); } - [Fact, CleanDatabase] + [Fact] public void AcquireLock_ReturnsNonNullInstance() { var @lock = _connection.AcquireDistributedLock("1", TimeSpan.FromSeconds(1)); Assert.NotNull(@lock); } - [Fact, CleanDatabase] + [Fact] public void CreateExpiredJob_ThrowsAnException_WhenJobIsNull() { var exception = Assert.Throws( @@ -100,7 +101,7 @@ public void CreateExpiredJob_ThrowsAnException_WhenJobIsNull() Assert.Equal("job", exception.ParamName); } - [Fact, CleanDatabase] + [Fact] public void CreateExpiredJob_ThrowsAnException_WhenParametersCollectionIsNull() { var exception = Assert.Throws( @@ -113,7 +114,7 @@ public void CreateExpiredJob_ThrowsAnException_WhenParametersCollectionIsNull() Assert.Equal("parameters", exception.ParamName); } - [Fact, CleanDatabase] + [Fact] public void CreateExpiredJob_CreatesAJobInTheStorage_AndSetsItsParameters() { var createdAt = new DateTime(2012, 12, 12, 0, 0, 0, 0, DateTimeKind.Utc); @@ -158,20 +159,20 @@ public void CreateExpiredJob_CreatesAJobInTheStorage_AndSetsItsParameters() Assert.Equal("Value2", parameters["Key2"]); } - [Fact, CleanDatabase] + [Fact] public void GetJobData_ThrowsAnException_WhenJobIdIsNull() { Assert.Throws(() => _connection.GetJobData(null)); } - [Fact, CleanDatabase] + [Fact] public void GetJobData_ReturnsNull_WhenThereIsNoSuchJob() { var result = _connection.GetJobData(ObjectId.GenerateNewId().ToString()); Assert.Null(result); } - [Fact, CleanDatabase] + [Fact] public void GetJobData_ReturnsResult_WhenJobExists() { var job = Job.FromExpression(() => HangfireTestJobs.SampleMethod("wrong")); @@ -197,20 +198,20 @@ public void GetJobData_ReturnsResult_WhenJobExists() Assert.True(result.CreatedAt < DateTime.UtcNow.AddMinutes(1)); } - [Fact, CleanDatabase] + [Fact] public void GetStateData_ThrowsAnException_WhenJobIdIsNull() { Assert.Throws(() => _connection.GetStateData(null)); } - [Fact, CleanDatabase] + [Fact] public void GetStateData_ReturnsNull_IfThereIsNoSuchState() { var result = _connection.GetStateData(ObjectId.GenerateNewId().ToString()); Assert.Null(result); } - [Fact, CleanDatabase] + [Fact] public void GetStateData_ReturnsCorrectData() { var data = new Dictionary @@ -253,7 +254,7 @@ public void GetStateData_ReturnsCorrectData() }.Serialize() } }; - + var filter = new BsonDocument { ["_id"] = jobId, @@ -270,7 +271,7 @@ public void GetStateData_ReturnsCorrectData() Assert.Equal("Value", result.Data["Key"]); } - [Fact, CleanDatabase] + [Fact] public void GetJobData_ReturnsJobLoadException_IfThereWasADeserializationException() { var jobDto = new JobDto @@ -289,7 +290,7 @@ public void GetJobData_ReturnsJobLoadException_IfThereWasADeserializationExcepti Assert.NotNull(result.LoadException); } - [Fact, CleanDatabase] + [Fact] public void SetParameter_ThrowsAnException_WhenJobIdIsNull() { var exception = Assert.Throws(() => _connection.SetJobParameter(null, "name", "value")); @@ -297,7 +298,7 @@ public void SetParameter_ThrowsAnException_WhenJobIdIsNull() Assert.Equal("id", exception.ParamName); } - [Fact, CleanDatabase] + [Fact] public void SetParameter_ThrowsAnException_WhenNameIsNull() { var exception = Assert.Throws( @@ -306,7 +307,7 @@ public void SetParameter_ThrowsAnException_WhenNameIsNull() Assert.Equal("name", exception.ParamName); } - [Fact, CleanDatabase] + [Fact] public void SetParameters_CreatesNewParameter_WhenParameterWithTheGivenNameDoesNotExists() { var jobDto = new JobDto @@ -335,7 +336,7 @@ public void SetParameters_CreatesNewParameter_WhenParameterWithTheGivenNameDoesN Assert.Equal("Value", job.Parameters["Name"]); } - [Fact, CleanDatabase] + [Fact] public void SetParameter_UpdatesValue_WhenParameterWithTheGivenName_AlreadyExists() { var jobDto = new JobDto @@ -366,7 +367,7 @@ public void SetParameter_UpdatesValue_WhenParameterWithTheGivenName_AlreadyExist Assert.Equal("AnotherValue", job.Parameters["Name"]); } - [Fact, CleanDatabase] + [Fact] public void SetParameter_CanAcceptNulls_AsValues() { var jobDto = new JobDto @@ -396,7 +397,7 @@ public void SetParameter_CanAcceptNulls_AsValues() Assert.Null(job.Parameters["Name"]); } - [Fact, CleanDatabase] + [Fact] public void GetParameter_ThrowsAnException_WhenJobIdIsNull() { var exception = Assert.Throws( @@ -405,7 +406,7 @@ public void GetParameter_ThrowsAnException_WhenJobIdIsNull() Assert.Equal("id", exception.ParamName); } - [Fact, CleanDatabase] + [Fact] public void GetParameter_ThrowsAnException_WhenNameIsNull() { var exception = Assert.Throws( @@ -414,14 +415,14 @@ public void GetParameter_ThrowsAnException_WhenNameIsNull() Assert.Equal("name", exception.ParamName); } - [Fact, CleanDatabase] + [Fact] public void GetParameter_ReturnsNull_WhenParameterDoesNotExists() { var value = _connection.GetJobParameter(ObjectId.GenerateNewId().ToString(), "hello"); Assert.Null(value); } - [Fact, CleanDatabase] + [Fact] public void GetParameter_ReturnsParameterValue_WhenJobExists() { var jobDto = new JobDto @@ -441,7 +442,7 @@ public void GetParameter_ReturnsParameterValue_WhenJobExists() Assert.Equal("value", value); } - [Fact, CleanDatabase] + [Fact] public void GetFirstByLowestScoreFromSet_ThrowsAnException_WhenKeyIsNull() { var exception = Assert.Throws( @@ -450,14 +451,14 @@ public void GetFirstByLowestScoreFromSet_ThrowsAnException_WhenKeyIsNull() Assert.Equal("key", exception.ParamName); } - [Fact, CleanDatabase] + [Fact] public void GetFirstByLowestScoreFromSet_ThrowsAnException_ToScoreIsLowerThanFromScore() { Assert.Throws( () => _connection.GetFirstByLowestScoreFromSet("key", 0, -1)); } - [Fact, CleanDatabase] + [Fact] public void GetFirstByLowestScoreFromSet_ReturnsNull_WhenTheKeyDoesNotExist() { var result = _connection.GetFirstByLowestScoreFromSet( @@ -466,7 +467,7 @@ public void GetFirstByLowestScoreFromSet_ReturnsNull_WhenTheKeyDoesNotExist() Assert.Null(result); } - [Fact, CleanDatabase] + [Fact] public void GetFirstByLowestScoreFromSet_ReturnsTheValueWithTheLowestScore() { _dbContext.JobGraph.InsertOne(new SetDto @@ -507,7 +508,7 @@ public void GetFirstByLowestScoreFromSet_ReturnsTheValueWithTheLowestScore() Assert.Equal("-1.0", result); } - [Fact, CleanDatabase] + [Fact] public void GetFirstByLowestScoreFromSet_ReturnsTheValue_WhenKeyContainsRegexSpecialChars() { var key = "some+-[regex]?-#set"; @@ -534,7 +535,7 @@ public void GetFirstByLowestScoreFromSet_ReturnsTheValue_WhenKeyContainsRegexSpe Assert.Equal("-1.0", result); } - [Fact, CleanDatabase] + [Fact] public void AnnounceServer_ThrowsAnException_WhenServerIdIsNull() { var exception = Assert.Throws( @@ -543,7 +544,7 @@ public void AnnounceServer_ThrowsAnException_WhenServerIdIsNull() Assert.Equal("serverId", exception.ParamName); } - [Fact, CleanDatabase] + [Fact] public void AnnounceServer_ThrowsAnException_WhenContextIsNull() { var exception = Assert.Throws( @@ -552,7 +553,7 @@ public void AnnounceServer_ThrowsAnException_WhenContextIsNull() Assert.Equal("context", exception.ParamName); } - [Fact, CleanDatabase] + [Fact] public void AnnounceServer_CreatesOrUpdatesARecord() { var context1 = new ServerContext @@ -580,13 +581,13 @@ public void AnnounceServer_CreatesOrUpdatesARecord() Assert.Equal(context2.WorkerCount, sameServer.WorkerCount); } - [Fact, CleanDatabase] + [Fact] public void RemoveServer_ThrowsAnException_WhenServerIdIsNull() { Assert.Throws(() => _connection.RemoveServer(null)); } - [Fact, CleanDatabase] + [Fact] public void RemoveServer_RemovesAServerRecord() { _dbContext.Server.InsertOne(new ServerDto @@ -606,14 +607,14 @@ public void RemoveServer_RemovesAServerRecord() Assert.NotEqual("Server1", server.Id, StringComparer.OrdinalIgnoreCase); } - [Fact, CleanDatabase] + [Fact] public void Heartbeat_ThrowsAnException_WhenServerIdIsNull() { Assert.Throws( () => _connection.Heartbeat(null)); } - [Fact, CleanDatabase] + [Fact] public void Heartbeat_ThrowsBackgroundServerGoneException_WhenGivenServerDoesNotExist() { var serverId = Guid.NewGuid().ToString(); @@ -622,7 +623,7 @@ public void Heartbeat_ThrowsBackgroundServerGoneException_WhenGivenServerDoesNot () => _connection.Heartbeat(serverId)); } - [Fact, CleanDatabase] + [Fact] public void Heartbeat_UpdatesLastHeartbeat_OfTheServerWithGivenId() { _dbContext.Server.InsertOne(new ServerDto @@ -647,14 +648,14 @@ public void Heartbeat_UpdatesLastHeartbeat_OfTheServerWithGivenId() Assert.Equal(2012, servers["server2"].Value.Year); } - [Fact, CleanDatabase] + [Fact] public void RemoveTimedOutServers_ThrowsAnException_WhenTimeOutIsNegative() { Assert.Throws( () => _connection.RemoveTimedOutServers(TimeSpan.FromMinutes(-5))); } - [Fact, CleanDatabase] + [Fact] public void RemoveTimedOutServers_DoItsWorkPerfectly() { var id1 = ObjectId.GenerateNewId(); @@ -678,13 +679,13 @@ public void RemoveTimedOutServers_DoItsWorkPerfectly() Assert.Equal("server2", liveServer.Id); } - [Fact, CleanDatabase] + [Fact] public void GetAllItemsFromSet_ThrowsAnException_WhenKeyIsNull() { Assert.Throws(() => _connection.GetAllItemsFromSet(null)); } - [Fact, CleanDatabase] + [Fact] public void GetAllItemsFromSet_ReturnsEmptyCollection_WhenKeyDoesNotExist() { var result = _connection.GetAllItemsFromSet("some-set"); @@ -693,7 +694,7 @@ public void GetAllItemsFromSet_ReturnsEmptyCollection_WhenKeyDoesNotExist() Assert.Empty(result); } - [Fact, CleanDatabase] + [Fact] public void GetAllItemsFromSet_ReturnsAllItems_InCorrectOrder() { // Arrange @@ -754,8 +755,8 @@ public void GetAllItemsFromSet_ReturnsAllItems_InCorrectOrder() Assert.Contains("2", result); Assert.Equal(new[] { "1", "2", "4", "5", "6" }, result); } - - [Fact, CleanDatabase] + + [Fact] public void GetAllItemsFromSet_ReturnsAllItems_WithCorrectValues() { // Arrange @@ -773,7 +774,7 @@ public void GetAllItemsFromSet_ReturnsAllItems_WithCorrectValues() Assert.Equal(new[] { "11:22", "33" }, result); } - [Fact, CleanDatabase] + [Fact] public void GetAllItemsFromSet_ReturnsAllItems_WhenKeyContainsRegexSpecialChars() { var key = "some+-[regex]?-#set"; @@ -792,7 +793,7 @@ public void GetAllItemsFromSet_ReturnsAllItems_WhenKeyContainsRegexSpecialChars( Assert.Equal(new[] { "11:22", "33" }, result); } - [Fact, CleanDatabase] + [Fact] public void SetRangeInHash_ThrowsAnException_WhenKeyIsNull() { var exception = Assert.Throws( @@ -801,7 +802,7 @@ public void SetRangeInHash_ThrowsAnException_WhenKeyIsNull() Assert.Equal("key", exception.ParamName); } - [Fact, CleanDatabase] + [Fact] public void SetRangeInHash_ThrowsAnException_WhenKeyValuePairsArgumentIsNull() { var exception = Assert.Throws( @@ -810,7 +811,7 @@ public void SetRangeInHash_ThrowsAnException_WhenKeyValuePairsArgumentIsNull() Assert.Equal("keyValuePairs", exception.ParamName); } - [Fact, CleanDatabase] + [Fact] public void SetRangeInHash_MergesAllRecords() { _connection.SetRangeInHash("some-hash", new Dictionary @@ -833,20 +834,20 @@ public void SetRangeInHash_MergesAllRecords() Assert.Equal("Value2", result["Key2"]); } - [Fact, CleanDatabase] + [Fact] public void GetAllEntriesFromHash_ThrowsAnException_WhenKeyIsNull() { Assert.Throws(() => _connection.GetAllEntriesFromHash(null)); } - [Fact, CleanDatabase] + [Fact] public void GetAllEntriesFromHash_ReturnsNull_IfHashDoesNotExist() { var result = _connection.GetAllEntriesFromHash("some-hash"); Assert.Null(result); } - [Fact, CleanDatabase] + [Fact] public void GetAllEntriesFromHash_ReturnsAllKeysAndTheirValues() { // Arrange @@ -882,20 +883,20 @@ public void GetAllEntriesFromHash_ReturnsAllKeysAndTheirValues() Assert.Equal("Value2", result["Key2"]); } - [Fact, CleanDatabase] + [Fact] public void GetSetCount_ThrowsAnException_WhenKeyIsNull() { Assert.Throws(() => _connection.GetSetCount(null)); } - [Fact, CleanDatabase] + [Fact] public void GetSetCount_ReturnsZero_WhenSetDoesNotExist() { var result = _connection.GetSetCount("my-set"); Assert.Equal(0, result); } - [Fact, CleanDatabase] + [Fact] public void GetSetCount_ReturnsNumberOfElements_InASet() { _dbContext.JobGraph.InsertOne(new SetDto @@ -925,7 +926,7 @@ public void GetSetCount_ReturnsNumberOfElements_InASet() Assert.Equal(2, result); } - [Fact, CleanDatabase] + [Fact] public void GetSetCount_ReturnsNumberOfElements_InASet_WhenKeyContainsRegexSpecialChars() { var key = "some+-[regex]?-#set"; @@ -950,13 +951,13 @@ public void GetSetCount_ReturnsNumberOfElements_InASet_WhenKeyContainsRegexSpeci Assert.Equal(2, result); } - [Fact, CleanDatabase] + [Fact] public void GetRangeFromSet_ThrowsAnException_WhenKeyIsNull() { Assert.Throws(() => _connection.GetRangeFromSet(null, 0, 1)); } - [Fact, CleanDatabase] + [Fact] public void GetRangeFromSet_ReturnsPagedElementsInCorrectOrder() { _dbContext.JobGraph.InsertOne(new SetDto @@ -1018,7 +1019,7 @@ public void GetRangeFromSet_ReturnsPagedElementsInCorrectOrder() Assert.Equal(new[] { "2", "3", "4", "6" }, result); } - [Fact, CleanDatabase] + [Fact] public void GetRangeFromSet_ReturnsPagedElementsInCorrectOrder_WhenKeyContainsRegexSpecialChars() { var key = "some+-[regex]?-#set"; @@ -1073,20 +1074,20 @@ public void GetRangeFromSet_ReturnsPagedElementsInCorrectOrder_WhenKeyContainsRe Assert.Equal(new[] { "2", "3", "4", "6" }, result); } - [Fact, CleanDatabase] + [Fact] public void GetSetTtl_ThrowsAnException_WhenKeyIsNull() { Assert.Throws(() => _connection.GetSetTtl(null)); } - [Fact, CleanDatabase] + [Fact] public void GetSetTtl_ReturnsNegativeValue_WhenSetDoesNotExist() { var result = _connection.GetSetTtl("my-set"); Assert.True(result < TimeSpan.Zero, $"{result} < {TimeSpan.Zero}"); } - [Fact, CleanDatabase] + [Fact] public void GetSetTtl_ReturnsExpirationTime_OfAGivenSet() { // Arrange @@ -1116,7 +1117,7 @@ public void GetSetTtl_ReturnsExpirationTime_OfAGivenSet() Assert.True(result < TimeSpan.FromMinutes(61)); } - [Fact, CleanDatabase] + [Fact] public void GetSetTtl_ReturnsExpirationTime_OfAGivenSet_WhenKeyContainsRegexSpecialChars() { var key = "some+-[regex]?-#set"; @@ -1139,20 +1140,20 @@ public void GetSetTtl_ReturnsExpirationTime_OfAGivenSet_WhenKeyContainsRegexSpec Assert.True(result < TimeSpan.FromMinutes(61)); } - [Fact, CleanDatabase] + [Fact] public void GetCounter_ThrowsAnException_WhenKeyIsNull() { Assert.Throws(() => _connection.GetCounter(null)); } - [Fact, CleanDatabase] + [Fact] public void GetCounter_ReturnsZero_WhenKeyDoesNotExist() { var result = _connection.GetCounter("my-counter"); Assert.Equal(0, result); } - [Fact, CleanDatabase] + [Fact] public void GetCounter_ReturnsSumOfValues_InCounterTable() { // Arrange @@ -1168,7 +1169,7 @@ public void GetCounter_ReturnsSumOfValues_InCounterTable() Key = "counter-2", Value = 1L }.Serialize()); - + // Act var result = _connection.GetCounter("counter-1"); @@ -1176,20 +1177,20 @@ public void GetCounter_ReturnsSumOfValues_InCounterTable() Assert.Equal(2, result); } - [Fact, CleanDatabase] + [Fact] public void GetHashCount_ThrowsAnException_WhenKeyIsNull() { Assert.Throws(() => _connection.GetHashCount(null)); } - [Fact, CleanDatabase] + [Fact] public void GetHashCount_ReturnsZero_WhenKeyDoesNotExist() { var result = _connection.GetHashCount("my-hash"); Assert.Equal(0, result); } - [Fact, CleanDatabase] + [Fact] public void GetHashCount_ReturnsNumber_OfHashFields() { // Arrange @@ -1200,7 +1201,7 @@ public void GetHashCount_ReturnsNumber_OfHashFields() { ["field-1"] = "field-1-value", ["field-2"] = "field-2-value", - + }, Key = "hash-1", }.Serialize()); @@ -1211,7 +1212,7 @@ public void GetHashCount_ReturnsNumber_OfHashFields() Fields = new Dictionary { ["field-1"] = "field-1-value", - + }, }.Serialize()); @@ -1222,20 +1223,20 @@ public void GetHashCount_ReturnsNumber_OfHashFields() Assert.Equal(2, result); } - [Fact, CleanDatabase] + [Fact] public void GetHashTtl_ThrowsAnException_WhenKeyIsNull() { Assert.Throws(() => _connection.GetHashTtl(null)); } - [Fact, CleanDatabase] + [Fact] public void GetHashTtl_ReturnsNegativeValue_WhenHashDoesNotExist() { var result = _connection.GetHashTtl("my-hash"); Assert.True(result < TimeSpan.Zero); } - [Fact, CleanDatabase] + [Fact] public void GetHashTtl_ReturnsExpirationTimeForHash() { // Arrange @@ -1246,7 +1247,7 @@ public void GetHashTtl_ReturnsExpirationTimeForHash() Fields = new Dictionary { ["field-1"] = "field-1-value", - + }, ExpireAt = DateTime.UtcNow.AddHours(1) }.Serialize()); @@ -1257,7 +1258,7 @@ public void GetHashTtl_ReturnsExpirationTimeForHash() Fields = new Dictionary { ["field-1"] = "field-1-value", - + }, ExpireAt = null }.Serialize()); @@ -1270,7 +1271,7 @@ public void GetHashTtl_ReturnsExpirationTimeForHash() Assert.True(result < TimeSpan.FromMinutes(61)); } - [Fact, CleanDatabase] + [Fact] public void GetValueFromHash_ThrowsAnException_WhenKeyIsNull() { var exception = Assert.Throws(() => _connection.GetValueFromHash(null, "name")); @@ -1278,7 +1279,7 @@ public void GetValueFromHash_ThrowsAnException_WhenKeyIsNull() Assert.Equal("key", exception.ParamName); } - [Fact, CleanDatabase] + [Fact] public void GetValueFromHash_ThrowsAnException_WhenNameIsNull() { var exception = Assert.Throws(() => _connection.GetValueFromHash("key", null)); @@ -1286,14 +1287,14 @@ public void GetValueFromHash_ThrowsAnException_WhenNameIsNull() Assert.Equal("name", exception.ParamName); } - [Fact, CleanDatabase] + [Fact] public void GetValueFromHash_ReturnsNull_WhenHashDoesNotExist() { var result = _connection.GetValueFromHash("my-hash", "name"); Assert.Null(result); } - [Fact, CleanDatabase] + [Fact] public void GetValueFromHash_ReturnsValue_OfAGivenField() { // Arrange @@ -1324,20 +1325,20 @@ public void GetValueFromHash_ReturnsValue_OfAGivenField() Assert.Equal("1", result); } - [Fact, CleanDatabase] + [Fact] public void GetListCount_ThrowsAnException_WhenKeyIsNull() { Assert.Throws(() => _connection.GetListCount(null)); } - [Fact, CleanDatabase] + [Fact] public void GetListCount_ReturnsZero_WhenListDoesNotExist() { var result = _connection.GetListCount("my-list"); Assert.Equal(0, result); } - [Fact, CleanDatabase] + [Fact] public void GetListCount_ReturnsTheNumberOfListElements() { // Arrange @@ -1364,20 +1365,20 @@ public void GetListCount_ReturnsTheNumberOfListElements() Assert.Equal(2, result); } - [Fact, CleanDatabase] + [Fact] public void GetListTtl_ThrowsAnException_WhenKeyIsNull() { Assert.Throws(() => _connection.GetListTtl(null)); } - [Fact, CleanDatabase] + [Fact] public void GetListTtl_ReturnsNegativeValue_WhenListDoesNotExist() { var result = _connection.GetListTtl("my-list"); Assert.True(result < TimeSpan.Zero); } - [Fact, CleanDatabase] + [Fact] public void GetListTtl_ReturnsExpirationTimeForList() { // Arrange @@ -1402,7 +1403,7 @@ public void GetListTtl_ReturnsExpirationTimeForList() Assert.True(result < TimeSpan.FromMinutes(61)); } - [Fact, CleanDatabase] + [Fact] public void GetRangeFromList_ThrowsAnException_WhenKeyIsNull() { var exception = Assert.Throws(() => _connection.GetRangeFromList(null, 0, 1)); @@ -1410,14 +1411,14 @@ public void GetRangeFromList_ThrowsAnException_WhenKeyIsNull() Assert.Equal("key", exception.ParamName); } - [Fact, CleanDatabase] + [Fact] public void GetRangeFromList_ReturnsAnEmptyList_WhenListDoesNotExist() { var result = _connection.GetRangeFromList("my-list", 0, 1); Assert.Empty(result); } - [Fact, CleanDatabase] + [Fact] public void GetRangeFromList_ReturnsAllEntries_WithinGivenBounds() { // Arrange @@ -1459,7 +1460,7 @@ public void GetRangeFromList_ReturnsAllEntries_WithinGivenBounds() Assert.Equal(new[] { "4", "3" }, result); } - [Fact, CleanDatabase] + [Fact] public void GetRangeFromList_ReturnsAllEntriesInCorrectOrder() { // Arrange @@ -1505,20 +1506,20 @@ public void GetRangeFromList_ReturnsAllEntriesInCorrectOrder() Assert.Equal(new[] { "4", "3", "2", "1" }, result); } - [Fact, CleanDatabase] + [Fact] public void GetAllItemsFromList_ThrowsAnException_WhenKeyIsNull() { Assert.Throws(() => _connection.GetAllItemsFromList(null)); } - [Fact, CleanDatabase] + [Fact] public void GetAllItemsFromList_ReturnsAnEmptyList_WhenListDoesNotExist() { var result = _connection.GetAllItemsFromList("my-list"); Assert.Empty(result); } - [Fact, CleanDatabase] + [Fact] public void GetAllItemsFromList_ReturnsAllItemsFromAGivenList_InCorrectOrder() { // Arrange diff --git a/src/Hangfire.Mongo.Tests/MongoDiscriminatorTests.cs b/src/Hangfire.Mongo.Tests/MongoDiscriminatorTests.cs index 517ad178..fe91a50b 100644 --- a/src/Hangfire.Mongo.Tests/MongoDiscriminatorTests.cs +++ b/src/Hangfire.Mongo.Tests/MongoDiscriminatorTests.cs @@ -14,14 +14,14 @@ namespace Hangfire.Mongo.Tests { + [Collection("Database")] public class MongoDiscriminatorTests { private readonly HangfireDbContext _dbContext; - public MongoDiscriminatorTests() + public MongoDiscriminatorTests(MongoDbFixture fixture) { - _dbContext = ConnectionUtils.CreateDbContext(); - + _dbContext = fixture.CreateDbContext(); } [Fact] diff --git a/src/Hangfire.Mongo.Tests/MongoDistributedLockFacts.cs b/src/Hangfire.Mongo.Tests/MongoDistributedLockFacts.cs index bc5a2d23..a415db85 100644 --- a/src/Hangfire.Mongo.Tests/MongoDistributedLockFacts.cs +++ b/src/Hangfire.Mongo.Tests/MongoDistributedLockFacts.cs @@ -16,7 +16,14 @@ namespace Hangfire.Mongo.Tests [Collection("Database")] public class MongoDistributedLockFacts { - private readonly HangfireDbContext _database = ConnectionUtils.CreateDbContext(); + private readonly HangfireDbContext _database; + + public MongoDistributedLockFacts(MongoDbFixture fixture) + { + fixture.CleanDatabase(); + _database = fixture.CreateDbContext(); + } + [Fact] public void Ctor_ThrowsAnException_WhenResourceIsNull() { @@ -36,7 +43,7 @@ public void Ctor_ThrowsAnException_WhenConnectionIsNull() Assert.Equal("dbContext", exception.ParamName); } - [Fact, CleanDatabase] + [Fact] public void Ctor_SetLock_WhenResourceIsNotLocked() { var lock1 = new MongoDistributedLock("resource1", TimeSpan.Zero, _database, new MongoStorageOptions()); @@ -48,14 +55,14 @@ public void Ctor_SetLock_WhenResourceIsNotLocked() } } - [Fact, CleanDatabase] + [Fact] public void Ctor_SetReleaseLock_WhenResourceIsNotLocked() { var lock1 = new MongoDistributedLock("resource1", TimeSpan.Zero, _database, new MongoStorageOptions()); var filter = new BsonDocument(nameof(DistributedLockDto.Resource), "resource1"); using (lock1.AcquireLock()) { - + var locksCount = _database.DistributedLock.Count(filter); Assert.Equal(1, locksCount); } @@ -64,14 +71,14 @@ public void Ctor_SetReleaseLock_WhenResourceIsNotLocked() Assert.Equal(0, locksCountAfter); } - [Fact, CleanDatabase] + [Fact] public void Ctor_AcquireLockWithinSameThread_WhenResourceIsLocked() { var lock1 = new MongoDistributedLock("resource1", TimeSpan.Zero, _database, new MongoStorageOptions()); var filter = new BsonDocument(nameof(DistributedLockDto.Resource), "resource1"); using (lock1.AcquireLock()) { - + var locksCount = _database.DistributedLock.Count(filter); Assert.Equal(1, locksCount); @@ -84,7 +91,7 @@ public void Ctor_AcquireLockWithinSameThread_WhenResourceIsLocked() } } - [Fact, CleanDatabase] + [Fact] public void Ctor_ThrowsAnException_WhenResourceIsLocked() { var lock1 = new MongoDistributedLock("resource1", TimeSpan.Zero, _database, new MongoStorageOptions()); @@ -109,7 +116,7 @@ public void Ctor_ThrowsAnException_WhenResourceIsLocked() } } - [Fact, CleanDatabase] + [Fact] public void Ctor_WaitForLock_SignaledAtLockRelease() { var t = new Thread(() => @@ -147,7 +154,7 @@ public void Ctor_ThrowsAnException_WhenOptionsIsNull() Assert.Equal("storageOptions", exception.ParamName); } - [Fact, CleanDatabase] + [Fact] public void Ctor_SetLockExpireAtWorks_WhenResourceIsNotLocked() { var lock1 = new MongoDistributedLock("resource1", TimeSpan.Zero, _database, @@ -169,7 +176,7 @@ public void Ctor_SetLockExpireAtWorks_WhenResourceIsNotLocked() } } - [Fact, CleanDatabase] + [Fact] public void Ctor_AcquireLock_WhenLockExpired() { // simulate situation when lock was not disposed correctly (app crash) and there is no heartbeats to prolong ExpireAt value diff --git a/src/Hangfire.Mongo.Tests/MongoFetchedJobFacts.cs b/src/Hangfire.Mongo.Tests/MongoFetchedJobFacts.cs index 6ddcb9b4..49fd60d9 100644 --- a/src/Hangfire.Mongo.Tests/MongoFetchedJobFacts.cs +++ b/src/Hangfire.Mongo.Tests/MongoFetchedJobFacts.cs @@ -15,9 +15,15 @@ public class MongoFetchedJobFacts { private static readonly ObjectId JobId = ObjectId.GenerateNewId(); private const string Queue = "queue"; - private MongoStorageOptions _mongoStorageOptions = new MongoStorageOptions(); + private readonly MongoStorageOptions _mongoStorageOptions = new MongoStorageOptions(); private readonly DateTime _fetchedAt = DateTime.UtcNow; - private readonly HangfireDbContext _dbContext = ConnectionUtils.CreateDbContext(); + private readonly HangfireDbContext _dbContext; + + public MongoFetchedJobFacts(MongoDbFixture fixture) + { + fixture.CleanDatabase(); + _dbContext = fixture.CreateDbContext(); + } [Fact] public void Ctor_ThrowsAnException_WhenConnectionIsNull() @@ -46,7 +52,7 @@ public void Ctor_CorrectlySets_AllInstanceProperties() Assert.Equal(Queue, fetchedJob.Queue); } - [Fact, CleanDatabase] + [Fact] public void RemoveFromQueue_ReallyDeletesTheJobFromTheQueue() { // Arrange @@ -68,7 +74,7 @@ public void RemoveFromQueue_ReallyDeletesTheJobFromTheQueue() Assert.Equal(0, count); } - [Fact, CleanDatabase] + [Fact] public void RemoveFromQueue_DoesNotDelete_UnrelatedJobs() { // Arrange @@ -91,7 +97,7 @@ public void RemoveFromQueue_DoesNotDelete_UnrelatedJobs() Assert.Equal(3, count); } - [Fact, CleanDatabase] + [Fact] public void Requeue_SetsFetchedAtValueToNull() { // Arrange @@ -104,12 +110,12 @@ public void Requeue_SetsFetchedAtValueToNull() processingJob.Requeue(); // Assert - var record = new JobDto( + var record = new JobDto( _dbContext.JobGraph.Find(new BsonDocument("_t", nameof(JobDto))).ToList().Single()); Assert.Null(record.FetchedAt); } - [Fact, CleanDatabase] + [Fact] public void Dispose_SetsFetchedAtValueToNull_IfThereWereNoCallsToComplete() { // Arrange diff --git a/src/Hangfire.Mongo.Tests/MongoJobQueueFacts.cs b/src/Hangfire.Mongo.Tests/MongoJobQueueFacts.cs index 179e01ce..83e4b241 100644 --- a/src/Hangfire.Mongo.Tests/MongoJobQueueFacts.cs +++ b/src/Hangfire.Mongo.Tests/MongoJobQueueFacts.cs @@ -18,7 +18,8 @@ public class MongoJobQueueFacts private readonly Mock _jobQueueSemaphoreMock; private readonly HangfireDbContext _hangfireDbContext; - public MongoJobQueueFacts() + + public MongoJobQueueFacts(MongoDbFixture fixture) { _jobQueueSemaphoreMock = new Mock(MockBehavior.Strict); var queue = "default"; @@ -26,8 +27,10 @@ public MongoJobQueueFacts() _jobQueueSemaphoreMock.Setup(s => s.WaitAny(DefaultQueues, It.IsAny(), It.IsAny(), out queue, out timedOut)) .Returns(true); - _hangfireDbContext = ConnectionUtils.CreateDbContext(); + fixture.CleanDatabase(); + _hangfireDbContext = fixture.CreateDbContext(); } + [Fact] public void Ctor_ThrowsAnException_WhenDbContextIsNull() { @@ -46,7 +49,7 @@ public void Ctor_ThrowsAnException_WhenOptionsValueIsNull() Assert.Equal("storageOptions", exception.ParamName); } - [Fact, CleanDatabase] + [Fact] public void Dequeue_ShouldThrowAnException_WhenQueuesCollectionIsNull() { var queue =new MongoJobFetcher(_hangfireDbContext, new MongoStorageOptions(), _jobQueueSemaphoreMock.Object); @@ -57,7 +60,7 @@ public void Dequeue_ShouldThrowAnException_WhenQueuesCollectionIsNull() Assert.Equal("queues", exception.ParamName); } - [Fact, CleanDatabase] + [Fact] public void Dequeue_ShouldThrowAnException_WhenQueuesCollectionIsEmpty() { var queue =new MongoJobFetcher(_hangfireDbContext, new MongoStorageOptions(), _jobQueueSemaphoreMock.Object); @@ -79,7 +82,7 @@ public void Dequeue_ThrowsOperationCanceled_WhenCancellationTokenIsSetAtTheBegin queue.FetchNextJob(DefaultQueues, cts.Token)); } - [Fact, CleanDatabase] + [Fact] public void Dequeue_ShouldWaitIndefinitely_WhenThereAreNoJobs() { var cts = new CancellationTokenSource(200); @@ -89,7 +92,7 @@ public void Dequeue_ShouldWaitIndefinitely_WhenThereAreNoJobs() queue.FetchNextJob(DefaultQueues, cts.Token)); } - [Fact, CleanDatabase] + [Fact] public void Dequeue_ShouldFetchAJob_FromTheSpecifiedQueue() { // Arrange @@ -102,18 +105,18 @@ public void Dequeue_ShouldFetchAJob_FromTheSpecifiedQueue() var token = CreateTimingOutCancellationToken(); var queue =new MongoJobFetcher(_hangfireDbContext, new MongoStorageOptions(), _jobQueueSemaphoreMock.Object); _jobQueueSemaphoreMock.Setup(m => m.WaitNonBlock("default")).Returns(true); - + // Act MongoFetchedJob payload = (MongoFetchedJob)queue.FetchNextJob(DefaultQueues, token); // Assert Assert.Equal(job.Id.ToString(), payload.JobId); Assert.Equal("default", payload.Queue); - + _jobQueueSemaphoreMock.Verify(m => m.WaitNonBlock("default"), Times.Once); } - [Fact, CleanDatabase] + [Fact] public void Dequeue_ShouldLeaveJobInTheQueue_ButSetItsFetchedAtValue() { // Arrange @@ -150,7 +153,7 @@ public void Dequeue_ShouldLeaveJobInTheQueue_ButSetItsFetchedAtValue() _jobQueueSemaphoreMock.Verify(m => m.WaitNonBlock("default"), Times.Once); } - [Fact, CleanDatabase] + [Fact] public void Dequeue_ShouldFetchATimedOutJobs_FromTheSpecifiedQueue() { // Arrange @@ -168,7 +171,7 @@ public void Dequeue_ShouldFetchATimedOutJobs_FromTheSpecifiedQueue() { InvisibilityTimeout = TimeSpan.FromMinutes(30) }; - + _jobQueueSemaphoreMock.Setup(m => m.WaitNonBlock("default")).Returns(true); var queue =new MongoJobFetcher(_hangfireDbContext, options, _jobQueueSemaphoreMock.Object); @@ -179,8 +182,8 @@ public void Dequeue_ShouldFetchATimedOutJobs_FromTheSpecifiedQueue() Assert.NotEmpty(payload.JobId); _jobQueueSemaphoreMock.Verify(m => m.WaitNonBlock("default"), Times.Once); } - - [Fact, CleanDatabase] + + [Fact] public void Dequeue_NoInvisibilityTimeout_WaitsForever() { // Arrange @@ -195,7 +198,7 @@ public void Dequeue_NoInvisibilityTimeout_WaitsForever() _hangfireDbContext.JobGraph.InsertOne(job.Serialize()); var options = new MongoStorageOptions(); - + _jobQueueSemaphoreMock.Setup(m => m.WaitNonBlock("default")).Returns(true); var queue =new MongoJobFetcher(_hangfireDbContext, options, _jobQueueSemaphoreMock.Object); @@ -210,7 +213,7 @@ public void Dequeue_NoInvisibilityTimeout_WaitsForever() _jobQueueSemaphoreMock.Verify(m => m.WaitNonBlock("default"), Times.Never); } - [Fact, CleanDatabase] + [Fact] public void Dequeue_ShouldSetFetchedAt_OnlyForTheFetchedJob() { // Arrange @@ -233,7 +236,7 @@ public void Dequeue_ShouldSetFetchedAt_OnlyForTheFetchedJob() _hangfireDbContext.JobGraph.InsertOne(job2.Serialize()); var queue =new MongoJobFetcher(_hangfireDbContext, new MongoStorageOptions(), _jobQueueSemaphoreMock.Object); - + _jobQueueSemaphoreMock.Setup(m => m.WaitNonBlock("default")).Returns(true); // Act @@ -256,7 +259,7 @@ public void Dequeue_ShouldSetFetchedAt_OnlyForTheFetchedJob() _jobQueueSemaphoreMock.Verify(m => m.WaitNonBlock("default"), Times.Once); } - [Fact, CleanDatabase] + [Fact] public void Dequeue_ShouldFetchJobs_OnlyFromSpecifiedQueues() { var job1 = new JobDto @@ -270,11 +273,11 @@ public void Dequeue_ShouldFetchJobs_OnlyFromSpecifiedQueues() var queue =new MongoJobFetcher(_hangfireDbContext, new MongoStorageOptions(), _jobQueueSemaphoreMock.Object); - + Assert.ThrowsAny(() => queue.FetchNextJob(DefaultQueues, CreateTimingOutCancellationToken())); } - [Fact, CleanDatabase] + [Fact] public void Dequeue_ShouldFetchJobs_FromMultipleQueuesBasedOnQueuePriority() { var criticalJob = new JobDto @@ -299,7 +302,7 @@ public void Dequeue_ShouldFetchJobs_FromMultipleQueuesBasedOnQueuePriority() var queue =new MongoJobFetcher(_hangfireDbContext, new MongoStorageOptions(), _jobQueueSemaphoreMock.Object); _jobQueueSemaphoreMock.Setup(m => m.WaitNonBlock("critical")).Returns(true); _jobQueueSemaphoreMock.Setup(m => m.WaitNonBlock("default")).Returns(true); - + var critical = (MongoFetchedJob)queue.FetchNextJob( new[] { "critical", "default" }, CreateTimingOutCancellationToken()); @@ -313,7 +316,7 @@ public void Dequeue_ShouldFetchJobs_FromMultipleQueuesBasedOnQueuePriority() Assert.NotNull(@default.JobId); Assert.Equal("default", @default.Queue); - + _jobQueueSemaphoreMock.Verify(m => m.WaitNonBlock("critical"), Times.Once); _jobQueueSemaphoreMock.Verify(m => m.WaitNonBlock("default"), Times.Once); } @@ -321,7 +324,7 @@ public void Dequeue_ShouldFetchJobs_FromMultipleQueuesBasedOnQueuePriority() private static CancellationToken CreateTimingOutCancellationToken(TimeSpan timeSpan = default(TimeSpan)) { timeSpan = timeSpan == default(TimeSpan) ? TimeSpan.FromSeconds(10) : timeSpan; - + var source = new CancellationTokenSource(timeSpan); return source.Token; } diff --git a/src/Hangfire.Mongo.Tests/MongoMonitoringApiFacts.cs b/src/Hangfire.Mongo.Tests/MongoMonitoringApiFacts.cs index e7549cff..0e4cc1eb 100644 --- a/src/Hangfire.Mongo.Tests/MongoMonitoringApiFacts.cs +++ b/src/Hangfire.Mongo.Tests/MongoMonitoringApiFacts.cs @@ -23,12 +23,14 @@ public class MongoMonitoringApiFacts private readonly HangfireDbContext _database; private readonly MongoMonitoringApi _monitoringApi; - public MongoMonitoringApiFacts() + public MongoMonitoringApiFacts(MongoDbFixture fixture) { - _database = ConnectionUtils.CreateDbContext(); + fixture.CleanDatabase(); + _database = fixture.CreateDbContext(); _monitoringApi = new MongoMonitoringApi(_database); } - [Fact, CleanDatabase] + + [Fact] public void GetStatistics_ReturnsZero_WhenNoJobsExist() { var result = _monitoringApi.GetStatistics(); @@ -38,7 +40,7 @@ public void GetStatistics_ReturnsZero_WhenNoJobsExist() Assert.Equal(0, result.Scheduled); } - [Fact, CleanDatabase] + [Fact] public void GetStatistics_ReturnsExpectedCounts_WhenJobsExist() { CreateJobInState(_database, ObjectId.GenerateNewId(1), EnqueuedState.StateName); @@ -54,8 +56,8 @@ public void GetStatistics_ReturnsExpectedCounts_WhenJobsExist() Assert.Equal(1, result.Processing); Assert.Equal(2, result.Scheduled); } - - [Fact, CleanDatabase] + + [Fact] public void GetStatistics_RecurringJob_CountsSets() { const string setJson = @" @@ -71,19 +73,19 @@ public void GetStatistics_RecurringJob_CountsSets() .Database .GetCollection(_database.JobGraph.CollectionNamespace.CollectionName) .InsertOne(BsonDocument.Parse(setJson)); - + var result = _monitoringApi.GetStatistics(); Assert.Equal(1, result.Recurring); } - [Fact, CleanDatabase] + [Fact] public void JobDetails_ReturnsNull_WhenThereIsNoSuchJob() { var result = _monitoringApi.JobDetails(ObjectId.GenerateNewId().ToString()); Assert.Null(result); } - [Fact, CleanDatabase] + [Fact] public void JobDetails_ReturnsResult_WhenJobExists() { var job1 = CreateJobInState(_database, ObjectId.GenerateNewId(1), EnqueuedState.StateName); @@ -97,7 +99,7 @@ public void JobDetails_ReturnsResult_WhenJobExists() Assert.True(result.CreatedAt < DateTime.UtcNow.AddMinutes(1)); } - [Fact, CleanDatabase] + [Fact] public void EnqueuedJobs_ReturnsEmpty_WhenThereIsNoJobs() { var resultList = _monitoringApi.EnqueuedJobs(DefaultQueue, From, PerPage); @@ -105,7 +107,7 @@ public void EnqueuedJobs_ReturnsEmpty_WhenThereIsNoJobs() Assert.Empty(resultList); } - [Fact, CleanDatabase] + [Fact] public void EnqueuedJobs_ReturnsSingleJob_WhenOneJobExistsThatIsNotFetched() { CreateJobInState(_database, ObjectId.GenerateNewId(1), EnqueuedState.StateName); @@ -114,7 +116,7 @@ public void EnqueuedJobs_ReturnsSingleJob_WhenOneJobExistsThatIsNotFetched() Assert.Single(resultList); } - [Fact, CleanDatabase] + [Fact] public void EnqueuedJobs_ReturnsEmpty_WhenOneJobExistsThatIsFetched() { CreateJobInState(_database, ObjectId.GenerateNewId(1), FetchedStateName); @@ -123,7 +125,7 @@ public void EnqueuedJobs_ReturnsEmpty_WhenOneJobExistsThatIsFetched() Assert.Empty(resultList); } - [Fact, CleanDatabase] + [Fact] public void EnqueuedJobs_ReturnsUnfetchedJobsOnly_WhenMultipleJobsExistsInFetchedAndUnfetchedStates() { CreateJobInState(_database, ObjectId.GenerateNewId(1), EnqueuedState.StateName); @@ -135,7 +137,7 @@ public void EnqueuedJobs_ReturnsUnfetchedJobsOnly_WhenMultipleJobsExistsInFetche Assert.Equal(2, resultList.Count); } - [Fact, CleanDatabase] + [Fact] public void FetchedJobs_ReturnsEmpty_WhenThereIsNoJobs() { var resultList = _monitoringApi.FetchedJobs(DefaultQueue, From, PerPage); @@ -143,7 +145,7 @@ public void FetchedJobs_ReturnsEmpty_WhenThereIsNoJobs() Assert.Empty(resultList); } - [Fact, CleanDatabase] + [Fact] public void FetchedJobs_ReturnsSingleJob_WhenOneJobExistsThatIsFetched() { CreateJobInState(_database, ObjectId.GenerateNewId(1), FetchedStateName); @@ -152,7 +154,7 @@ public void FetchedJobs_ReturnsSingleJob_WhenOneJobExistsThatIsFetched() Assert.Single(resultList); } - [Fact, CleanDatabase] + [Fact] public void FetchedJobs_ReturnsEmpty_WhenOneJobExistsThatIsNotFetched() { CreateJobInState(_database, ObjectId.GenerateNewId(1), EnqueuedState.StateName); @@ -161,7 +163,7 @@ public void FetchedJobs_ReturnsEmpty_WhenOneJobExistsThatIsNotFetched() Assert.Empty(resultList); } - [Fact, CleanDatabase] + [Fact] public void FetchedJobs_ReturnsFetchedJobsOnly_WhenMultipleJobsExistsInFetchedAndUnfetchedStates() { CreateJobInState(_database, ObjectId.GenerateNewId(1), FetchedStateName); @@ -173,7 +175,7 @@ public void FetchedJobs_ReturnsFetchedJobsOnly_WhenMultipleJobsExistsInFetchedAn Assert.Equal(2, resultList.Count); } - [Fact, CleanDatabase] + [Fact] public void ProcessingJobs_ReturnsProcessingJobsOnly_WhenMultipleJobsExistsInProcessingSucceededAndEnqueuedState() { CreateJobInState(_database, ObjectId.GenerateNewId(1), ProcessingState.StateName); @@ -206,7 +208,7 @@ public void ProcessingJobs_ReturnsProcessingJobsOnly_WhenMultipleJobsExistsInPro - [Fact, CleanDatabase] + [Fact] public void ProcessingJobs_ReturnsLatestStateHistory_WhenJobRequeued() { var oldServerId = "oldserverid"; @@ -234,7 +236,7 @@ public void ProcessingJobs_ReturnsLatestStateHistory_WhenJobRequeued() jobDto.StateHistory = new[] { firstProcessingState, latestProcessingState }; return jobDto; }); - + var resultList = _monitoringApi.ProcessingJobs(From, PerPage); Assert.Single(resultList); @@ -242,7 +244,7 @@ public void ProcessingJobs_ReturnsLatestStateHistory_WhenJobRequeued() Assert.Equal(newStartTime, resultList[0].Value.StartedAt); } - [Fact, CleanDatabase] + [Fact] public void FailedJobs_ReturnsFailedJobs_InDescendingOrder() { var failedJob0 = CreateJobInState(_database, ObjectId.GenerateNewId(1), FailedState.StateName); @@ -255,86 +257,86 @@ public void FailedJobs_ReturnsFailedJobs_InDescendingOrder() Assert.Equal(failedJob1.Id.ToString(), resultList[1].Key); Assert.Equal(failedJob2.Id.ToString(), resultList[0].Key); } - - [Fact, CleanDatabase] + + [Fact] public void SucceededByDatesCount_ReturnsSuccededJobs_ForLastWeek() { var date = DateTime.UtcNow.Date; var succededCount = 10L; - + _database.JobGraph.InsertOne(new CounterDto { Id = ObjectId.GenerateNewId(), // this might fail if we test during date change... seems unlikely // TODO, wrap Datetime in a mock friendly wrapper - Key = $"stats:succeeded:{date:yyyy-MM-dd}", + Key = $"stats:succeeded:{date:yyyy-MM-dd}", Value = succededCount }.Serialize()); - + var results = _monitoringApi.SucceededByDatesCount(); - + Assert.Equal(succededCount, results[date]); Assert.Equal(8, results.Count); } - - [Fact, CleanDatabase] + + [Fact] public void HourlySucceededJobs_ReturnsSuccededJobs_ForLast24Hours() { var now = DateTime.UtcNow; - + var succeededCount = 10L; _database.JobGraph.InsertOne(new CounterDto { Id = ObjectId.GenerateNewId(), // this might fail if we test during hour change... still unlikely // TODO, wrap Datetime in a mock friendly wrapper - Key = $"stats:succeeded:{now:yyyy-MM-dd-HH}", + Key = $"stats:succeeded:{now:yyyy-MM-dd-HH}", Value = succeededCount }.Serialize()); - + var results = _monitoringApi.HourlySucceededJobs(); - + Assert.Equal(succeededCount, results.First(kv => kv.Key.Hour.Equals(now.Hour)).Value); Assert.Equal(24, results.Count); } - - [Fact, CleanDatabase] + + [Fact] public void FailedByDatesCount_ReturnsFailedJobs_ForLastWeek() { var date = DateTime.UtcNow.Date; var failedCount = 10L; - + _database.JobGraph.InsertOne(new CounterDto { Id = ObjectId.GenerateNewId(), // this might fail if we test during date change... seems unlikely - Key = $"stats:failed:{date:yyyy-MM-dd}", + Key = $"stats:failed:{date:yyyy-MM-dd}", Value = failedCount }.Serialize()); - + var results = _monitoringApi.FailedByDatesCount(); - + Assert.Equal(failedCount, results[date]); Assert.Equal(8, results.Count); } - - [Fact, CleanDatabase] + + [Fact] public void HourlyFailedJobs_ReturnsFailedJobs_ForLast24Hours() { var now = DateTime.UtcNow; var failedCount = 10L; - + _database.JobGraph.InsertOne(new CounterDto { Id = ObjectId.GenerateNewId(), // this might fail if we test during hour change... still unlikely // TODO, wrap Datetime in a mock friendly wrapper - Key = $"stats:failed:{now:yyyy-MM-dd-HH}", + Key = $"stats:failed:{now:yyyy-MM-dd-HH}", Value = failedCount }.Serialize()); - + var results = _monitoringApi.HourlyFailedJobs(); - + Assert.Equal(failedCount, results.First(kv => kv.Key.Hour.Equals(now.Hour)).Value); Assert.Equal(24, results.Count); } diff --git a/src/Hangfire.Mongo.Tests/MongoNotificationObserverErrorFacts.cs b/src/Hangfire.Mongo.Tests/MongoNotificationObserverErrorFacts.cs index fa044208..2c3a1ab1 100644 --- a/src/Hangfire.Mongo.Tests/MongoNotificationObserverErrorFacts.cs +++ b/src/Hangfire.Mongo.Tests/MongoNotificationObserverErrorFacts.cs @@ -9,24 +9,26 @@ namespace Hangfire.Mongo.Tests { + [Collection("Database")] public sealed class MongoNotificationObserverErrorFacts : IDisposable { private readonly HangfireDbContext _dbContext; private readonly Mock _jobQueueSemaphoreMock; private readonly CancellationTokenSource _cts; - public MongoNotificationObserverErrorFacts() + + public MongoNotificationObserverErrorFacts(MongoDbFixture fixture) { - _dbContext = ConnectionUtils.CreateDbContext(); + _dbContext = fixture.CreateDbContext(); _jobQueueSemaphoreMock = new Mock(MockBehavior.Strict); var mongoNotificationObserver = new MongoNotificationObserver( - _dbContext, + _dbContext, new MongoStorageOptions(), _jobQueueSemaphoreMock.Object); - + _dbContext.Database.DropCollection(_dbContext.Notifications.CollectionNamespace.CollectionName); _cts = new CancellationTokenSource(); - + Task.Run(async () => { await Task.Yield(); @@ -40,7 +42,7 @@ public void Dispose() _cts.Cancel(); _cts.Dispose(); } - + [Fact] public void Execute_CollectionNotCapped_Converted() { @@ -48,11 +50,11 @@ public void Execute_CollectionNotCapped_Converted() var signal = new SemaphoreSlim(0,1); _jobQueueSemaphoreMock.Setup(m => m.Release("test")) .Callback(() => signal.Release()); - + // ACT _dbContext.Notifications.InsertOne(NotificationDto.JobEnqueued("test").Serialize()); var signalled = signal.Wait(1000); - + // ASSERT Assert.True(signalled); _jobQueueSemaphoreMock.Verify(m => m.Release("test"), Times.Once); diff --git a/src/Hangfire.Mongo.Tests/MongoNotificationObserverFacts.cs b/src/Hangfire.Mongo.Tests/MongoNotificationObserverFacts.cs index 4d2f37c8..7ee4d036 100644 --- a/src/Hangfire.Mongo.Tests/MongoNotificationObserverFacts.cs +++ b/src/Hangfire.Mongo.Tests/MongoNotificationObserverFacts.cs @@ -10,26 +10,28 @@ namespace Hangfire.Mongo.Tests { + [Collection("Database")] public sealed class MongoNotificationObserverFacts : IDisposable { private readonly HangfireDbContext _dbContext; private readonly Mock _jobQueueSemaphoreMock; private readonly CancellationTokenSource _cts; - public MongoNotificationObserverFacts() + + public MongoNotificationObserverFacts(MongoDbFixture fixture) { - _dbContext = ConnectionUtils.CreateDbContext(); + _dbContext = fixture.CreateDbContext(); _jobQueueSemaphoreMock = new Mock(MockBehavior.Strict); var mongoNotificationObserver = new MongoNotificationObserver( _dbContext, new MongoStorageOptions(), _jobQueueSemaphoreMock.Object); - + _dbContext.Database.DropCollection(_dbContext.Notifications.CollectionNamespace.CollectionName); var migration = new AddNotificationsCollection(); migration.Execute(_dbContext.Database, new MongoStorageOptions(), null); _cts = new CancellationTokenSource(); - + Task.Run(async () => { await Task.Yield(); @@ -43,7 +45,7 @@ public void Dispose() _cts.Cancel(); _cts.Dispose(); } - + [Fact] public void Execute_JobEnqueued_Signaled() { @@ -51,11 +53,11 @@ public void Execute_JobEnqueued_Signaled() var signal = new SemaphoreSlim(0,1); _jobQueueSemaphoreMock.Setup(m => m.Release("test")) .Callback(() => signal.Release()); - + // ACT _dbContext.Notifications.InsertOne(NotificationDto.JobEnqueued("test").Serialize()); signal.Wait(1000); - + // ASSERT _jobQueueSemaphoreMock.Verify(m => m.Release("test"), Times.Once); } diff --git a/src/Hangfire.Mongo.Tests/MongoRunServerFacts.cs b/src/Hangfire.Mongo.Tests/MongoRunServerFacts.cs index bbcdee62..aee3e2d9 100644 --- a/src/Hangfire.Mongo.Tests/MongoRunServerFacts.cs +++ b/src/Hangfire.Mongo.Tests/MongoRunServerFacts.cs @@ -38,10 +38,10 @@ public class MongoRunFixture : IDisposable private readonly BackgroundJobServer _server; public HangfireDbContext DbContext { get; } - public MongoRunFixture() + public MongoRunFixture(MongoDbFixture fixture) { var databaseName = "Mongo-Hangfire-CamelCase"; - var context = ConnectionUtils.CreateDbContext(databaseName); + var context = fixture.CreateDbContext(databaseName); DbContext = context; // Make sure we start from scratch context.Database.Client.DropDatabase(databaseName); @@ -54,8 +54,8 @@ public MongoRunFixture() BackupStrategy = new NoneMongoBackupStrategy() } }; - - JobStorage.Current = ConnectionUtils.CreateStorage(storageOptions, databaseName); + + JobStorage.Current = fixture.CreateStorage(storageOptions, databaseName); var conventionPack = new ConventionPack {new CamelCaseElementNameConvention()}; ConventionRegistry.Register("CamelCase", conventionPack, t => true); @@ -111,7 +111,7 @@ public void ContinueWith_Executed_Success() var parentId2 = BackgroundJob.ContinueWith(parentId1, j => j.AddId(parentId1)); BackgroundJob.ContinueWith(parentId2, j => j.AddAndSignal(parentId2)); var signalled = TestJob.Signal.WaitOne(20000); - + // ASSERT Assert.True(signalled, "not signalled"); Assert.Equal(3, TestJob.JobIds.Count); diff --git a/src/Hangfire.Mongo.Tests/MongoStorageFacts.cs b/src/Hangfire.Mongo.Tests/MongoStorageFacts.cs index 4dd215fb..01a3ce54 100644 --- a/src/Hangfire.Mongo.Tests/MongoStorageFacts.cs +++ b/src/Hangfire.Mongo.Tests/MongoStorageFacts.cs @@ -11,6 +11,14 @@ namespace Hangfire.Mongo.Tests [Collection("Database")] public class MongoStorageFacts { + private readonly MongoStorage _storage; + + public MongoStorageFacts(MongoDbFixture fixture) + { + fixture.CleanDatabase(); + _storage = fixture.CreateStorage(); + } + [Fact] public void Ctor_ThrowsAnException_WhenConnectionStringIsEmpty() { @@ -35,19 +43,17 @@ public void Ctor_ThrowsAnException_WhenStorageOptionsValueIsNull() Assert.Equal("storageOptions", exception.ParamName); } - [Fact, CleanDatabase] + [Fact] public void GetMonitoringApi_ReturnsNonNullInstance() { - MongoStorage storage = ConnectionUtils.CreateStorage(); - IMonitoringApi api = storage.GetMonitoringApi(); + IMonitoringApi api = _storage.GetMonitoringApi(); Assert.NotNull(api); } - [Fact, CleanDatabase] + [Fact] public void GetConnection_ReturnsNonNullInstance() { - MongoStorage storage = ConnectionUtils.CreateStorage(); - using (IStorageConnection connection = storage.GetConnection()) + using (IStorageConnection connection = _storage.GetConnection()) { Assert.NotNull(connection); } @@ -56,9 +62,7 @@ public void GetConnection_ReturnsNonNullInstance() [Fact] public void GetComponents_ReturnsAllNeededComponents() { - MongoStorage storage = ConnectionUtils.CreateStorage(); - - var components = storage.GetComponents(); + var components = _storage.GetComponents(); Type[] componentTypes = components.Select(x => x.GetType()).ToArray(); Assert.Contains(typeof(MongoExpirationManager), componentTypes); diff --git a/src/Hangfire.Mongo.Tests/MongoVersionHelperFacts.cs b/src/Hangfire.Mongo.Tests/MongoVersionHelperFacts.cs index 5c5f4909..a724dc25 100644 --- a/src/Hangfire.Mongo.Tests/MongoVersionHelperFacts.cs +++ b/src/Hangfire.Mongo.Tests/MongoVersionHelperFacts.cs @@ -1,8 +1,5 @@ using System; -using System.Runtime.CompilerServices; using System.Threading; -using System.Threading.Tasks; -using Hangfire.Common; using Hangfire.Mongo.Tests.Utils; using MongoDB.Bson; using MongoDB.Driver; @@ -15,6 +12,10 @@ namespace Hangfire.Mongo.Tests [Collection("Database")] public class MongoVersionHelperFacts { + private readonly MongoDbFixture _fixture; + + public MongoVersionHelperFacts(MongoDbFixture fixture) => _fixture = fixture; + [Fact] public void GetVersion_HasAdditionalInfo_Success() { @@ -26,10 +27,10 @@ public void GetVersion_HasAdditionalInfo_Success() { ["version"] = "3.6.4-1.2" }); - + // ACT var version = MongoVersionHelper.GetVersion(dbMock.Object); - + // ASSERT Assert.Equal(version, new Version(3, 6, 4)); } @@ -38,8 +39,8 @@ public void GetVersion_HasAdditionalInfo_Success() public void GetVersion_FromDb_Success() { // ARRANGE - var db = ConnectionUtils.CreateDbContext(); - + var db = _fixture.CreateDbContext(); + // ACT var version = MongoVersionHelper.GetVersion(db.Database); diff --git a/src/Hangfire.Mongo.Tests/MongoWatcherFacts.cs b/src/Hangfire.Mongo.Tests/MongoWatcherFacts.cs index fe27bedf..fb2748e0 100644 --- a/src/Hangfire.Mongo.Tests/MongoWatcherFacts.cs +++ b/src/Hangfire.Mongo.Tests/MongoWatcherFacts.cs @@ -16,17 +16,18 @@ public sealed class MongoWatcherFacts : IDisposable private readonly Mock _jobQueueSemaphoreMock; private readonly CancellationTokenSource _cts; - public MongoWatcherFacts() + + public MongoWatcherFacts(MongoDbFixture fixture) { - _dbContext = ConnectionUtils.CreateDbContext(); + _dbContext = fixture.CreateDbContext(); _jobQueueSemaphoreMock = new Mock(MockBehavior.Strict); var watcher = new MongoJobQueueWatcher( _dbContext, new MongoStorageOptions(), _jobQueueSemaphoreMock.Object); - + _cts = new CancellationTokenSource(); - + Task.Run(async () => { await Task.Yield(); @@ -40,7 +41,7 @@ public void Dispose() _cts.Cancel(); _cts.Dispose(); } - + [Fact(Skip = "Needs replica set, enable when you figure out how to set it up in github actions")] public void Execute_JobEnqueued_Signaled() { @@ -64,7 +65,7 @@ public void Execute_JobEnqueued_Signaled() } }); signal.Wait(100000); - + // ASSERT _jobQueueSemaphoreMock.Verify(m => m.Release("test"), Times.Once); } diff --git a/src/Hangfire.Mongo.Tests/MongoWriteOnlyTransactionFacts.cs b/src/Hangfire.Mongo.Tests/MongoWriteOnlyTransactionFacts.cs index 575dfa18..74d8b8bb 100644 --- a/src/Hangfire.Mongo.Tests/MongoWriteOnlyTransactionFacts.cs +++ b/src/Hangfire.Mongo.Tests/MongoWriteOnlyTransactionFacts.cs @@ -17,7 +17,13 @@ namespace Hangfire.Mongo.Tests [Collection("Database")] public class MongoWriteOnlyTransactionFacts { - private readonly HangfireDbContext _database = ConnectionUtils.CreateDbContext(); + private readonly HangfireDbContext _database; + + public MongoWriteOnlyTransactionFacts(MongoDbFixture fixture) + { + fixture.CleanDatabase(); + _database = fixture.CreateDbContext(); + } [Fact] public void Ctor_ThrowsAnException_IfConnectionIsNull() @@ -28,7 +34,6 @@ public void Ctor_ThrowsAnException_IfConnectionIsNull() } [Fact] - [CleanDatabase] public void ExpireJob_SetsJobExpirationData() { var job = new JobDto @@ -63,7 +68,6 @@ public void ExpireJob_SetsJobExpirationData() } [Fact] - [CleanDatabase] public void PersistJob_ClearsTheJobExpirationData() { var job = new JobDto @@ -99,7 +103,6 @@ public void PersistJob_ClearsTheJobExpirationData() } [Fact] - [CleanDatabase] public void SetJobState_AppendsAStateAndSetItToTheJob() { var job = new JobDto @@ -151,7 +154,6 @@ public void SetJobState_AppendsAStateAndSetItToTheJob() } [Fact] - [CleanDatabase] public void AddJobState_JustAddsANewRecordInATable() { var job = new JobDto @@ -187,7 +189,6 @@ public void AddJobState_JustAddsANewRecordInATable() } [Fact] - [CleanDatabase] public void AddToQueue_CallsEnqueue_OnTargetPersistentQueue() { var jobId = ObjectId.GenerateNewId(); @@ -213,7 +214,6 @@ public void AddToQueue_CallsEnqueue_OnTargetPersistentQueue() } [Fact] - [CleanDatabase] public void IncrementCounter_AddsRecordToCounterTable_WithPositiveValue() { Commit(x => x.IncrementCounter("my-key")); @@ -231,7 +231,6 @@ public void IncrementCounter_AddsRecordToCounterTable_WithPositiveValue() } [Fact] - [CleanDatabase] public void IncrementCounter_WithExpiry_AddsARecord_WithExpirationTimeSet() { Commit(x => x.IncrementCounter("my-key", TimeSpan.FromDays(1))); @@ -253,7 +252,6 @@ public void IncrementCounter_WithExpiry_AddsARecord_WithExpirationTimeSet() } [Fact] - [CleanDatabase] public void IncrementCounter_WithExistingKey_AddsAnotherRecord() { Commit(x => @@ -274,7 +272,6 @@ public void IncrementCounter_WithExistingKey_AddsAnotherRecord() } [Fact] - [CleanDatabase] public void DecrementCounter_AddsRecordToCounterTable_WithNegativeValue() { Commit(x => x.DecrementCounter("my-key")); @@ -291,7 +288,6 @@ public void DecrementCounter_AddsRecordToCounterTable_WithNegativeValue() } [Fact] - [CleanDatabase] public void DecrementCounter_WithExpiry_AddsARecord_WithExpirationTimeSet() { Commit(x => x.DecrementCounter("my-key", TimeSpan.FromDays(1))); @@ -313,7 +309,6 @@ public void DecrementCounter_WithExpiry_AddsARecord_WithExpirationTimeSet() } [Fact] - [CleanDatabase] public void DecrementCounter_WithExistingKey_AddsAnotherRecord() { Commit(x => @@ -332,7 +327,6 @@ public void DecrementCounter_WithExistingKey_AddsAnotherRecord() } [Fact] - [CleanDatabase] public void AddToSet_AddsARecord_IfThereIsNo_SuchKeyAndValue() { Commit(x => x.AddToSet("my-key", "my-value")); @@ -348,7 +342,6 @@ public void AddToSet_AddsARecord_IfThereIsNo_SuchKeyAndValue() } [Fact] - [CleanDatabase] public void AddToSet_AddsARecord_WhenKeyIsExists_ButValuesAreDifferent() { Commit(x => @@ -366,7 +359,6 @@ public void AddToSet_AddsARecord_WhenKeyIsExists_ButValuesAreDifferent() } [Fact] - [CleanDatabase] public void AddToSet_DoesNotAddARecord_WhenBothKeyAndValueAreExist() { Commit(x => @@ -381,7 +373,6 @@ public void AddToSet_DoesNotAddARecord_WhenBothKeyAndValueAreExist() } [Fact] - [CleanDatabase] public void AddToSet_WithScore_AddsARecordWithScore_WhenBothKeyAndValueAreNotExist() { Commit(x => x.AddToSet("my-key", "my-value", 3.2)); @@ -396,7 +387,6 @@ public void AddToSet_WithScore_AddsARecordWithScore_WhenBothKeyAndValueAreNotExi } [Fact] - [CleanDatabase] public void AddToSet_WithScore_UpdatesAScore_WhenBothKeyAndValueAreExist() { Commit(x => @@ -412,7 +402,6 @@ public void AddToSet_WithScore_UpdatesAScore_WhenBothKeyAndValueAreExist() } [Fact] - [CleanDatabase] public void RemoveFromSet_RemovesARecord_WithGivenKeyAndValue() { Commit(x => @@ -427,7 +416,6 @@ public void RemoveFromSet_RemovesARecord_WithGivenKeyAndValue() } [Fact] - [CleanDatabase] public void RemoveFromSet_DoesNotRemoveRecord_WithSameKey_AndDifferentValue() { Commit(x => @@ -442,7 +430,6 @@ public void RemoveFromSet_DoesNotRemoveRecord_WithSameKey_AndDifferentValue() } [Fact] - [CleanDatabase] public void RemoveFromSet_DoesNotRemoveRecord_WithSameValue_AndDifferentKey() { Commit(x => @@ -457,7 +444,6 @@ public void RemoveFromSet_DoesNotRemoveRecord_WithSameValue_AndDifferentKey() } [Fact] - [CleanDatabase] public void InsertToList_AddsARecord_WithGivenValues() { Commit(x => x.InsertToList("my-key", "my-value")); @@ -468,7 +454,6 @@ public void InsertToList_AddsARecord_WithGivenValues() } [Fact] - [CleanDatabase] public void InsertToList_AddsAnotherRecord_WhenBothKeyAndValueAreExist() { Commit(x => @@ -483,7 +468,6 @@ public void InsertToList_AddsAnotherRecord_WhenBothKeyAndValueAreExist() } [Fact] - [CleanDatabase] public void RemoveFromList_RemovesAllRecords_WithGivenKeyAndValue() { Commit(x => @@ -499,7 +483,6 @@ public void RemoveFromList_RemovesAllRecords_WithGivenKeyAndValue() } [Fact] - [CleanDatabase] public void RemoveFromList_DoesNotRemoveRecords_WithSameKey_ButDifferentValue() { Commit(x => @@ -514,7 +497,6 @@ public void RemoveFromList_DoesNotRemoveRecords_WithSameKey_ButDifferentValue() } [Fact] - [CleanDatabase] public void RemoveFromList_DoesNotRemoveRecords_WithSameValue_ButDifferentKey() { Commit(x => @@ -529,7 +511,6 @@ public void RemoveFromList_DoesNotRemoveRecords_WithSameValue_ButDifferentKey() } [Fact] - [CleanDatabase] public void TrimList_TrimsAList_ToASpecifiedRange() { Commit(x => @@ -550,7 +531,6 @@ public void TrimList_TrimsAList_ToASpecifiedRange() } [Fact] - [CleanDatabase] public void TrimList_RemovesRecordsToEnd_IfKeepAndingAt_GreaterThanMaxElementIndex() { Commit(x => @@ -567,7 +547,6 @@ public void TrimList_RemovesRecordsToEnd_IfKeepAndingAt_GreaterThanMaxElementInd } [Fact] - [CleanDatabase] public void TrimList_RemovesAllRecords_WhenStartingFromValue_GreaterThanMaxElementIndex() { Commit(x => @@ -582,7 +561,6 @@ public void TrimList_RemovesAllRecords_WhenStartingFromValue_GreaterThanMaxEleme } [Fact] - [CleanDatabase] public void TrimList_RemovesAllRecords_IfStartFromGreaterThanEndingAt() { Commit(x => @@ -597,7 +575,6 @@ public void TrimList_RemovesAllRecords_IfStartFromGreaterThanEndingAt() } [Fact] - [CleanDatabase] public void TrimList_RemovesRecords_OnlyOfAGivenKey() { Commit(x => @@ -612,7 +589,6 @@ public void TrimList_RemovesRecords_OnlyOfAGivenKey() } [Fact] - [CleanDatabase] public void SetRangeInHash_ThrowsAnException_WhenKeyIsNull() { var exception = Assert.Throws( @@ -622,7 +598,6 @@ public void SetRangeInHash_ThrowsAnException_WhenKeyIsNull() } [Fact] - [CleanDatabase] public void SetRangeInHash_ThrowsAnException_WhenKeyValuePairsArgumentIsNull() { var exception = Assert.Throws( @@ -632,7 +607,6 @@ public void SetRangeInHash_ThrowsAnException_WhenKeyValuePairsArgumentIsNull() } [Fact] - [CleanDatabase] public void SetRangeInHash_MergesAllRecords() { Commit(x => x.SetRangeInHash("some-hash", new Dictionary @@ -651,7 +625,6 @@ public void SetRangeInHash_MergesAllRecords() } [Fact] - [CleanDatabase] public void RemoveHash_ThrowsAnException_WhenKeyIsNull() { Assert.Throws( @@ -659,7 +632,6 @@ public void RemoveHash_ThrowsAnException_WhenKeyIsNull() } [Fact] - [CleanDatabase] public void RemoveHash_RemovesAllHashRecords() { // Arrange @@ -678,7 +650,6 @@ public void RemoveHash_RemovesAllHashRecords() } [Fact] - [CleanDatabase] public void ExpireSet_SetsSetExpirationData() { var set1 = new SetDto {Key = "Set1", Value = "value1", SetType = "Set1"}; @@ -701,7 +672,6 @@ public void ExpireSet_SetsSetExpirationData() } [Fact] - [CleanDatabase] public void ExpireSet_SetsSetExpirationData_WhenKeyContainsRegexSpecialChars() { var key = "some+-[regex]?-#set"; @@ -720,7 +690,6 @@ public void ExpireSet_SetsSetExpirationData_WhenKeyContainsRegexSpecialChars() } [Fact] - [CleanDatabase] public void ExpireList_SetsListExpirationData() { var list1 = new ListDto {Item = "List1", Value = "value1"}; @@ -740,7 +709,6 @@ public void ExpireList_SetsListExpirationData() } [Fact] - [CleanDatabase] public void ExpireHash_SetsHashExpirationData() { var hash1 = new HashDto {Key = "Hash1"}; @@ -761,7 +729,6 @@ public void ExpireHash_SetsHashExpirationData() [Fact] - [CleanDatabase] public void PersistSet_ClearsTheSetExpirationData() { var set1Val1 = new SetDto {Key = "Set1", Value = "value1", SetType = "Set1", ExpireAt = DateTime.UtcNow}; @@ -783,7 +750,6 @@ public void PersistSet_ClearsTheSetExpirationData() } [Fact] - [CleanDatabase] public void PersistSet_ClearsTheSetExpirationData_WhenKeyContainsRegexSpecialChars() { var key = "some+-[regex]?-#set"; @@ -799,7 +765,6 @@ public void PersistSet_ClearsTheSetExpirationData_WhenKeyContainsRegexSpecialCha } [Fact] - [CleanDatabase] public void PersistList_ClearsTheListExpirationData() { var list1 = new ListDto {Item = "List1", Value = "value1", ExpireAt = DateTime.UtcNow}; @@ -818,7 +783,6 @@ public void PersistList_ClearsTheListExpirationData() } [Fact] - [CleanDatabase] public void PersistHash_ClearsTheHashExpirationData() { var hash1 = new HashDto {Key = "Hash1", ExpireAt = DateTime.UtcNow}; @@ -837,7 +801,6 @@ public void PersistHash_ClearsTheHashExpirationData() } [Fact] - [CleanDatabase] public void AddRangeToSet_AddToExistingSetData() { // ASSERT @@ -869,7 +832,6 @@ public void AddRangeToSet_AddToExistingSetData() } [Fact] - [CleanDatabase] public void RemoveSet_ClearsTheSetData() { var set1Val1 = new SetDto {Key = "Set1", Value = "value1", SetType = "Set1", ExpireAt = DateTime.UtcNow}; @@ -891,7 +853,6 @@ public void RemoveSet_ClearsTheSetData() } [Fact] - [CleanDatabase] public void RemoveSet_ClearsTheSetData_WhenKeyContainsRegexSpecialChars() { var key = "some+-[regex]?-#set"; diff --git a/src/Hangfire.Mongo.Tests/MultipleServersFacts.cs b/src/Hangfire.Mongo.Tests/MultipleServersFacts.cs index bec1b906..3af8c94a 100644 --- a/src/Hangfire.Mongo.Tests/MultipleServersFacts.cs +++ b/src/Hangfire.Mongo.Tests/MultipleServersFacts.cs @@ -10,7 +10,15 @@ namespace Hangfire.Mongo.Tests [Collection("Database")] public class MultipleServersFacts { - [Fact(Skip = "Long running and does not always fail"), CleanDatabase] + private readonly MongoStorage _storage; + + public MultipleServersFacts(MongoDbFixture fixture) + { + fixture.CleanDatabase(); + _storage = fixture.CreateStorage(new MongoStorageOptions { QueuePollInterval = TimeSpan.FromSeconds(1) }); + } + + [Fact(Skip = "Long running and does not always fail")] public void MultipleServerRunsRecurrentJobs() { // ARRANGE @@ -18,7 +26,7 @@ public void MultipleServerRunsRecurrentJobs() const int workerCount = 20; var options = new BackgroundJobServerOptions[serverCount]; - var storage = ConnectionUtils.CreateStorage(new MongoStorageOptions { QueuePollInterval = TimeSpan.FromSeconds(1) }); + var servers = new BackgroundJobServer[serverCount]; var jobManagers = new RecurringJobManager[serverCount]; @@ -27,8 +35,8 @@ public void MultipleServerRunsRecurrentJobs() { options[i] = new BackgroundJobServerOptions { Queues = new[] { $"queue_options_{i}" }, WorkerCount = workerCount }; - servers[i] = new BackgroundJobServer(options[i], storage); - jobManagers[i] = new RecurringJobManager(storage); + servers[i] = new BackgroundJobServer(options[i], _storage); + jobManagers[i] = new RecurringJobManager(_storage); } try diff --git a/src/Hangfire.Mongo.Tests/Utils/CleanDatabaseAttribute.cs b/src/Hangfire.Mongo.Tests/Utils/CleanDatabaseAttribute.cs deleted file mode 100644 index 0e1254aa..00000000 --- a/src/Hangfire.Mongo.Tests/Utils/CleanDatabaseAttribute.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System; -using System.Reflection; -using System.Threading; -using MongoDB.Bson; -using MongoDB.Driver; -using Xunit.Sdk; - -namespace Hangfire.Mongo.Tests.Utils -{ -#pragma warning disable 1591 - public class CleanDatabaseAttribute : BeforeAfterTestAttribute - { - private static readonly object GlobalLock = new object(); - - public bool Initialized { get; set; } - - public CleanDatabaseAttribute() : this(true) - { - } - - public CleanDatabaseAttribute(bool initialized) - { - Initialized = initialized; - } - - public override void Before(MethodInfo methodUnderTest) - { - Monitor.Enter(GlobalLock); - - if (Initialized) - { - RecreateDatabaseAndInstallObjects(); - return; - } - - // Drop the database and do not run any - // migrations to initialize the database. - ConnectionUtils.DropDatabase(); - } - - public override void After(MethodInfo methodUnderTest) - { - Monitor.Exit(GlobalLock); - } - - private static void RecreateDatabaseAndInstallObjects() - { - - try - { - var context = ConnectionUtils.CreateDbContext(); - context.DistributedLock.DeleteMany(new BsonDocument()); - context.JobGraph.DeleteMany(new BsonDocument()); - context.Server.DeleteMany(new BsonDocument()); - context.Database.DropCollection(context.Notifications.CollectionNamespace.CollectionName); - } - catch (MongoException ex) - { - throw new InvalidOperationException("Unable to cleanup database.", ex); - } - } - } -#pragma warning restore 1591 -} \ No newline at end of file diff --git a/src/Hangfire.Mongo.Tests/Utils/ConnectionUtils.cs b/src/Hangfire.Mongo.Tests/Utils/ConnectionUtils.cs deleted file mode 100644 index b162cb62..00000000 --- a/src/Hangfire.Mongo.Tests/Utils/ConnectionUtils.cs +++ /dev/null @@ -1,50 +0,0 @@ -using Hangfire.Mongo.Database; -using Hangfire.Mongo.Migration.Strategies; -using Hangfire.Mongo.Migration.Strategies.Backup; -using MongoDB.Driver; -using System; - -[assembly: Xunit.TestFramework("Hangfire.Mongo.Tests.Utils.ConnectionUtils", "Hangfire.Mongo.Tests")] - -namespace Hangfire.Mongo.Tests.Utils -{ -#pragma warning disable 1591 - public class ConnectionUtils - { - private const string DefaultDatabaseName = @"Hangfire-Mongo-Tests"; - private static string ConnectionString = "mongodb://localhost:27017"; - // "mongodb://localhost:27017?replicaSet=rs0&readPreference=primary&ssl=false"; - - public static MongoStorage CreateStorage(string databaseName = null) - { - var storageOptions = new MongoStorageOptions - { - MigrationOptions = new MongoMigrationOptions - { - MigrationStrategy = new DropMongoMigrationStrategy(), - BackupStrategy = new NoneMongoBackupStrategy() - } - }; - return CreateStorage(storageOptions, databaseName); - } - - - public static MongoStorage CreateStorage(MongoStorageOptions storageOptions, string databaseName=null) - { - var mongoClientSettings = MongoClientSettings.FromConnectionString(ConnectionString); - return new MongoStorage(mongoClientSettings, databaseName ?? DefaultDatabaseName, storageOptions); - } - - public static HangfireDbContext CreateDbContext(string dbName = null) - { - return new HangfireDbContext(ConnectionString, dbName ?? DefaultDatabaseName); - } - - public static void DropDatabase() - { - var client = new MongoClient(ConnectionString); - client.DropDatabase(DefaultDatabaseName); - } - } -#pragma warning restore 1591 -} diff --git a/src/Hangfire.Mongo.Tests/Utils/DatabaseCollection.cs b/src/Hangfire.Mongo.Tests/Utils/DatabaseCollection.cs new file mode 100644 index 00000000..9317384d --- /dev/null +++ b/src/Hangfire.Mongo.Tests/Utils/DatabaseCollection.cs @@ -0,0 +1,9 @@ +using Xunit; + +namespace Hangfire.Mongo.Tests.Utils +{ + [CollectionDefinition("Database")] + public class DatabaseCollection : ICollectionFixture + { + } +} diff --git a/src/Hangfire.Mongo.Tests/Utils/MongoDbFixture.cs b/src/Hangfire.Mongo.Tests/Utils/MongoDbFixture.cs new file mode 100644 index 00000000..3dc5ea95 --- /dev/null +++ b/src/Hangfire.Mongo.Tests/Utils/MongoDbFixture.cs @@ -0,0 +1,81 @@ +using System; +using EphemeralMongo; +using Hangfire.Mongo.Database; +using Hangfire.Mongo.Migration.Strategies; +using Hangfire.Mongo.Migration.Strategies.Backup; +using MongoDB.Bson; +using MongoDB.Driver; +using MongoDB.Driver.Linq; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace Hangfire.Mongo.Tests.Utils; + +public sealed class MongoDbFixture : IDisposable +{ + private const string DefaultDatabaseName = @"Hangfire-Mongo-Tests"; + + private readonly IMongoRunner _runner; + + public MongoDbFixture(IMessageSink sink) + { + var options = new MongoRunnerOptions + { + StandardOuputLogger = text => sink.OnMessage(new DiagnosticMessage(text)), + StandardErrorLogger = text => sink.OnMessage(new DiagnosticMessage($"MongoDB ERROR: {text}")), + }; + _runner = MongoRunner.Run(options); + } + + public void Dispose() + { + _runner.Dispose(); + } + + public MongoStorage CreateStorage(string databaseName = null) + { + var storageOptions = new MongoStorageOptions + { + MigrationOptions = new MongoMigrationOptions + { + MigrationStrategy = new DropMongoMigrationStrategy(), + BackupStrategy = new NoneMongoBackupStrategy() + } + }; + return CreateStorage(storageOptions, databaseName); + } + + public MongoStorage CreateStorage(MongoStorageOptions storageOptions, string databaseName=null) + { + var client = GetMongoClient(); + return new MongoStorage(client, databaseName ?? DefaultDatabaseName, storageOptions); + } + + public HangfireDbContext CreateDbContext(string dbName = null) + { + var client = GetMongoClient(); + return new HangfireDbContext(client, dbName ?? DefaultDatabaseName); + } + + public void CleanDatabase(string dbName = null) + { + try + { + var context = CreateDbContext(dbName); + context.DistributedLock.DeleteMany(new BsonDocument()); + context.JobGraph.DeleteMany(new BsonDocument()); + context.Server.DeleteMany(new BsonDocument()); + context.Database.DropCollection(context.Notifications.CollectionNamespace.CollectionName); + } + catch (MongoException ex) + { + throw new InvalidOperationException("Unable to cleanup database.", ex); + } + } + + private MongoClient GetMongoClient() + { + var settings = MongoClientSettings.FromConnectionString(_runner.ConnectionString); + return new MongoClient(settings); + } +} \ No newline at end of file diff --git a/src/Hangfire.Mongo.Tests/xunit.runner.json b/src/Hangfire.Mongo.Tests/xunit.runner.json new file mode 100644 index 00000000..2718c2cd --- /dev/null +++ b/src/Hangfire.Mongo.Tests/xunit.runner.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json", + "diagnosticMessages": true +}