mirror of https://github.com/abpframework/abp.git
14 changed files with 371 additions and 109 deletions
@ -0,0 +1,43 @@ |
|||||
|
using System; |
||||
|
using MongoDB.Bson; |
||||
|
using MongoDB.Bson.Serialization; |
||||
|
using MongoDB.Bson.Serialization.Serializers; |
||||
|
|
||||
|
namespace Volo.Abp.MongoDB |
||||
|
{ |
||||
|
public class AbpMongoDbDateTimeSerializer : DateTimeSerializer |
||||
|
{ |
||||
|
protected DateTimeKind DateTimeKind { get; set; } |
||||
|
protected bool DisableDateTimeNormalization{ get; set; } |
||||
|
|
||||
|
public AbpMongoDbDateTimeSerializer(DateTimeKind dateTimeKind , bool disableDateTimeNormalization) |
||||
|
{ |
||||
|
DateTimeKind = dateTimeKind; |
||||
|
DisableDateTimeNormalization = disableDateTimeNormalization; |
||||
|
} |
||||
|
|
||||
|
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, DateTime value) |
||||
|
{ |
||||
|
context.Writer.WriteDateTime(DisableDateTimeNormalization |
||||
|
? ToMillisecondsSinceEpoch(value) |
||||
|
: ToMillisecondsSinceEpoch(DateTime.SpecifyKind(value, DateTimeKind))); |
||||
|
} |
||||
|
|
||||
|
public override DateTime Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) |
||||
|
{ |
||||
|
var dateTime = new BsonDateTime(context.Reader.ReadDateTime()).ToUniversalTime(); |
||||
|
return DateTime.SpecifyKind(dateTime, DisableDateTimeNormalization ? DateTimeKind.Unspecified : DateTimeKind); |
||||
|
} |
||||
|
|
||||
|
private static long ToMillisecondsSinceEpoch(DateTime dateTime) |
||||
|
{ |
||||
|
return (dateTime - BsonConstants.UnixEpoch).Ticks / 10000L; |
||||
|
} |
||||
|
|
||||
|
// For unit testing.
|
||||
|
internal void SetDateTimeKind(DateTimeKind dateTimeKind) |
||||
|
{ |
||||
|
DateTimeKind = dateTimeKind; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
using Microsoft.EntityFrameworkCore; |
||||
|
using Microsoft.EntityFrameworkCore.Infrastructure; |
||||
|
|
||||
|
namespace Volo.Abp.EntityFrameworkCore |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Avoid unit test caching the configure of the entity.
|
||||
|
/// OnModelCreating will be executed multiple times
|
||||
|
/// </summary>
|
||||
|
public class UnitTestModelCacheKeyFactory : IModelCacheKeyFactory |
||||
|
{ |
||||
|
public object Create(DbContext context) |
||||
|
{ |
||||
|
return context; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,9 +0,0 @@ |
|||||
using Volo.Abp.TestApp.Testing; |
|
||||
|
|
||||
namespace Volo.Abp.EntityFrameworkCore.ValueConverters |
|
||||
{ |
|
||||
public class AbpDateTimeValueConverter_Tests : AbpDateTimeValueConverter_Tests<AbpEntityFrameworkCoreTestModule> |
|
||||
{ |
|
||||
|
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,66 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Shouldly; |
||||
|
using Volo.Abp.TestApp.Domain; |
||||
|
using Volo.Abp.TestApp.Testing; |
||||
|
using Volo.Abp.Timing; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.EntityFrameworkCore.ValueConverters |
||||
|
{ |
||||
|
public abstract class EFCore_DateTimeKindTests : DateTimeKind_Tests<AbpEntityFrameworkCoreTestModule> |
||||
|
{ |
||||
|
[Fact] |
||||
|
public async Task DateTime_Kind_Should_Be_Normalized_In_View_Query_Test() |
||||
|
{ |
||||
|
var personName = "bob lee"; |
||||
|
await PersonRepository.InsertAsync(new Person(Guid.NewGuid(), personName, 18) |
||||
|
{ |
||||
|
Birthday = DateTime.Parse("2020-01-01 00:00:00"), |
||||
|
LastActive = DateTime.Parse("2020-01-01 00:00:00"), |
||||
|
}, true); |
||||
|
|
||||
|
var person = await PersonRepository.GetViewAsync(personName); |
||||
|
|
||||
|
person.ShouldNotBeNull(); |
||||
|
person.CreationTime.Kind.ShouldBe(Kind); |
||||
|
|
||||
|
person.Birthday.ShouldNotBeNull(); |
||||
|
person.Birthday.Value.Kind.ShouldBe(Kind); |
||||
|
person.Birthday.Value.ToString("yyy-MM-dd HH:mm:ss").ShouldBe("2020-01-01 00:00:00"); |
||||
|
|
||||
|
//LastActive DisableDateTimeNormalization
|
||||
|
person.LastActive.ShouldNotBeNull(); |
||||
|
person.LastActive.Value.Kind.ShouldBe(DateTimeKind.Unspecified); |
||||
|
person.LastActive.Value.ToString("yyy-MM-dd HH:mm:ss").ShouldBe("2020-01-01 00:00:00"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public class DateTimeKindTests : EFCore_DateTimeKindTests |
||||
|
{ |
||||
|
protected override void AfterAddApplication(IServiceCollection services) |
||||
|
{ |
||||
|
Kind = DateTimeKind.Unspecified; |
||||
|
services.Configure<AbpClockOptions>(x => x.Kind = Kind); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public class DateTimeKindTests_Local : EFCore_DateTimeKindTests |
||||
|
{ |
||||
|
protected override void AfterAddApplication(IServiceCollection services) |
||||
|
{ |
||||
|
Kind = DateTimeKind.Local; |
||||
|
services.Configure<AbpClockOptions>(x => x.Kind = Kind); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public class DateTimeKindTests_Utc : EFCore_DateTimeKindTests |
||||
|
{ |
||||
|
protected override void AfterAddApplication(IServiceCollection services) |
||||
|
{ |
||||
|
Kind = DateTimeKind.Utc; |
||||
|
services.Configure<AbpClockOptions>(x => x.Kind = Kind); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,81 @@ |
|||||
|
using System; |
||||
|
using System.Reflection; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using MongoDB.Bson.Serialization; |
||||
|
using MongoDB.Bson.Serialization.Serializers; |
||||
|
using Volo.Abp.TestApp.Testing; |
||||
|
using Volo.Abp.Timing; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.MongoDB.Serializer |
||||
|
{ |
||||
|
[Collection(MongoTestCollection.Name)] |
||||
|
public abstract class MongoDB_DateTimeKind_Tests : DateTimeKind_Tests<AbpMongoDbTestModule>, IDisposable |
||||
|
{ |
||||
|
protected override void AfterAddApplication(IServiceCollection services) |
||||
|
{ |
||||
|
// MongoDB uses static properties to store the mapping information,
|
||||
|
// We must reconfigure it in the new unit test.
|
||||
|
foreach (var registeredClassMap in BsonClassMap.GetRegisteredClassMaps()) |
||||
|
{ |
||||
|
var frozen = registeredClassMap.GetType().BaseType?.GetField("_frozen", BindingFlags.NonPublic | BindingFlags.Instance); |
||||
|
frozen?.SetValue(registeredClassMap, false); |
||||
|
|
||||
|
foreach (var declaredMemberMap in registeredClassMap.DeclaredMemberMaps) |
||||
|
{ |
||||
|
var serializer = declaredMemberMap.GetSerializer(); |
||||
|
switch (serializer) |
||||
|
{ |
||||
|
case AbpMongoDbDateTimeSerializer dateTimeSerializer: |
||||
|
dateTimeSerializer.SetDateTimeKind(Kind); |
||||
|
break; |
||||
|
case NullableSerializer<DateTime> nullableSerializer: |
||||
|
{ |
||||
|
var lazySerializer = nullableSerializer.GetType() |
||||
|
?.GetField("_lazySerializer", BindingFlags.NonPublic | BindingFlags.Instance) |
||||
|
?.GetValue(serializer)?.As<Lazy<IBsonSerializer<DateTime>>>(); |
||||
|
|
||||
|
if (lazySerializer?.Value is AbpMongoDbDateTimeSerializer dateTimeSerializer) |
||||
|
{ |
||||
|
dateTimeSerializer.SetDateTimeKind(Kind); |
||||
|
} |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
frozen?.SetValue(registeredClassMap, true); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public class DateTimeKindTests_Unspecified : MongoDB_DateTimeKind_Tests |
||||
|
{ |
||||
|
protected override void AfterAddApplication(IServiceCollection services) |
||||
|
{ |
||||
|
Kind = DateTimeKind.Unspecified; |
||||
|
services.Configure<AbpClockOptions>(x => x.Kind = Kind); |
||||
|
base.AfterAddApplication(services); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public class DateTimeKindTests_Local : MongoDB_DateTimeKind_Tests |
||||
|
{ |
||||
|
protected override void AfterAddApplication(IServiceCollection services) |
||||
|
{ |
||||
|
Kind = DateTimeKind.Local; |
||||
|
services.Configure<AbpClockOptions>(x => x.Kind = Kind); |
||||
|
base.AfterAddApplication(services); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public class DateTimeKindTests_Utc : MongoDB_DateTimeKind_Tests |
||||
|
{ |
||||
|
protected override void AfterAddApplication(IServiceCollection services) |
||||
|
{ |
||||
|
Kind = DateTimeKind.Utc; |
||||
|
services.Configure<AbpClockOptions>(x => x.Kind = Kind); |
||||
|
base.AfterAddApplication(services); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,30 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using MongoDB.Driver; |
||||
|
using Volo.Abp.Domain.Repositories.MongoDB; |
||||
|
using Volo.Abp.MongoDB; |
||||
|
using Volo.Abp.TestApp.Domain; |
||||
|
|
||||
|
namespace Volo.Abp.TestApp.MongoDB |
||||
|
{ |
||||
|
public class PersonRepository : MongoDbRepository<ITestAppMongoDbContext, Person, Guid>, IPersonRepository |
||||
|
{ |
||||
|
public PersonRepository(IMongoDbContextProvider<ITestAppMongoDbContext> dbContextProvider) |
||||
|
: base(dbContextProvider) |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
public async Task<PersonView> GetViewAsync(string name) |
||||
|
{ |
||||
|
var person = await (await (await GetCollectionAsync()).FindAsync(x => x.Name == name)).FirstOrDefaultAsync(); |
||||
|
return new PersonView() |
||||
|
{ |
||||
|
Name = person.Name, |
||||
|
CreationTime = person.CreationTime, |
||||
|
Birthday = person.Birthday, |
||||
|
LastActive = person.LastActive |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,73 +0,0 @@ |
|||||
using System; |
|
||||
using System.Threading.Tasks; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using Shouldly; |
|
||||
using Volo.Abp.Domain.Repositories; |
|
||||
using Volo.Abp.Modularity; |
|
||||
using Volo.Abp.TestApp.Domain; |
|
||||
using Volo.Abp.Timing; |
|
||||
using Xunit; |
|
||||
|
|
||||
namespace Volo.Abp.TestApp.Testing |
|
||||
{ |
|
||||
public abstract class AbpDateTimeValueConverter_Tests<TStartupModule> : TestAppTestBase<TStartupModule> |
|
||||
where TStartupModule : IAbpModule |
|
||||
{ |
|
||||
private readonly IPersonRepository _personRepository; |
|
||||
|
|
||||
protected AbpDateTimeValueConverter_Tests() |
|
||||
{ |
|
||||
_personRepository = GetRequiredService<IPersonRepository>(); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public async Task DateTime_Kind_Should_Be_Normalized_To_UTC_Test() |
|
||||
{ |
|
||||
var personId = Guid.Parse("4125582e-d100-4c27-aa84-e4de85830dca"); |
|
||||
await _personRepository.InsertAsync(new Person(personId, "bob lee", 18) |
|
||||
{ |
|
||||
Birthday = DateTime.Parse("2020-01-01 00:00:00"), |
|
||||
LastActive = DateTime.Parse("2020-01-01 00:00:00"), |
|
||||
}, true); |
|
||||
|
|
||||
var person = await _personRepository.GetAsync(personId); |
|
||||
|
|
||||
person.ShouldNotBeNull(); |
|
||||
person.CreationTime.Kind.ShouldBe(DateTimeKind.Utc); |
|
||||
|
|
||||
person.Birthday.ShouldNotBeNull(); |
|
||||
person.Birthday.Value.Kind.ShouldBe(DateTimeKind.Utc); |
|
||||
person.Birthday.Value.ToString("yyy-MM-dd HH:mm:ss").ShouldBe("2020-01-01 00:00:00"); |
|
||||
|
|
||||
//LastActive DisableDateTimeNormalization
|
|
||||
person.LastActive.ShouldNotBeNull(); |
|
||||
person.LastActive.Value.Kind.ShouldBe(DateTimeKind.Unspecified); |
|
||||
person.LastActive.Value.ToString("yyy-MM-dd HH:mm:ss").ShouldBe("2020-01-01 00:00:00"); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public async Task DateTime_Kind_Should_Be_Normalized_To_UTC_View_Test() |
|
||||
{ |
|
||||
var personName = "bob lee"; |
|
||||
await _personRepository.InsertAsync(new Person(Guid.NewGuid(), personName, 18) |
|
||||
{ |
|
||||
Birthday = DateTime.Parse("2020-01-01 00:00:00"), |
|
||||
LastActive = DateTime.Parse("2020-01-01 00:00:00"), |
|
||||
}, true); |
|
||||
|
|
||||
var person = await _personRepository.GetViewAsync(personName); |
|
||||
|
|
||||
person.ShouldNotBeNull(); |
|
||||
person.CreationTime.Kind.ShouldBe(DateTimeKind.Utc); |
|
||||
|
|
||||
person.Birthday.ShouldNotBeNull(); |
|
||||
person.Birthday.Value.Kind.ShouldBe(DateTimeKind.Utc); |
|
||||
person.Birthday.Value.ToString("yyy-MM-dd HH:mm:ss").ShouldBe("2020-01-01 00:00:00"); |
|
||||
|
|
||||
//LastActive DisableDateTimeNormalization
|
|
||||
person.LastActive.ShouldNotBeNull(); |
|
||||
person.LastActive.Value.Kind.ShouldBe(DateTimeKind.Unspecified); |
|
||||
person.LastActive.Value.ToString("yyy-MM-dd HH:mm:ss").ShouldBe("2020-01-01 00:00:00"); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,46 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Shouldly; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.TestApp.Domain; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.TestApp.Testing |
||||
|
{ |
||||
|
public abstract class DateTimeKind_Tests<TStartupModule> : TestAppTestBase<TStartupModule> |
||||
|
where TStartupModule : IAbpModule |
||||
|
{ |
||||
|
protected IPersonRepository PersonRepository { get; } |
||||
|
protected DateTimeKind Kind { get; set; } |
||||
|
|
||||
|
protected DateTimeKind_Tests() |
||||
|
{ |
||||
|
PersonRepository = GetRequiredService<IPersonRepository>(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task DateTime_Kind_Should_Be_Normalized_Test() |
||||
|
{ |
||||
|
var personId = Guid.NewGuid(); |
||||
|
await PersonRepository.InsertAsync(new Person(personId, "bob lee", 18) |
||||
|
{ |
||||
|
Birthday = DateTime.Parse("2020-01-01 00:00:00"), |
||||
|
LastActive = DateTime.Parse("2020-01-01 00:00:00"), |
||||
|
}, true); |
||||
|
|
||||
|
var person = await PersonRepository.GetAsync(personId); |
||||
|
|
||||
|
person.ShouldNotBeNull(); |
||||
|
person.CreationTime.Kind.ShouldBe(Kind); |
||||
|
|
||||
|
person.Birthday.ShouldNotBeNull(); |
||||
|
person.Birthday.Value.Kind.ShouldBe(Kind); |
||||
|
person.Birthday.Value.ToString("yyy-MM-dd HH:mm:ss").ShouldBe("2020-01-01 00:00:00"); |
||||
|
|
||||
|
//LastActive DisableDateTimeNormalization
|
||||
|
person.LastActive.ShouldNotBeNull(); |
||||
|
person.LastActive.Value.Kind.ShouldBe(DateTimeKind.Unspecified); |
||||
|
person.LastActive.Value.ToString("yyy-MM-dd HH:mm:ss").ShouldBe("2020-01-01 00:00:00"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue