Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: multiple users per alias #88

Merged
merged 15 commits into from
Jun 24, 2021

Conversation

ngwalker
Copy link
Contributor

Purpose

To enable the use of multiple "as an admin" alias' as the User

Approach

Added logic to the TestConfiguration class to iterate over the Users list, with conditional logic

Closes #83

@ngwalker ngwalker requested a review from ewingjm June 17, 2021 20:24
@ngwalker ngwalker self-assigned this Jun 17, 2021
Copy link
Member

@ewingjm ewingjm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple of changes suggested so that this works where there are multiple different user aliases. Suggestions not tested btw so may need some tweaks. Also just needs documenting in the README and it should be good to go 👍🏻 Thanks, @ngwalker!

@ewingjm
Copy link
Member

ewingjm commented Jun 18, 2021

OK so it's clear to me now from testing my suggested code that it's going to need a considerable amount of tweaks to get it working! 😄 Hopefully it's a bit clearer at least as to what he desired outcome is.

@ewingjm
Copy link
Member

ewingjm commented Jun 18, 2021

I've tested this and I believe it's working -

namespace Capgemini.PowerApps.SpecFlowBindings.Configuration
{
    using System;
    using System.Collections.Generic;
    using System.Configuration;
    using System.Linq;
    using Microsoft.Dynamics365.UIAutomation.Browser;
    using YamlDotNet.Serialization;

    /// <summary>
    /// Test configuration for Dynamics 365 automated UI testing.
    /// </summary>
    public class TestConfiguration
    {
        /// <summary>
        /// The name of the file that stores the test configuration.
        /// </summary>
        public const string FileName = "power-apps-bindings.yml";

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

        private object userEnumeratorsLock = new object();
        private Dictionary<string, IEnumerator<UserConfiguration>> userEnumerators;

        /// <summary>
        /// Initializes a new instance of the <see cref="TestConfiguration"/> class.
        /// </summary>
        public TestConfiguration()
        {
            this.BrowserOptions = new BrowserOptions();
        }

        /// <summary>
        /// Sets the URL of the target Dynamics 365 instance.
        /// </summary>
        [YamlMember(Alias = "url")]
        public string Url { private get; set; }

        /// <summary>
        /// Gets or sets the browser options to use for running tests.
        /// </summary>
        [YamlMember(Alias = "browserOptions")]
        public BrowserOptions BrowserOptions { get; set; }

        /// <summary>
        /// Gets or sets users that tests can be run as.
        /// </summary>
        [YamlMember(Alias = "users")]
        public List<UserConfiguration> Users { get; set; }

        /// <summary>
        /// Gets or sets application user client ID and client secret for performing certain operations (e.g. impersonating other users during test data creation).
        /// </summary>
        [YamlMember(Alias = "applicationUser")]
        public ClientCredentials ApplicationUser { get; set; }

        [YamlIgnore]
        private Dictionary<string, IEnumerator<UserConfiguration>> UserEnumerators
        {
            get
            {
                lock (this.userEnumeratorsLock)
                {
                    if (this.userEnumerators == null)
                    {
                        this.userEnumerators = this.Users
                            .Select(user => user.Alias)
                            .Distinct()
                            .ToDictionary(
                                alias => alias,
                                alias => this.Users.Where(u => u.Alias == alias).GetEnumerator());
                    }
                }

                return this.userEnumerators;
            }
        }

        /// <summary>
        /// Gets the target URL.
        /// </summary>
        /// <returns>The URL of the test environment.</returns>
        public Uri GetTestUrl()
        {
            return new Uri(ConfigHelper.GetEnvironmentVariableIfExists(this.Url));
        }

        /// <summary>
        /// Retrieves the configuration for a user.
        /// </summary>
        /// <param name="userAlias">The alias of the user.</param>
        /// <returns>The user configuration.</returns>
        public UserConfiguration GetUser(string userAlias)
        {
            UserConfiguration user;

            try
            {
                lock (this.userEnumeratorsLock)
                {
                    var aliasEnumerator = this.UserEnumerators[userAlias];
                    if (!aliasEnumerator.MoveNext())
                    {
                        this.UserEnumerators[userAlias] = this.Users.Where(u => u.Alias == userAlias).GetEnumerator();
                        aliasEnumerator = this.UserEnumerators[userAlias];
                        aliasEnumerator.MoveNext();
                    }

                    user = aliasEnumerator.Current;
                }
            }
            catch (Exception ex)
            {
                throw new ConfigurationErrorsException($"{GetUserException} User: {userAlias}", ex);
            }

            return user;
        }
    }
}

@ngwalker ngwalker requested a review from ewingjm June 21, 2021 07:56
Copy link
Contributor Author

@ngwalker ngwalker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added suggested changes

@ewingjm ewingjm changed the title added logic to support multiple as admin users feat: multiple users per alias Jun 21, 2021
README.md Outdated Show resolved Hide resolved
README.md Show resolved Hide resolved
Copy link
Member

@ewingjm ewingjm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some more changes requested as I realised this might be a breaking change for some package consumers.

Co-authored-by: Max Ewing <max.ewing@outlook.com>
Copy link
Contributor Author

@ngwalker ngwalker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requested changes applied

…n/TestConfiguration.cs

Co-authored-by: Max Ewing <max.ewing@outlook.com>
@ewingjm
Copy link
Member

ewingjm commented Jun 21, 2021

Requested changes applied

Still some more to be done to remove the surplus test user and use the new currentUser parameter. The login binding will need to be updated to pass false in order to cycle users but the default behaviour should be to return the current user for the thread (if there is one).

ewingjm
ewingjm previously approved these changes Jun 24, 2021
README.md Outdated Show resolved Hide resolved
README.md Show resolved Hide resolved
@@ -18,6 +19,9 @@ public class TestConfiguration

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

private readonly object userEnumeratorsLock = new object();
private readonly ThreadLocal<UserConfiguration> currentUser = new ThreadLocal<UserConfiguration>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency with what we've got in the PowerAppsStepDefiner class I would've resolved the SonarCloud comment by adding the static keyword that was missing rather than using a ThreadLocal<> instance member.

@ewingjm ewingjm merged commit 26ed97f into master Jun 24, 2021
@ewingjm ewingjm deleted the NGW/cycle-through-multiple-users-for-an-alias branch June 24, 2021 12:15
@sonarcloud
Copy link

sonarcloud bot commented Jun 24, 2021

Kudos, SonarCloud Quality Gate passed!

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

100.0% 100.0% Coverage
0.0% 0.0% Duplication

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Load balance tests across multiple users with the same alias
2 participants