From f197d24c4c2c19b3616fb3b08d6009b5fb3149c4 Mon Sep 17 00:00:00 2001 From: Eric LeVin Date: Sat, 6 May 2023 15:01:14 -0500 Subject: [PATCH 1/3] added docker-compose for tests --- .gitignore | 2 ++ .../Jobs/SimpleJobWithData.cs | 16 ++++++++++++++++ tests/docker-compose.yaml | 19 +++++++++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 tests/Quartz.Spi.MongoDbJobStore.Tests/Jobs/SimpleJobWithData.cs create mode 100644 tests/docker-compose.yaml diff --git a/.gitignore b/.gitignore index 8ca3cfc..dc9f2b6 100644 --- a/.gitignore +++ b/.gitignore @@ -264,3 +264,5 @@ paket-files/ __pycache__/ *.pyc *.DotSettings + +tests/data \ No newline at end of file diff --git a/tests/Quartz.Spi.MongoDbJobStore.Tests/Jobs/SimpleJobWithData.cs b/tests/Quartz.Spi.MongoDbJobStore.Tests/Jobs/SimpleJobWithData.cs new file mode 100644 index 0000000..ed66b39 --- /dev/null +++ b/tests/Quartz.Spi.MongoDbJobStore.Tests/Jobs/SimpleJobWithData.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Quartz.Spi.MongoDbJobStore.Tests.Jobs +{ + public class SimpleJob : IJob + { + public Task Execute(IJobExecutionContext context) + { + throw new NotImplementedException(); + } + } +} diff --git a/tests/docker-compose.yaml b/tests/docker-compose.yaml new file mode 100644 index 0000000..0b1db21 --- /dev/null +++ b/tests/docker-compose.yaml @@ -0,0 +1,19 @@ +version: '3.1' + +services: + + mongo: + image: mongo + restart: always + ports: + - 27017:27017 + volumes: + - ./data:/data/db + + mongo-express: + image: mongo-express + restart: always + ports: + - 8081:8081 + environment: + ME_CONFIG_MONGODB_URL: mongodb://mongod:27017/ \ No newline at end of file From 8a08eb5dd48c8355b59b972883e35013cfd7d7ad Mon Sep 17 00:00:00 2001 From: Eric LeVin Date: Sat, 6 May 2023 15:09:16 -0500 Subject: [PATCH 2/3] Working with Mongo 2.4.2 and Quartz 3.6.2 --- .../Models/JobDetail.cs | 4 +- .../MongoDbJobStore.cs | 7 +++- .../Quartz.Spi.MongoDbJobStore.csproj | 8 ++-- .../Repositories/JobDetailRepository.cs | 13 +++++-- .../Repositories/JobStoreClassMap.cs | 30 ++++++++++---- .../Repositories/TriggerRepository.cs | 37 +++++++++++++----- .../Util/LogicalThreadContext.cs | 15 +------ .../BaseStoreTests.cs | 4 +- .../Jobs/SimpleJobWithData.cs | 35 ++++++++++++++++- .../MongoDbJobStoreTests.cs | 39 ++++++++++++++++++- .../Quartz.Spi.MongoDbJobStore.Tests.csproj | 2 +- 11 files changed, 146 insertions(+), 48 deletions(-) diff --git a/src/Quartz.Spi.MongoDbJobStore/Models/JobDetail.cs b/src/Quartz.Spi.MongoDbJobStore/Models/JobDetail.cs index 5b83c02..33cea4a 100644 --- a/src/Quartz.Spi.MongoDbJobStore/Models/JobDetail.cs +++ b/src/Quartz.Spi.MongoDbJobStore/Models/JobDetail.cs @@ -45,8 +45,8 @@ public IJobDetail GetJobDetail() // The missing properties are figured out at runtime from the job type attributes return new JobDetailImpl() { - Key = new JobKey(Id.Name, Id.Group), - Description = Description, + Name = Id.Name, + Group = Id.Group, JobType = JobType, JobDataMap = JobDataMap, Durable = Durable, diff --git a/src/Quartz.Spi.MongoDbJobStore/MongoDbJobStore.cs b/src/Quartz.Spi.MongoDbJobStore/MongoDbJobStore.cs index 1f13df4..4e66fc8 100644 --- a/src/Quartz.Spi.MongoDbJobStore/MongoDbJobStore.cs +++ b/src/Quartz.Spi.MongoDbJobStore/MongoDbJobStore.cs @@ -531,6 +531,11 @@ public async Task GetTriggerState(TriggerKey triggerKey, } } + public Task ResetTriggerFromErrorState(TriggerKey triggerKey, CancellationToken cancellationToken = new CancellationToken()) + { + throw new NotImplementedException(); + } + public async Task PauseTrigger(TriggerKey triggerKey, CancellationToken token = default(CancellationToken)) { try @@ -1347,7 +1352,7 @@ await _triggerRepository.UpdateTriggerState(triggerKey, Models.TriggerState.Erro var operableTrigger = (IOperableTrigger) nextTrigger.GetTrigger(); operableTrigger.FireInstanceId = GetFiredTriggerRecordId(); - + var firedTrigger = new FiredTrigger(operableTrigger.FireInstanceId, nextTrigger, null) { State = Models.TriggerState.Acquired, diff --git a/src/Quartz.Spi.MongoDbJobStore/Quartz.Spi.MongoDbJobStore.csproj b/src/Quartz.Spi.MongoDbJobStore/Quartz.Spi.MongoDbJobStore.csproj index 7445a82..e530c40 100644 --- a/src/Quartz.Spi.MongoDbJobStore/Quartz.Spi.MongoDbJobStore.csproj +++ b/src/Quartz.Spi.MongoDbJobStore/Quartz.Spi.MongoDbJobStore.csproj @@ -1,15 +1,17 @@ - net452;net462;netstandard2.0 + netstandard2.1 Quartz.Spi.MongoDbJobStore true - - + + + + diff --git a/src/Quartz.Spi.MongoDbJobStore/Repositories/JobDetailRepository.cs b/src/Quartz.Spi.MongoDbJobStore/Repositories/JobDetailRepository.cs index 8bddd56..f0fae0f 100644 --- a/src/Quartz.Spi.MongoDbJobStore/Repositories/JobDetailRepository.cs +++ b/src/Quartz.Spi.MongoDbJobStore/Repositories/JobDetailRepository.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using MongoDB.Bson; using MongoDB.Driver; using Quartz.Impl.Matchers; using Quartz.Spi.MongoDbJobStore.Extensions; @@ -24,12 +25,16 @@ public async Task GetJob(JobKey jobKey) public async Task> GetJobsKeys(GroupMatcher matcher) { - return - await Collection.Find(FilterBuilder.And( + var items = await Collection.Find(FilterBuilder.And( FilterBuilder.Eq(detail => detail.Id.InstanceName, InstanceName), FilterBuilder.Regex(detail => detail.Id.Group, matcher.ToBsonRegularExpression()))) - .Project(detail => detail.Id.GetJobKey()) - .ToListAsync().ConfigureAwait(false); + .Project(detail => new + { + Name = detail.Id.Name, + Group = detail.Id.Group + }) + .ToListAsync().ConfigureAwait(false); + return items.Select(jd => JobKey.Create(jd.Name, jd.Group)).ToList(); } public async Task> GetJobGroupNames() diff --git a/src/Quartz.Spi.MongoDbJobStore/Repositories/JobStoreClassMap.cs b/src/Quartz.Spi.MongoDbJobStore/Repositories/JobStoreClassMap.cs index af0be81..57261d6 100644 --- a/src/Quartz.Spi.MongoDbJobStore/Repositories/JobStoreClassMap.cs +++ b/src/Quartz.Spi.MongoDbJobStore/Repositories/JobStoreClassMap.cs @@ -11,37 +11,51 @@ namespace Quartz.Spi.MongoDbJobStore.Repositories { internal static class JobStoreClassMap { + public static BsonClassMap RegisterClassMap( + Action> classMapInitializer) + { + try + { + return BsonClassMap.RegisterClassMap(map => + classMapInitializer(map)); + } + catch (Exception ex) + { + throw; + } + } + public static void RegisterClassMaps() { BsonSerializer.RegisterGenericSerializerDefinition(typeof (ISet<>), typeof (SetSerializer<>)); - BsonSerializer.RegisterSerializer(new JobDataMapSerializer()); + // BsonSerializer.RegisterSerializer(new JobDataMapSerializer()); - BsonClassMap.RegisterClassMap>(map => + RegisterClassMap>(map => { map.AutoMap(); map.MapProperty(key => key.Group); map.MapProperty(key => key.Name); map.AddKnownType(typeof(JobKey)); }); - BsonClassMap.RegisterClassMap>(map => + RegisterClassMap>(map => { map.AutoMap(); map.MapProperty(key => key.Group); map.MapProperty(key => key.Name); map.AddKnownType(typeof(TriggerKey)); }); - BsonClassMap.RegisterClassMap(map => + RegisterClassMap(map => { map.MapCreator(jobKey => new JobKey(jobKey.Name)); map.MapCreator(jobKey => new JobKey(jobKey.Name, jobKey.Group)); }); - BsonClassMap.RegisterClassMap(map => + RegisterClassMap(map => { map.MapCreator(triggerKey => new TriggerKey(triggerKey.Name)); map.MapCreator(triggerKey => new TriggerKey(triggerKey.Name, triggerKey.Group)); }); - BsonClassMap.RegisterClassMap(map => + RegisterClassMap(map => { map.AutoMap(); map.MapProperty(day => day.Hour); @@ -51,13 +65,13 @@ public static void RegisterClassMaps() map.MapCreator(day => new TimeOfDay(day.Hour, day.Minute)); }); - BsonClassMap.RegisterClassMap(map => + RegisterClassMap(map => { map.AutoMap(); map.MapProperty(detail => detail.JobType).SetSerializer(new TypeSerializer()); }); - BsonClassMap.RegisterClassMap(map => + RegisterClassMap(map => { map.AutoMap(); var serializer = diff --git a/src/Quartz.Spi.MongoDbJobStore/Repositories/TriggerRepository.cs b/src/Quartz.Spi.MongoDbJobStore/Repositories/TriggerRepository.cs index e2ea6c7..d1abf7d 100644 --- a/src/Quartz.Spi.MongoDbJobStore/Repositories/TriggerRepository.cs +++ b/src/Quartz.Spi.MongoDbJobStore/Repositories/TriggerRepository.cs @@ -62,18 +62,28 @@ public async Task> GetTriggers(JobKey jobKey) public async Task> GetTriggerKeys(GroupMatcher matcher) { - return await Collection.Find(FilterBuilder.And( + var items = await Collection.Find(FilterBuilder.And( FilterBuilder.Eq(trigger => trigger.Id.InstanceName, InstanceName), FilterBuilder.Regex(trigger => trigger.Id.Group, matcher.ToBsonRegularExpression()))) - .Project(trigger => trigger.Id.GetTriggerKey()) + .Project(detail => new + { + Name = detail.Id.Name, + Group = detail.Id.Group + }) .ToListAsync().ConfigureAwait(false); + return items.Select(tk => new TriggerKey(tk.Name, tk.Group)).ToList(); } public async Task> GetTriggerKeys(Models.TriggerState state) { - return await Collection.Find(trigger => trigger.Id.InstanceName == InstanceName && trigger.State == state) - .Project(trigger => trigger.Id.GetTriggerKey()) + var items = await Collection.Find(trigger => trigger.Id.InstanceName == InstanceName && trigger.State == state) + .Project(detail => new + { + Name = detail.Id.Name, + Group = detail.Id.Group + }) .ToListAsync().ConfigureAwait(false); + return items.Select(tk => new TriggerKey(tk.Name, tk.Group)).ToList(); } public async Task> GetTriggerGroupNames() @@ -102,7 +112,7 @@ public async Task> GetTriggersToAcquire(DateTimeOffset noLaterT var noLaterThanDateTime = noLaterThan.UtcDateTime; var noEarlierThanDateTime = noEarlierThan.UtcDateTime; - return await Collection.Find(trigger => trigger.Id.InstanceName == InstanceName && + var items = await Collection.Find(trigger => trigger.Id.InstanceName == InstanceName && trigger.State == Models.TriggerState.Waiting && trigger.NextFireTime <= noLaterThanDateTime && (trigger.MisfireInstruction == -1 || @@ -113,8 +123,13 @@ public async Task> GetTriggersToAcquire(DateTimeOffset noLaterT SortBuilder.Descending(trigger => trigger.Priority) )) .Limit(maxCount) - .Project(trigger => trigger.Id.GetTriggerKey()) + .Project(detail => new + { + Name = detail.Id.Name, + Group = detail.Id.Group + }) .ToListAsync().ConfigureAwait(false); + return items.Select(tk => new TriggerKey(tk.Name, tk.Group)).ToList(); } public async Task GetCount() @@ -236,7 +251,11 @@ public bool HasMisfiredTriggers(DateTime nextFireTime, int maxResults, out List< trigger.MisfireInstruction != MisfireInstruction.IgnoreMisfirePolicy && trigger.NextFireTime < nextFireTime && trigger.State == Models.TriggerState.Waiting) - .Project(trigger => trigger.Id.GetTriggerKey()) + .Project(detail => new + { + Name = detail.Id.Name, + Group = detail.Id.Group + }) .Sort(SortBuilder.Combine( SortBuilder.Ascending(trigger => trigger.NextFireTime), SortBuilder.Descending(trigger => trigger.Priority) @@ -247,7 +266,7 @@ public bool HasMisfiredTriggers(DateTime nextFireTime, int maxResults, out List< var hasReachedLimit = false; while (cursor.MoveNext() && !hasReachedLimit) { - foreach (var triggerKey in cursor.Current) + foreach (var tk in cursor.Current) { if (results.Count == maxResults) { @@ -255,7 +274,7 @@ public bool HasMisfiredTriggers(DateTime nextFireTime, int maxResults, out List< } else { - results.Add(triggerKey); + results.Add(new TriggerKey(tk.Name, tk.Group)); } } } diff --git a/src/Quartz.Spi.MongoDbJobStore/Util/LogicalThreadContext.cs b/src/Quartz.Spi.MongoDbJobStore/Util/LogicalThreadContext.cs index 3a6e30f..b8add38 100644 --- a/src/Quartz.Spi.MongoDbJobStore/Util/LogicalThreadContext.cs +++ b/src/Quartz.Spi.MongoDbJobStore/Util/LogicalThreadContext.cs @@ -27,6 +27,7 @@ using System.Collections.Concurrent; using System.Security; +using System.Threading; // Workaround for getting off remoting removed in NET Core: http://www.cazzulino.com/callcontext-netstandard-netcore.html #if NET452 @@ -51,17 +52,11 @@ public static class LogicalThreadContext /// The name of the item. /// The object in the call context associated with the specified name or null if no object has been stored previously -#if NET462 || NETSTANDARD2_0 static ConcurrentDictionary> state = new ConcurrentDictionary>(); -#endif public static T GetData(string name) { -#if NET452 - return (T)CallContext.GetData(name); -#elif NET462 || NETSTANDARD2_0 return state.TryGetValue(name, out AsyncLocal data) ? (T)data.Value : default(T); -#endif } /// @@ -71,11 +66,7 @@ public static T GetData(string name) /// The object to store in the call context. public static void SetData(string name, object value) { -#if NET452 - CallContext.SetData(name, value); -#elif NET462 || NETSTANDARD2_0 state.GetOrAdd(name, _ => new AsyncLocal()).Value = value; -#endif } /// @@ -84,11 +75,7 @@ public static void SetData(string name, object value) /// The name of the data slot to empty. public static void FreeNamedDataSlot(string name) { -#if NET452 - CallContext.FreeNamedDataSlot(name); -#elif NET462 || NETSTANDARD2_0 state.TryRemove(name, out AsyncLocal discard); -#endif } } } \ No newline at end of file diff --git a/tests/Quartz.Spi.MongoDbJobStore.Tests/BaseStoreTests.cs b/tests/Quartz.Spi.MongoDbJobStore.Tests/BaseStoreTests.cs index 665f2d6..737613b 100644 --- a/tests/Quartz.Spi.MongoDbJobStore.Tests/BaseStoreTests.cs +++ b/tests/Quartz.Spi.MongoDbJobStore.Tests/BaseStoreTests.cs @@ -9,13 +9,13 @@ public abstract class BaseStoreTests { public const string Barrier = "BARRIER"; public const string DateStamps = "DATE_STAMPS"; - public static readonly TimeSpan TestTimeout = TimeSpan.FromSeconds(125); + public static readonly TimeSpan TestTimeout = TimeSpan.FromSeconds(120); protected async Task CreateScheduler(string instanceName = "QUARTZ_TEST") { var properties = new NameValueCollection { - ["quartz.serializer.type"] = "binary", + ["quartz.serializer.type"] = "json", [StdSchedulerFactory.PropertySchedulerInstanceName] = instanceName, [StdSchedulerFactory.PropertySchedulerInstanceId] = $"{Environment.MachineName}-{Guid.NewGuid()}", [StdSchedulerFactory.PropertyJobStoreType] = typeof(MongoDbJobStore).AssemblyQualifiedName, diff --git a/tests/Quartz.Spi.MongoDbJobStore.Tests/Jobs/SimpleJobWithData.cs b/tests/Quartz.Spi.MongoDbJobStore.Tests/Jobs/SimpleJobWithData.cs index ed66b39..e2c7fb6 100644 --- a/tests/Quartz.Spi.MongoDbJobStore.Tests/Jobs/SimpleJobWithData.cs +++ b/tests/Quartz.Spi.MongoDbJobStore.Tests/Jobs/SimpleJobWithData.cs @@ -2,15 +2,46 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Threading; using System.Threading.Tasks; namespace Quartz.Spi.MongoDbJobStore.Tests.Jobs { - public class SimpleJob : IJob + public class SimpleJobWithData : IJob { + public string MyTestVar { get; set; } + + public static JobDataMap Create(string myVar) + { + return new JobDataMap((IDictionary)new Dictionary() + { + { nameof(MyTestVar), myVar } + }); + } + public Task Execute(IJobExecutionContext context) { - throw new NotImplementedException(); + try + { + var jobExecTimestamps = (List) context.Scheduler.Context.Get(BaseStoreTests.DateStamps); + var barrier = (Barrier) context.Scheduler.Context.Get(BaseStoreTests.Barrier); + + if (string.IsNullOrEmpty(MyTestVar)) + { + throw new ApplicationException($"{nameof(MyTestVar)} should not be empty."); + } + + jobExecTimestamps.Add(DateTime.UtcNow); + + barrier.SignalAndWait(BaseStoreTests.TestTimeout); + } + catch (Exception e) + { + Console.Write(e); + throw e; + } + + return Task.FromResult(0); } } } diff --git a/tests/Quartz.Spi.MongoDbJobStore.Tests/MongoDbJobStoreTests.cs b/tests/Quartz.Spi.MongoDbJobStore.Tests/MongoDbJobStoreTests.cs index 4e9424b..2f37c70 100644 --- a/tests/Quartz.Spi.MongoDbJobStore.Tests/MongoDbJobStoreTests.cs +++ b/tests/Quartz.Spi.MongoDbJobStore.Tests/MongoDbJobStoreTests.cs @@ -285,6 +285,38 @@ public async Task TestAbilityToFireImmediatelyWhenStartedBeforeWithTriggerJob() // This is dangerously subjective! but what else to do? } + [Fact] + public async Task TestJobDataIsInjectedProperly() + { + var jobExecTimestamps = new List(); + + var barrier = new Barrier(2); + + _scheduler.Context.Put(Barrier, barrier); + _scheduler.Context.Put(DateStamps, jobExecTimestamps); + + var job1 = JobBuilder.Create().WithIdentity("job1") + .SetJobData(SimpleJobWithData.Create("test-variable")).Build(); + var trigger1 = TriggerBuilder.Create().ForJob(job1).Build(); + + var sTime = DateTime.UtcNow; + + await _scheduler.ScheduleJob(job1, trigger1); + await _scheduler.Start(); + + barrier.SignalAndWait(TestTimeout); + + await _scheduler.Shutdown(false); + + Assert.NotEmpty(jobExecTimestamps); + var fTime = jobExecTimestamps.First(); + var diff = fTime - sTime; + var isFastEnough = diff < TimeSpan.FromMilliseconds(7000); + + isFastEnough.Should().BeTrue("Immediate trigger did not fire within a reasonable amount of time."); + // This is dangerously subjective! but what else to do? + } + [Fact] public async Task TestAbilityToFireImmediatelyWhenStartedAfter() { @@ -307,9 +339,12 @@ public async Task TestAbilityToFireImmediatelyWhenStartedAfter() await _scheduler.Shutdown(false); - var fTime = jobExecTimestamps[0]; + Assert.NotEmpty(jobExecTimestamps); + var fTime = jobExecTimestamps.First(); + var diff = fTime - sTime; + var isFastEnough = diff < TimeSpan.FromMilliseconds(7000); - (fTime - sTime < TimeSpan.FromMilliseconds(7000)).Should().BeTrue("Immediate trigger did not fire within a reasonable amount of time."); + isFastEnough.Should().BeTrue("Immediate trigger did not fire within a reasonable amount of time."); // This is dangerously subjective! but what else to do? } diff --git a/tests/Quartz.Spi.MongoDbJobStore.Tests/Quartz.Spi.MongoDbJobStore.Tests.csproj b/tests/Quartz.Spi.MongoDbJobStore.Tests/Quartz.Spi.MongoDbJobStore.Tests.csproj index 1296fae..9a72e59 100644 --- a/tests/Quartz.Spi.MongoDbJobStore.Tests/Quartz.Spi.MongoDbJobStore.Tests.csproj +++ b/tests/Quartz.Spi.MongoDbJobStore.Tests/Quartz.Spi.MongoDbJobStore.Tests.csproj @@ -1,7 +1,7 @@ - net452;net462;netcoreapp2.0 + net6.0 false Quartz.Spi.MongoDbJobStore.Tests Quartz.Spi.MongoDbJobStore.Tests From 32fa6e586e72a642df0399d3e6e43df8fd9f7cfb Mon Sep 17 00:00:00 2001 From: Eric LeVin Date: Sat, 6 May 2023 17:08:11 -0500 Subject: [PATCH 3/3] Got JobData serializing correctly with complex types --- .../Repositories/JobStoreClassMap.cs | 14 ++----- .../Serializers/JobDataMapSerializer.cs | 38 ++++++++++++++----- .../Jobs/SimpleJobWithData.cs | 18 ++++++--- .../MongoDbJobStoreTests.cs | 2 +- 4 files changed, 46 insertions(+), 26 deletions(-) diff --git a/src/Quartz.Spi.MongoDbJobStore/Repositories/JobStoreClassMap.cs b/src/Quartz.Spi.MongoDbJobStore/Repositories/JobStoreClassMap.cs index 57261d6..842a452 100644 --- a/src/Quartz.Spi.MongoDbJobStore/Repositories/JobStoreClassMap.cs +++ b/src/Quartz.Spi.MongoDbJobStore/Repositories/JobStoreClassMap.cs @@ -11,24 +11,16 @@ namespace Quartz.Spi.MongoDbJobStore.Repositories { internal static class JobStoreClassMap { - public static BsonClassMap RegisterClassMap( + private static BsonClassMap RegisterClassMap( Action> classMapInitializer) { - try - { - return BsonClassMap.RegisterClassMap(map => - classMapInitializer(map)); - } - catch (Exception ex) - { - throw; - } + return BsonClassMap.RegisterClassMap(classMapInitializer); } public static void RegisterClassMaps() { BsonSerializer.RegisterGenericSerializerDefinition(typeof (ISet<>), typeof (SetSerializer<>)); - // BsonSerializer.RegisterSerializer(new JobDataMapSerializer()); + BsonSerializer.RegisterSerializer(new JobDataMapSerializer()); RegisterClassMap>(map => { diff --git a/src/Quartz.Spi.MongoDbJobStore/Serializers/JobDataMapSerializer.cs b/src/Quartz.Spi.MongoDbJobStore/Serializers/JobDataMapSerializer.cs index 29d804f..7791192 100644 --- a/src/Quartz.Spi.MongoDbJobStore/Serializers/JobDataMapSerializer.cs +++ b/src/Quartz.Spi.MongoDbJobStore/Serializers/JobDataMapSerializer.cs @@ -2,6 +2,8 @@ using MongoDB.Bson; using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using Quartz.Simpl; namespace Quartz.Spi.MongoDbJobStore.Serializers @@ -9,29 +11,47 @@ namespace Quartz.Spi.MongoDbJobStore.Serializers internal class JobDataMapSerializer : SerializerBase { private readonly DefaultObjectSerializer _objectSerializer = new DefaultObjectSerializer(); + private readonly JsonSerializerSettings _serializerSettings; + public JobDataMapSerializer() + { + _serializerSettings = new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore, + TypeNameHandling = TypeNameHandling.Auto, + TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple + }; + } + + public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, JobDataMap value) { - if (value == null) + if (value.Count == 0) { context.Writer.WriteNull(); return; } - - var base64 = Convert.ToBase64String(_objectSerializer.Serialize(value)); - context.Writer.WriteString(base64); + + var json = JsonConvert.SerializeObject(value, _serializerSettings); + var document = BsonDocument.Parse(json); + + var serializer = BsonSerializer.LookupSerializer(typeof(BsonDocument)); + serializer.Serialize(context, document); } - + public override JobDataMap Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) { if (context.Reader.CurrentBsonType == BsonType.Null) { context.Reader.ReadNull(); - return null; + return new JobDataMap(); } - - var bytes = Convert.FromBase64String(context.Reader.ReadString()); - return _objectSerializer.DeSerialize(bytes); + + var serializer = BsonSerializer.LookupSerializer(); + var document = serializer.Deserialize(context); + var json = BsonExtensionMethods.ToJson(document); + var result = JsonConvert.DeserializeObject(json, _serializerSettings)!; + return result; } } } \ No newline at end of file diff --git a/tests/Quartz.Spi.MongoDbJobStore.Tests/Jobs/SimpleJobWithData.cs b/tests/Quartz.Spi.MongoDbJobStore.Tests/Jobs/SimpleJobWithData.cs index e2c7fb6..510b63c 100644 --- a/tests/Quartz.Spi.MongoDbJobStore.Tests/Jobs/SimpleJobWithData.cs +++ b/tests/Quartz.Spi.MongoDbJobStore.Tests/Jobs/SimpleJobWithData.cs @@ -10,12 +10,14 @@ namespace Quartz.Spi.MongoDbJobStore.Tests.Jobs public class SimpleJobWithData : IJob { public string MyTestVar { get; set; } + public List TestItems { get; set; } - public static JobDataMap Create(string myVar) + public static JobDataMap Create(string myVar, List items) { return new JobDataMap((IDictionary)new Dictionary() { - { nameof(MyTestVar), myVar } + { nameof(MyTestVar), myVar }, + { nameof(TestItems), items } }); } @@ -23,13 +25,19 @@ public Task Execute(IJobExecutionContext context) { try { - var jobExecTimestamps = (List) context.Scheduler.Context.Get(BaseStoreTests.DateStamps); - var barrier = (Barrier) context.Scheduler.Context.Get(BaseStoreTests.Barrier); - if (string.IsNullOrEmpty(MyTestVar)) { throw new ApplicationException($"{nameof(MyTestVar)} should not be empty."); } + + if (TestItems == null || TestItems.Count == 0) + { + throw new ApplicationException($"{nameof(TestItems)} should not be empty."); + } + + var jobExecTimestamps = (List) context.Scheduler.Context.Get(BaseStoreTests.DateStamps); + var barrier = (Barrier) context.Scheduler.Context.Get(BaseStoreTests.Barrier); + jobExecTimestamps.Add(DateTime.UtcNow); diff --git a/tests/Quartz.Spi.MongoDbJobStore.Tests/MongoDbJobStoreTests.cs b/tests/Quartz.Spi.MongoDbJobStore.Tests/MongoDbJobStoreTests.cs index 2f37c70..3c585dd 100644 --- a/tests/Quartz.Spi.MongoDbJobStore.Tests/MongoDbJobStoreTests.cs +++ b/tests/Quartz.Spi.MongoDbJobStore.Tests/MongoDbJobStoreTests.cs @@ -296,7 +296,7 @@ public async Task TestJobDataIsInjectedProperly() _scheduler.Context.Put(DateStamps, jobExecTimestamps); var job1 = JobBuilder.Create().WithIdentity("job1") - .SetJobData(SimpleJobWithData.Create("test-variable")).Build(); + .SetJobData(SimpleJobWithData.Create("test-variable", new List(){"test-value"})).Build(); var trigger1 = TriggerBuilder.Create().ForJob(job1).Build(); var sTime = DateTime.UtcNow;