chr
2026-04-05 fe750b791d5b517cc4e9bc8e99a9a75139a0cfba
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using NUnit.Framework;
using OpenTap.Engine.UnitTests;
using OpenTap.Plugins.BasicSteps;
 
namespace OpenTap.UnitTests
{
    public class ResultRow
    {
        public string ResultName { get; set; }
        public int ResultValue { get; set; }
    }
 
    public class PublishResultsSameValues : TestStep
    {
 
        public int Count { get; set; } = 100;
 
        public override void Run()
        {
            var resultValue = new Random().Next();
            for (var i = 0; i < Count; i++)
            {
                Results.Publish(new ResultRow
                {
                    ResultName = $"{this.StepRun.TestStepId}",
                    ResultValue = resultValue
                });
            }
        }
    }
    public class PublishResultsSameValues2 : TestStep
    {
 
        public int Count { get; set; } = 100;
        public override void Run()
        {
            var rnd = new Random();
            var resultValue = rnd.Next();
            var resultValue2 = rnd.NextDouble();
            
            for (var i = 0; i < Count; i++)
                Results.Publish("Test", new List<string> { "X", "Y" }, resultValue, resultValue2);   
        }
    }
 
    [TestFixture]
    public class Results2
    {
        [TestCase(typeof(PublishResultsSameValues))]
        [TestCase(typeof(PublishResultsSameValues2))]
        public void TestManyResults(Type stepType)
        {
            // this test has been a bit unstable. Repeat a few times to make sure it works.
            for (int i = 0; i < 5; i++) 
            {
                var record = new RecordAllResultListener();
                var plan = new TestPlan();
                var repeat = new RepeatStep
                {
                    Count = 10
                };
                var parallel = new ParallelStep();
 
                plan.ChildTestSteps.Add(repeat);
 
                var results1 = (TestStep)Activator.CreateInstance(stepType);
                var results2 = (TestStep)Activator.CreateInstance(stepType);
                parallel.ChildTestSteps.Add(results1);
                parallel.ChildTestSteps.Add(results2);
 
                repeat.ChildTestSteps.Add(parallel);
 
                var run = plan.Execute(new IResultListener[]
                {
                    record
                });
                Assert.AreEqual(Verdict.NotSet, run.Verdict);
                foreach (var table in record.Results)
                {
                    foreach (var column in table.Columns)
                    {
                        var distinctCount = column.Data.Cast<object>().Distinct().Count();
                        Assert.AreEqual(1, distinctCount);
                    }
                }
            }
        }
        
        [TestCase(10, 10)]
        [TestCase(50, 50)]
        [TestCase(100, 100)]
        public void TestSetParameterRaceCondition(int threadCount, int paramsPerThread)
        {
            var step = new DelayStep();
            var run = new TestStepRun(step, Guid.NewGuid(), Array.Empty<ResultParameter>());
            var threads = new Task[threadCount];
            var evt = new ManualResetEventSlim(false);
            
            for (int i = 0; i < threadCount; i++)
            {
                int i2 = i;
                threads[i2] = TapThread.StartAwaitable(() =>
                {
                    evt.Wait();
                    int start = i2 * paramsPerThread;
                    foreach (var i1 in Enumerable.Range(start, paramsPerThread))
                    {
                        run.Parameters[i1.ToString()] = i1;
                    }
                });
            }
            
            // Ensure all the threads are started and waiting on the event
            TapThread.Sleep(1000); 
            evt.Set();
            Task.WaitAll(threads);
            
            for (int i = 0; i < threadCount * paramsPerThread; i++)
            {
                var param = run.Parameters[i.ToString()];
                Assert.AreEqual(param, i);
            }
        }
 
        class ParameterAssigningResultListener : ResultListener
        {
            public List<string> Assignments = new List<string>();
            public override void OnTestStepRunStart(TestStepRun stepRun)
            {
                base.OnTestStepRunStart(stepRun);
                foreach (var assignment in Assignments)
                {
                    stepRun.Parameters[assignment] = assignment;
                }
            }
        }
 
        [Test]
        public void TestRacyResultListeners()
        {
            using var session = Session.Create(SessionOptions.OverlayComponentSettings);
            var collector = new PlanRunCollectorListener();
            var a1 = new ParameterAssigningResultListener() { Assignments = { "Param1", "Param2", "Param3" } };
            var a2 = new ParameterAssigningResultListener() { Assignments = { "Param4", "Param5", "Param6" } };
            ResultSettings.Current.Add(a1);
            ResultSettings.Current.Add(a2);
            ResultSettings.Current.Add(collector);
 
            var plan = new TestPlan();
            plan.ChildTestSteps.Add(new DelayStep());
            plan.Execute();
 
            Assert.AreEqual(collector.StepRunStartEvents[0].Verdict, Verdict.NotSet);
        }
    }
}