Skip to content

Commit 4116eda

Browse files
authored
[Bug] Fix mongo conventions (#10)
* Fix mongo conventions * Move convention initialization to ScheduleRepository * Configure GitHub actions for mongo tests (#2) * Test with real mongo * Remove msbuild * test on linux * Test with old document for deserialization
1 parent e7a2120 commit 4116eda

File tree

6 files changed

+234
-42
lines changed

6 files changed

+234
-42
lines changed

.github/workflows/dotnet-desktop.yaml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,9 @@ jobs:
5151
strategy:
5252
matrix:
5353
configuration: [Release]
54+
mongodb-version: ['4.2', '4.4', '5.0', '6.0']
5455

55-
runs-on: windows-latest # For a list of available runner types, refer to
56+
runs-on: ubuntu-latest # For a list of available runner types, refer to
5657
# https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on
5758

5859
env:
@@ -70,9 +71,10 @@ jobs:
7071
with:
7172
dotnet-version: 6.0.x
7273

73-
# Add MSBuild to the PATH: https://github.com/microsoft/setup-msbuild
74-
- name: Setup MSBuild.exe
75-
uses: microsoft/[email protected]
74+
- name: Start MongoDB
75+
uses: supercharge/[email protected]
76+
with:
77+
mongodb-version: ${{ matrix.mongodb-version }}
7678

7779
# Execute all unit tests in the solution
7880
- name: Execute unit tests
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
{
2+
"_id": BinData(3, 'LH9BsL6fuEWaP4utMDFX1w=='),
3+
"WakeTime" : ISODate("2022-09-28T07:17:22.451Z"),
4+
"BindingKey" : "Message",
5+
"Exchange" : "Message",
6+
"ExchangeType" : "topic",
7+
"RoutingKey" : "#",
8+
"InnerMessage" : BinData(0,"eyJldmVudFR5cGUiOiJTZW5kTGVhcm5Qcm9tb0FjdGlvbkVtYWlsMSIsInVzZXJJZCI6Ijk1Njc0YzBhMmY5YjQ5ZjRhZjQ1MWQ4YTlmODQ0YzkzIiwidHJ5Q291bnQiOjB9"),
9+
"BasicProperties" : {
10+
"ContentType" : null,
11+
"ContentEncoding" : null,
12+
"Headers" : {
13+
14+
},
15+
"DeliveryMode" : 2,
16+
"Priority" : 0,
17+
"CorrelationId" : "3952ffcc-a6f9-4706-87f9-9edbfc5f74b7",
18+
"ReplyTo" : null,
19+
"Expiration" : null,
20+
"MessageId" : null,
21+
"Timestamp" : 0,
22+
"Type" : "Message",
23+
"UserId" : null,
24+
"AppId" : null,
25+
"ClusterId" : null,
26+
"ContentTypePresent" : false,
27+
"ContentEncodingPresent" : false,
28+
"HeadersPresent" : true,
29+
"DeliveryModePresent" : true,
30+
"PriorityPresent" : false,
31+
"CorrelationIdPresent" : true,
32+
"ReplyToPresent" : false,
33+
"ExpirationPresent" : false,
34+
"MessageIdPresent" : false,
35+
"TimestampPresent" : false,
36+
"TypePresent" : true,
37+
"UserIdPresent" : false,
38+
"AppIdPresent" : false,
39+
"ClusterIdPresent" : false
40+
},
41+
"State" : 1
42+
}

Source/EasyNetQ.Scheduler.Mongo.Tests/EasyNetQ.Scheduler.Mongo.Tests.csproj

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@
2525
<Reference Include="System" />
2626
<Reference Include="Microsoft.CSharp" />
2727
</ItemGroup>
28+
<ItemGroup>
29+
<None Include="BSONs\Pending.json">
30+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
31+
</None>
32+
</ItemGroup>
2833
<ItemGroup>
2934
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
3035
</ItemGroup>

Source/EasyNetQ.Scheduler.Mongo.Tests/ScheduleRepositoryTests.cs

Lines changed: 74 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,109 @@
11
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
24
using System.Text;
5+
using MongoDB.Driver;
36
using Xunit;
47

58
namespace EasyNetQ.Scheduler.Mongo.Tests
69
{
7-
public class ScheduleRepositoryTests
10+
public class ScheduleRepositoryTests : IClassFixture<SchedulesDatabaseFixture>
811
{
912
private readonly ScheduleRepository scheduleRepository;
13+
private readonly SchedulesDatabaseFixture databaseFixture;
1014

11-
public ScheduleRepositoryTests()
15+
public ScheduleRepositoryTests(SchedulesDatabaseFixture databaseFixture)
1216
{
13-
var configuration = new ScheduleRepositoryConfiguration
14-
{
15-
ConnectionString = "mongodb://localhost:27017/?w=1&readPreference=primary&uuidRepresentation=csharpLegacy",
16-
CollectionName = "Schedules",
17-
DatabaseName = "EasyNetQ",
18-
DeleteTimeout = TimeSpan.FromMinutes(5),
19-
PublishTimeout = TimeSpan.FromSeconds(60),
20-
};
21-
scheduleRepository = new ScheduleRepository(configuration, () => DateTime.UtcNow);
17+
this.databaseFixture = databaseFixture;
18+
scheduleRepository = new ScheduleRepository(databaseFixture.Configuration, () => DateTime.UtcNow);
2219
}
2320

24-
[Fact(Skip = "Required a database")]
21+
[Fact]
2522
public void Should_be_able_to_store_a_schedule()
2623
{
27-
scheduleRepository.Store(new Schedule
28-
{
29-
BindingKey = "abc",
30-
CancellationKey = "bcd",
31-
WakeTime = new DateTime(2011, 5, 18),
32-
InnerMessage = Encoding.UTF8.GetBytes("Hello World!"),
33-
Id = Guid.Empty,
34-
State = ScheduleState.Pending,
35-
});
24+
var schedule = new Schedule
25+
{
26+
BindingKey = "abc",
27+
CancellationKey = "bcd",
28+
WakeTime = new DateTime(2011, 5, 18),
29+
InnerMessage = Encoding.UTF8.GetBytes("Hello World!"),
30+
Id = Guid.NewGuid(),
31+
State = ScheduleState.Pending,
32+
};
33+
scheduleRepository.Store(schedule);
34+
35+
var insertedDoc = databaseFixture.GetDocument(schedule.Id);
36+
37+
Assert.Equal(schedule.Id, insertedDoc["_id"].AsGuid);
38+
Assert.Equal(schedule.CancellationKey, insertedDoc["CancellationKey"].AsString);
3639
}
3740

38-
[Fact(Skip = "Required a database")]
41+
[Fact]
3942
public void Should_be_able_to_cancel_a_schedule()
4043
{
41-
scheduleRepository.Cancel("bcd");
44+
var cancellation = Guid.NewGuid().ToString();
45+
databaseFixture.InitScheduleWithCancellation(cancellation);
46+
47+
scheduleRepository.Cancel(cancellation);
48+
49+
var count = databaseFixture.Collection.CountDocuments(d => d["CancellationKey"] == cancellation);
50+
Assert.Equal(0, count);
4251
}
4352

44-
[Fact(Skip = "Required a database")]
53+
[Fact]
4554
public void Should_be_able_to_get_messages()
4655
{
47-
while (true)
48-
{
49-
var schedule = scheduleRepository.GetPending();
50-
if(schedule == null)
51-
break;
52-
Console.WriteLine("{0}, {1}, {2}",
53-
schedule.BindingKey,
54-
schedule.WakeTime,
55-
Encoding.UTF8.GetString(schedule.InnerMessage));
56-
}
56+
var id = Guid.NewGuid();
57+
var wakeTime = DateTime.MinValue.AddDays(5);
58+
databaseFixture.InitializeOne(id, ScheduleState.Pending, wakeTime);
59+
60+
var schedule = scheduleRepository.GetPending();
61+
62+
Assert.Equal(id, schedule.Id);
5763
}
5864

59-
[Fact(Skip = "Required a database")]
65+
[Fact]
6066
public void Should_be_able_to_handle_timeout()
6167
{
68+
var id = Guid.NewGuid();
69+
var publishingTime = DateTime.UtcNow.Add(-databaseFixture.Configuration.PublishTimeout);
70+
databaseFixture.InitializeOne(id, ScheduleState.Publishing, publishingTime: publishingTime);
71+
6272
scheduleRepository.HandleTimeout();
73+
74+
var actual = databaseFixture.GetDocument(id);
75+
Assert.Equal(ScheduleState.Pending, actual["State"]);
6376
}
6477

6578

66-
[Fact(Skip = "Required a database")]
79+
[Fact]
6780
public void Should_be_able_to_mark_as_published()
6881
{
69-
scheduleRepository.MarkAsPublished(Guid.Empty);
82+
var id = Guid.NewGuid();
83+
databaseFixture.InitializeOne(id);
84+
scheduleRepository.MarkAsPublished(id);
85+
86+
var actual = databaseFixture.GetDocument(id);
87+
88+
Assert.Equal(ScheduleState.Published, actual["State"]);
89+
}
90+
91+
[Fact]
92+
public void Should_be_able_to_get_original_message()
93+
{
94+
databaseFixture.InitDocumentsWithOriginalBSON();
95+
var actualIds = new HashSet<Guid>();
96+
while (true)
97+
{
98+
var schedule = scheduleRepository.GetPending();
99+
if (schedule == null)
100+
break;
101+
102+
actualIds.Add(schedule.Id);
103+
}
104+
105+
Assert.True(actualIds.Count > 0);
106+
Assert.Contains(databaseFixture.PendingOldDocId, actualIds);
70107
}
71108
}
72109
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Text;
6+
using MongoDB.Bson;
7+
using MongoDB.Bson.Serialization;
8+
using MongoDB.Bson.Serialization.Conventions;
9+
using MongoDB.Driver;
10+
11+
namespace EasyNetQ.Scheduler.Mongo.Tests
12+
{
13+
14+
public class SchedulesDatabaseFixture : IDisposable
15+
{
16+
public readonly IMongoCollection<BsonDocument> Collection;
17+
public readonly Guid PendingOldDocId = Guid.Parse("b0417f2c-9fbe-45b8-9a3f-8bad303157d7");
18+
private readonly IMongoDatabase database;
19+
20+
public readonly ScheduleRepositoryConfiguration Configuration = new ScheduleRepositoryConfiguration
21+
{
22+
ConnectionString = "mongodb://localhost:27017/?w=1&readPreference=primary&uuidRepresentation=csharpLegacy",
23+
CollectionName = "Schedules",
24+
DatabaseName = "EasyNetQ",
25+
DeleteTimeout = TimeSpan.FromMinutes(5),
26+
PublishTimeout = TimeSpan.FromSeconds(60),
27+
};
28+
29+
public SchedulesDatabaseFixture()
30+
{
31+
InitializeMongoConventions();
32+
database = CreateDatabase(new MongoUrl(Configuration.ConnectionString), Configuration.DatabaseName);
33+
Collection = database.GetCollection<BsonDocument>(Configuration.CollectionName);
34+
}
35+
36+
public void Dispose()
37+
{
38+
39+
}
40+
41+
public void InitScheduleWithCancellation(string cancellation)
42+
{
43+
var schedule = new Schedule
44+
{
45+
CancellationKey = cancellation,
46+
Id = Guid.NewGuid()
47+
};
48+
Collection.InsertOne(schedule.ToBsonDocument());
49+
}
50+
51+
public void InitializeOne(Guid id, ScheduleState state = ScheduleState.Pending, DateTime? wakeTime = null, DateTime? publishingTime = null)
52+
{
53+
var schedule = new Schedule
54+
{
55+
Id = id,
56+
State = state,
57+
WakeTime = wakeTime ?? DateTime.UtcNow.AddDays(-1),
58+
PublishingTime = publishingTime
59+
};
60+
Collection.InsertOne(schedule.ToBsonDocument());
61+
}
62+
63+
public BsonDocument GetDocument(Guid id)
64+
=> database.GetCollection<BsonDocument>(Configuration.CollectionName)
65+
.Find(d => d["_id"] == id)
66+
.FirstOrDefault();
67+
68+
public void InitDocumentsWithOriginalBSON()
69+
{
70+
var bsons = LoadOldBSONs().ToList();
71+
Collection.InsertMany(bsons);
72+
}
73+
74+
private static IEnumerable<BsonDocument> LoadOldBSONs()
75+
{
76+
var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "BSONs");
77+
foreach (var fileName in Directory.GetFiles(path))
78+
{
79+
var content = File.ReadAllText(fileName);
80+
var bson = BsonSerializer.Deserialize<BsonDocument>(content);
81+
yield return bson;
82+
}
83+
}
84+
85+
private static IMongoDatabase CreateDatabase(MongoUrl connectionString, string databaseName)
86+
{
87+
var settings = MongoClientSettings.FromUrl(connectionString);
88+
settings.ReadEncoding = new UTF8Encoding(false, false);
89+
var client = new MongoClient(settings);
90+
return client.GetDatabase(databaseName);
91+
}
92+
93+
private static void InitializeMongoConventions()
94+
{
95+
ConventionRegistry.Register("ignoreIfNull", new ConventionPack {new IgnoreIfNullConvention(true)}, t => true);
96+
ConventionRegistry.Register("ignoreExtraElements", new ConventionPack {new IgnoreExtraElementsConvention(true)}, t => true);
97+
}
98+
}
99+
}

Source/EasyNetQ.Scheduler.Mongo/ScheduleRepository.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using System;
22
using System.Text;
3+
using MongoDB.Bson.Serialization.Conventions;
34
using MongoDB.Driver;
4-
using MongoDB.Driver.Builders;
55

66
namespace EasyNetQ.Scheduler.Mongo
77
{
@@ -79,6 +79,7 @@ public void HandleTimeout()
7979

8080
private IMongoCollection<Schedule> CreateAndIndex()
8181
{
82+
InitializeMongoConventions();
8283
var collection = GetICollection<Schedule>(configuration.ConnectionString, configuration.DatabaseName, configuration.CollectionName);
8384
collection.Indexes.CreateOne(new CreateIndexModel<Schedule>(
8485
Builders<Schedule>.IndexKeys.Ascending(x => x.CancellationKey),
@@ -112,5 +113,11 @@ private static IMongoCollection<TDocument> GetICollection<TDocument>(string conn
112113
var database = CreateDatabase(new MongoUrl(connectionString), databaseName);
113114
return database.GetCollection<TDocument>(collectionName);
114115
}
116+
117+
private static void InitializeMongoConventions()
118+
{
119+
ConventionRegistry.Register("ignoreIfNull", new ConventionPack {new IgnoreIfNullConvention(true)}, t => true);
120+
ConventionRegistry.Register("ignoreExtraElements", new ConventionPack {new IgnoreExtraElementsConvention(true)}, t => true);
121+
}
115122
}
116123
}

0 commit comments

Comments
 (0)