Skip to content

Commit

Permalink
Fixes GH96: read and cache revisions (#97)
Browse files Browse the repository at this point in the history
* Extra revision functionality
- save revisions even when the revision is older than the current cached revision
- Implement read specific revisions by a thing's route/uri

* Bump versions for proper pre-release usage

* Remove ReadByRoute options

* Added unit tests and resolve related bugs

* Some administrative fixes

* Finetuning according to review

* Finetuning Assembler and RequirementsVerification

* fixes according to review

* Added unit tests for RelationalExpressionVerifiers IsMessageBusActive indicator property
  • Loading branch information
lxatstariongroup authored Mar 16, 2020
1 parent 3e3a00f commit f706c06
Show file tree
Hide file tree
Showing 23 changed files with 697 additions and 192 deletions.
2 changes: 1 addition & 1 deletion CDP4Common/CDP4Common.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<TargetFrameworks>net45;net451;net452;net46;net461;net462;net47;net471;net472;netstandard1.6;netstandard2.0</TargetFrameworks>
<Company>RHEA System S.A.</Company>
<Title>CDP4Common Community Edition</Title>
<VersionPrefix>5.1.0</VersionPrefix>
<VersionPrefix>5.1.1</VersionPrefix>
<Description>CDP4 Common Class Library that contains DTOs, POCOs</Description>
<Copyright>Copyright © RHEA System S.A.</Copyright>
<Authors>Sam, Merlin, Alex, Naron, Alexander, Yevhen</Authors>
Expand Down
45 changes: 24 additions & 21 deletions CDP4Common/Helpers/PocoThingFactory.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="PocoThingFactory.cs" company="RHEA System S.A.">
// Copyright (c) 2015-2019 RHEA System S.A.
// Copyright (c) 2015-2020 RHEA System S.A.
//
// Author: Sam Gerené, Merlin Bieze, Alex Vorobiev, Naron Phou
// Author: Sam Gerené, Merlin Bieze, Alex Vorobiev, Naron Phou, Alexander van Delft
//
// This file is part of CDP4-SDK Community Edition
//
Expand Down Expand Up @@ -33,8 +33,6 @@ namespace CDP4Common.Helpers
using CDP4Common.Types;
using NLog;

using Dto = CDP4Common.DTO;

/// <summary>
/// Provides static method to instantiate and resolve the properties of all <see cref="Thing"/>s stored in a cache.
/// Provides internal static helper methods to resolve the properties of a thing.
Expand All @@ -47,21 +45,31 @@ public static class PocoThingFactory
private static readonly Logger logger = LogManager.GetCurrentClassLogger();

/// <summary>
/// Call ResolvedReferencedProperties for the POCO <see cref="Thing"/>s
/// Resolve the POCO <see cref="Thing"/>'s properties using the assiciated DTO <see cref="DTO.Thing"/>'s properties
/// </summary>
/// <param name="dtoThings">the associated DTO <see cref="Thing"/>s with the data</param>
/// <param name="dto">the associated DTO <see cref="DTO.Thing"/> that contains the data</param>
/// <param name="poco">The <see cref="Thing"/></param>
public static void ResolveDependencies(DTO.Thing dto, Thing poco)
{
poco.ResetSentinel();
poco.ResolveProperties(dto);
}

/// <summary>
/// Get the cached POCO <see cref="Thing"/>s for the associated DTO <see cref="DTO.Thing"/>s and resolve their properties
/// </summary>
/// <param name="dtoThings">the associated DTO <see cref="DTO.Thing"/>s with the data</param>
/// <param name="cache">the cache containing the <see cref="Thing"/>s</param>
public static void ResolveDependencies(IEnumerable<DTO.Thing> dtoThings, ConcurrentDictionary<CacheKey, Lazy<CommonData.Thing>> cache)
{
foreach (var dtoThing in dtoThings)
{
var cacheKey = new CacheKey(dtoThing.Iid, dtoThing.IterationContainerId);
Lazy<Thing> associatedLazyPoco;
if (cache.TryGetValue(cacheKey, out associatedLazyPoco))

if (cache.TryGetValue(cacheKey, out var associatedLazyPoco))
{
var associatedPoco = associatedLazyPoco.Value;
associatedPoco.ResetSentinel();
associatedPoco.ResolveProperties(dtoThing);
ResolveDependencies(dtoThing, associatedPoco);
}
}
}
Expand All @@ -79,8 +87,7 @@ internal static void ResolveList<T>(this ContainerList<T> list, IEnumerable<Guid
list.Clear();
foreach (var guid in guidList)
{
T thing;
if (cache.TryGet(guid, iterationId, out thing))
if (cache.TryGet(guid, iterationId, out T thing))
{
thing.ChangeKind = ChangeKind.None;
list.Add(thing);
Expand All @@ -102,15 +109,13 @@ internal static void ResolveList<T>(this OrderedItemList<T> list, IEnumerable<Or
var orderedList = new List<OrderedItem>();
foreach (var item in orderedItemList)
{
Guid guid;
if (!Guid.TryParse(item.V.ToString(), out guid))
if (!Guid.TryParse(item.V.ToString(), out var guid))
{
logger.Error("The ordered item does not represent a Thing.");
continue;
}

T thing;
if (cache.TryGet(guid, iterationId, out thing))
if (cache.TryGet(guid, iterationId, out T thing))
{
var ordereditem = new OrderedItem {K = item.K, V = thing};
orderedList.Add(ordereditem);
Expand Down Expand Up @@ -139,7 +144,7 @@ internal static void ClearAndAddRange<T>(this List<T> list, IEnumerable<T> sourc
/// <summary>
/// Clear and add to the <see cref="OrderedItemList{T}"/> from a <see cref="IEnumerable{OrderedItem}"/>
/// </summary>
/// <typeparam name="T">The generic type of the <see cref="OrderedItemList{T}"/>. This should be a primitive type that matches the value of the <see cref="Dto.Thing"/>'s <see cref="IEnumerable{OrderedItem}"/></typeparam>
/// <typeparam name="T">The generic type of the <see cref="OrderedItemList{T}"/>. This should be a primitive type that matches the value of the <see cref="DTO.Thing"/>'s <see cref="IEnumerable{OrderedItem}"/></typeparam>
/// <param name="list">The <see cref="OrderedItemList{T}"/> to resolve</param>
/// <param name="orderedItemList">The source <see cref="IEnumerable{OrderedItem}"/></param>
internal static void ClearAndAddRange<T>(this OrderedItemList<T> list, IEnumerable<OrderedItem> orderedItemList)
Expand All @@ -161,8 +166,7 @@ internal static void ResolveList<T>(this List<T> list, IEnumerable<Guid> guidLis
list.Clear();
foreach (var guid in guidList)
{
T thing;
if (cache.TryGet(guid, iterationId, out thing))
if (cache.TryGet(guid, iterationId, out T thing))
{
list.Add(thing);
}
Expand Down Expand Up @@ -239,8 +243,7 @@ internal static T Get<T>(this ConcurrentDictionary<CacheKey, Lazy<CommonData.Thi
/// <returns>The casted <see cref="Thing"/></returns>
private static T Get<T>(this ConcurrentDictionary<CacheKey, Lazy<CommonData.Thing>> cache, CacheKey key) where T : Thing
{
Lazy<Thing> lazy;
var result = cache.TryGetValue(key, out lazy);
var result = cache.TryGetValue(key, out var lazy);
if (!result)
{
return null;
Expand Down
4 changes: 2 additions & 2 deletions CDP4Dal.NetCore.Tests/DAL/DalTestFixture.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="DalTestFixture.cs" company="RHEA System S.A.">
// Copyright (c) 2015-2019 RHEA System S.A.
// Copyright (c) 2015-2020 RHEA System S.A.
//
// Author: Sam Gerené, Merlin Bieze, Alex Vorobiev, Naron Phou
// Author: Sam Gerené, Merlin Bieze, Alex Vorobiev, Naron Phou, Alexander van Delft
//
// This file is part of CDP4-SDK Community Edition
//
Expand Down
4 changes: 2 additions & 2 deletions CDP4Dal.NetCore.Tests/SessionTestFixture.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="SessionTestFixture.cs" company="RHEA System S.A.">
// Copyright (c) 2015-2019 RHEA System S.A.
// Copyright (c) 2015-2020 RHEA System S.A.
//
// Author: Sam Gerené, Merlin Bieze, Alex Vorobiev, Naron Phou
// Author: Sam Gerené, Merlin Bieze, Alex Vorobiev, Naron Phou, Alexander van Delft
//
// This file is part of CDP4-SDK Community Edition
//
Expand Down
105 changes: 105 additions & 0 deletions CDP4Dal.Tests/AssemblerTestFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,16 @@ namespace CDP4Dal.Tests
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

using CDP4Common.CommonData;
using CDP4Common.EngineeringModelData;
using CDP4Common.SiteDirectoryData;
using CDP4Common.Types;

using CDP4Dal.Events;

using NUnit.Framework;

using Dto = CDP4Common.DTO;

[TestFixture]
Expand Down Expand Up @@ -183,6 +187,107 @@ public async Task AssertThatAssemblerSynchronizationWorks()
// checks that the removed category is no longer in the cache
Assert.AreEqual(6, assembler.Cache.Count);
Assert.IsFalse(assembler.Cache.TryGetValue(new CacheKey(categoryToRemove.Iid, null), out lazyCat));
}

[Test]
public async Task AssertThatRevisionsAreCachedCorrectly()
{
var assembler = new Assembler(this.uri);

var parameterIid = Guid.NewGuid();
var parameterRevision1 = new Dto.Parameter(parameterIid, 1); //The Parameter's 1st Revision
var parameterRevision2 = new Dto.Parameter(parameterIid, 2); //The Parameter's 2nd Revision
var parameterRevision3 = new Dto.Parameter(parameterIid, 3); //The Parameter's 3rd Revision

var valueSet1 = new Dto.ParameterValueSet(Guid.NewGuid(), 1); //ValueSet that belongs to the parameter's 1st Revision
var valueSet2 = new Dto.ParameterValueSet(Guid.NewGuid(), 1); //ValueSet that belongs to the parameter's 2nd Revision
var valueSet3 = new Dto.ParameterValueSet(Guid.NewGuid(), 1); //ValueSet that belongs to the parameter's 3rd Revision

parameterRevision1.ValueSet.Add(valueSet1.Iid);
parameterRevision2.ValueSet.Add(valueSet2.Iid);
parameterRevision3.ValueSet.Add(valueSet3.Iid);

//******************************************************************************************************************
// 1st call of Synchronize for Revision 2, which is the currently active revision
//******************************************************************************************************************
await assembler.Synchronize(new List<Dto.Thing> { parameterRevision2, valueSet2 });

//Cache should not be empty
Assert.IsNotEmpty(assembler.Cache);

//Cache should contain 2 items
Assert.AreEqual(2, assembler.Cache.Count);

//Get the cached version of the parameter
var cachedParameter = assembler.Cache.First(x => x.Value.Value.Iid == parameterRevision2.Iid).Value.Value as Parameter;

//Revision number should be 2 now
Assert.AreEqual(parameterRevision2.RevisionNumber, cachedParameter.RevisionNumber);

//Parameter should contain a ValueSet
Assert.AreEqual(1, cachedParameter.ValueSet.Count);

//Parameter should contain the correct ValueSet
Assert.AreEqual(cachedParameter.ValueSet.First().Iid, valueSet2.Iid);

//******************************************************************************************************************
// 2st call of Synchronize which introduces a newer revision: Revision nr. 3.
//******************************************************************************************************************
await assembler.Synchronize(new List<Dto.Thing> { parameterRevision3, valueSet3 });

//Cache should still contain 2 things, because parameterRevision2 is removed from cache together with valueSet2
//parameterRevision2 now is contained in the Revisions property of the cached version of the parameter
Assert.AreEqual(2, assembler.Cache.Count);

cachedParameter = assembler.Cache.First(x => x.Value.Value.Iid == parameterRevision3.Iid).Value.Value as Parameter;

//Current cached parameter version is Revision 3
Assert.AreEqual(parameterRevision3.RevisionNumber, cachedParameter.RevisionNumber);

//cached parameter should contain a ValueSet
Assert.AreEqual(1, cachedParameter.ValueSet.Count);

//cached parameter should contain exactly 1 revision
Assert.AreEqual(1, cachedParameter.Revisions.Count);

//cached parameter should contain the correct ValueSet
Assert.AreEqual(cachedParameter.ValueSet.First().Iid, valueSet3.Iid);

//Revisions property of current cached item should contain the right revision number
Assert.AreEqual(cachedParameter.Revisions.First().Value.RevisionNumber, parameterRevision2.RevisionNumber);

//******************************************************************************************************************
// 3rd call of Synchronize with older revision, that should be added as a revision to an existing cached poco
//******************************************************************************************************************
await assembler.Synchronize(new List<Dto.Thing> { parameterRevision1, valueSet1 });

//Cache should still contain 2 things, because parameterRevision1 is added to the Revisions property of the current cached parameter
Assert.AreEqual(2, assembler.Cache.Count);

cachedParameter = assembler.Cache.First(x => x.Value.Value.Iid == parameterRevision1.Iid).Value.Value as Parameter;

//parameterRevision3 is still the current cached version
Assert.AreEqual(parameterRevision3.RevisionNumber, cachedParameter.RevisionNumber);

//cached parameter should contain a ValueSet
Assert.AreEqual(1, cachedParameter.ValueSet.Count);

//cached parameter should contain the correct ValueSet
Assert.AreEqual(cachedParameter.ValueSet.First().Iid, valueSet3.Iid);

//cached parameter should contain exactly 2 revisions
Assert.AreEqual(2, cachedParameter.Revisions.Count);

var revisionParameter1 = cachedParameter.Revisions.Single(x => x.Value.Iid == parameterRevision1.Iid && x.Value.RevisionNumber == parameterRevision1.RevisionNumber).Value as Parameter;
var revisionParameter2 = cachedParameter.Revisions.Single(x => x.Value.Iid == parameterRevision2.Iid && x.Value.RevisionNumber == parameterRevision2.RevisionNumber).Value as Parameter;

//Should be empty, because an older revision than the one currently in the cache was asked for
//In that case the ValueSet belonging to the Parameter doens't get cloned (because it is unknown at that moment)
Assert.AreEqual(0, revisionParameter1.ValueSet.Count);

//Should be 1, because the ValueSet2 was cloned and added to the Parameter added to the Revisions property of the cached parameter
//when revision 3 was added to the cache
Assert.AreEqual(1, revisionParameter2.ValueSet.Count);
}

[Test]
Expand Down
Loading

0 comments on commit f706c06

Please sign in to comment.