I found a bug in OpenTap 9.21, and hope it will be fixed in the next release

I found a bug in OpenTap 9.21, and hope it will be fixed in the next release.
I am running two test plans parallelly by calling TestPlan.ExecuteAsync at the same time. Each test plan use SCPIRegexStep to send SCPI commands to a different instrument.
But I got an exception at this line:return membersLookup.AddValue((targetType, sourceType), (result?.ToArray() ?? Array.Empty<(IMemberData, bool)>()));
in the following function:
static (IMemberData, bool hasEnabledAttribute) GetSettingsLookup(TypeData targetType, ITypeData sourceType)
{
if(membersLookup.TryGetValue((targetType, sourceType), out var value))
return value;

return membersLookup.AddValue((targetType, sourceType), (result?.ToArray() ?? Array.Empty<(IMemberData, bool)>()));
}
Because after the first task call membersLookup.AddValue, the second task with the same key can not add duplicate key into membersLookup.

the exception call stack is as follows:
2023-10-07 10:11:22.024213 ; TestPlan ; Warning ; TestPlan aborted.
2023-10-07 10:11:22.025078 ; TestPlan ; Error ; An element with the same key but a different value already exists. Key: ‘(OpenTap.IResource, OpenTap.Plugins.BasicSteps.SCPIRegexStep)’
2023-10-07 10:11:22.030716 ; TestPlan ; Debug ; ArgumentException: An element with the same key but a different value already exists. Key: ‘(OpenTap.IResource, OpenTap.Plugins.BasicSteps.SCPIRegexStep)’
2023-10-07 10:11:22.081944 ; TestPlan ; Debug ; at System.Collections.Immutable.ImmutableDictionary2.HashBucket.Add(TKey key, TValue value, IEqualityComparer1 keyOnlyComparer, IEqualityComparer1 valueComparer, KeyCollisionBehavior behavior, OperationResult& result) 2023-10-07 10:11:22.081952 ; TestPlan ; Debug ; at System.Collections.Immutable.ImmutableDictionary2.Add(TKey key, TValue value, KeyCollisionBehavior behavior, MutationInput origin)
2023-10-07 10:11:22.081953 ; TestPlan ; Debug ; at System.Collections.Immutable.ImmutableDictionary2.Add(TKey key, TValue value) 2023-10-07 10:11:22.081955 ; TestPlan ; Debug ; at OpenTap.TestStepExtensions.GetSettingsLookup(TypeData targetType, ITypeData sourceType) 2023-10-07 10:11:22.081957 ; TestPlan ; Debug ; at OpenTap.TestStepExtensions.GetObjectSettings[T,T2,T3](T2 item, Boolean onlyEnabled, Func3 transform, HashSet1 itemSet, TypeData targetType) 2023-10-07 10:11:22.081959 ; TestPlan ; Debug ; at OpenTap.TestStepExtensions.GetObjectSettings[T,T2,T3](IEnumerable1 objects, Boolean onlyEnabled, Func3 transform, HashSet1 itemSet)
2023-10-07 10:11:22.081961 ; TestPlan ; Debug ; at OpenTap.ResourceDependencyAnalyzer.getManyResources[T](T steps)
2023-10-07 10:11:22.081963 ; TestPlan ; Debug ; at OpenTap.ResourceDependencyAnalyzer.GetAllResources(Object references, Boolean& errorDetected)
2023-10-07 10:11:22.081964 ; TestPlan ; Debug ; at OpenTap.ResourceManagerUtils.GetResourceNodesNoCache(Object source)
2023-10-07 10:11:22.081966 ; TestPlan ; Debug ; at OpenTap.ResourceManagerUtils.GetResourceNodes(IEnumerable1 _source) 2023-10-07 10:11:22.081970 ; TestPlan ; Debug ; at OpenTap.ResourceTaskManager.BeginStep(TestPlanRun planRun, ITestStepParent item, TestPlanExecutionStage stage, CancellationToken cancellationToken) 2023-10-07 10:11:22.081972 ; TestPlan ; Debug ; at OpenTap.TestPlan.OpenInternal(TestPlanRun run, Boolean isOpen, List1 steps)

I tried to fix this bug by replacing return membersLookup.AddValue((targetType, sourceType), (result?.ToArray() ?? Array.Empty<(IMemberData, bool)>())); with the following code, and it seems works:
static readonly object lookupLock = new object();
static (IMemberData, bool hasEnabledAttribute) GetSettingsLookup(TypeData targetType, ITypeData sourceType)
{
if(membersLookup.TryGetValue((targetType, sourceType), out var value))
return value;

lock (lookupLock)
{
if (!membersLookupCache.TryGetValue((targetType, sourceType), out value))
{
value = membersLookupCache.AddValue((targetType, sourceType), (result?.ToArray() ?? Array.Empty<(IMemberData, bool)>()));
}
}
return value;
}

1 Like

Hi @allen ,

Thanks for highlighting the issue.

I have submitted a PR which fixes the issue here: 1282-GetSettingsLookupRaceFix: Test by rmadsen-ks · Pull Request #1283 · opentap/opentap · GitHub

Hi Rolf,
Thanks for your quick reponse,is there any plan when this fix will be included in the next release? So that I can download the new release.

You caught us at a great time, I expect the next release (9.22) will be early next week.

If you want to try it out you can start using the release candidate: (OpenTAP 9.22.0-rc.3+638974b3)

@allen, fyi OpenTAP 9.22 was released a few weeks ago. It includes this bug fix.