Skip to content

Commit 2f7a932

Browse files
Alex Banceewingjm
andauthored
fix: GetUser returning wrong users for alias (#89)
* fix: GetUser(string alias) not returning new users The default behaviour wasn't returning a user for the given alias when `currentUser` was `true`. It would also cycle users when requesting the same alias in a single scenario with `currentUser` was set to `true` if the calls were separated by a call for another alias. * fix: exceptions creating base profiles Depending on the test runner, this code would fail. Synchronisation also needs to happen across processes in the case where build agents are running multiple test runs concurrently. * fix: CurrentUsers occasionally `null` Co-authored-by: Max Ewing <max.ewing@outlook.com>
1 parent 26ed97f commit 2f7a932

File tree

3 files changed

+54
-16
lines changed

3 files changed

+54
-16
lines changed

bindings/src/Capgemini.PowerApps.SpecFlowBindings/Configuration/TestConfiguration.cs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
using System.Collections.Generic;
55
using System.Configuration;
66
using System.Linq;
7-
using System.Threading;
87
using YamlDotNet.Serialization;
98

109
/// <summary>
@@ -19,8 +18,9 @@ public class TestConfiguration
1918

2019
private const string GetUserException = "Unable to retrieve user configuration. Please ensure a user with the given alias exists in the config.";
2120

21+
private static readonly Dictionary<string, UserConfiguration> CurrentUsers = new Dictionary<string, UserConfiguration>();
22+
2223
private readonly object userEnumeratorsLock = new object();
23-
private readonly ThreadLocal<UserConfiguration> currentUser = new ThreadLocal<UserConfiguration>();
2424
private Dictionary<string, IEnumerator<UserConfiguration>> userEnumerators;
2525
private string profilesBasePath;
2626

@@ -107,9 +107,9 @@ public Uri GetTestUrl()
107107
/// <returns>The user configuration.</returns>
108108
public UserConfiguration GetUser(string userAlias, bool useCurrentUser = true)
109109
{
110-
if (useCurrentUser && this.currentUser.Value != null)
110+
if (useCurrentUser && CurrentUsers.ContainsKey(userAlias))
111111
{
112-
return this.currentUser.Value;
112+
return CurrentUsers[userAlias];
113113
}
114114

115115
try
@@ -124,15 +124,30 @@ public UserConfiguration GetUser(string userAlias, bool useCurrentUser = true)
124124
aliasEnumerator.MoveNext();
125125
}
126126

127-
this.currentUser.Value = aliasEnumerator.Current;
127+
if (CurrentUsers.ContainsKey(userAlias))
128+
{
129+
CurrentUsers[userAlias] = aliasEnumerator.Current;
130+
}
131+
else
132+
{
133+
CurrentUsers.Add(userAlias, aliasEnumerator.Current);
134+
}
128135
}
129136
}
130137
catch (Exception ex)
131138
{
132139
throw new ConfigurationErrorsException($"{GetUserException} User: {userAlias}", ex);
133140
}
134141

135-
return this.currentUser.Value;
142+
return CurrentUsers[userAlias];
143+
}
144+
145+
/// <summary>
146+
/// Called internally between scenarios to reset thread state.
147+
/// </summary>
148+
internal void Flush()
149+
{
150+
CurrentUsers.Clear();
136151
}
137152
}
138153
}

bindings/src/Capgemini.PowerApps.SpecFlowBindings/Hooks/BeforeRunHooks.cs

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
{
33
using System.IO;
44
using System.Linq;
5+
using System.Threading;
56
using System.Threading.Tasks;
67
using Capgemini.PowerApps.SpecFlowBindings.Configuration;
78
using Capgemini.PowerApps.SpecFlowBindings.Steps;
89
using Microsoft.Dynamics365.UIAutomation.Api.UCI;
9-
using Microsoft.Dynamics365.UIAutomation.Browser;
1010
using TechTalk.SpecFlow;
1111

1212
/// <summary>
@@ -31,17 +31,39 @@ public static void BaseProfileSetup()
3131
var profileDirectory = UserProfileDirectories[username];
3232
var baseDirectory = Path.Combine(profileDirectory, "base");
3333

34-
Directory.CreateDirectory(baseDirectory);
34+
// SpecFlow isolation settings may run scenarios in different processes or AppDomains and [BeforeTestRun] runs per thread. Lock statement insufficient.
35+
using (var mutex = new Mutex(true, $"{nameof(BaseProfileSetup)}-{username}", out var createdNew))
36+
{
37+
if (!createdNew)
38+
{
39+
mutex.WaitOne();
40+
}
3541

36-
var userBrowserOptions = (BrowserOptionsWithProfileSupport)TestConfig.BrowserOptions.Clone();
37-
userBrowserOptions.ProfileDirectory = baseDirectory;
38-
userBrowserOptions.Headless = true;
42+
if (Directory.Exists(baseDirectory))
43+
{
44+
mutex.ReleaseMutex();
45+
return;
46+
}
3947

40-
var webClient = new WebClient(userBrowserOptions);
41-
using (new XrmApp(webClient))
42-
{
43-
var user = TestConfig.Users.First(u => u.Username == username);
44-
LoginSteps.Login(webClient.Browser.Driver, TestConfig.GetTestUrl(), user.Username, user.Password);
48+
try
49+
{
50+
Directory.CreateDirectory(baseDirectory);
51+
52+
var userBrowserOptions = (BrowserOptionsWithProfileSupport)TestConfig.BrowserOptions.Clone();
53+
userBrowserOptions.ProfileDirectory = baseDirectory;
54+
userBrowserOptions.Headless = true;
55+
56+
var webClient = new WebClient(userBrowserOptions);
57+
using (new XrmApp(webClient))
58+
{
59+
var user = TestConfig.Users.First(u => u.Username == username);
60+
LoginSteps.Login(webClient.Browser.Driver, TestConfig.GetTestUrl(), user.Username, user.Password);
61+
}
62+
}
63+
finally
64+
{
65+
mutex.ReleaseMutex();
66+
}
4567
}
4668
});
4769
}

bindings/src/Capgemini.PowerApps.SpecFlowBindings/PowerAppsStepDefiner.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ protected static void Quit()
222222
xrmApp = null;
223223
client = null;
224224
testDriver = null;
225+
testConfig?.Flush();
225226

226227
if (!string.IsNullOrEmpty(currentProfileDirectory) && Directory.Exists(currentProfileDirectory))
227228
{

0 commit comments

Comments
 (0)