private void PrepareTestData(IServiceProvider serviceProvider)
        {
            var dbContext     = serviceProvider.GetService <WCADbContext>();
            var testUser      = dbContext.GetTestUser();
            var actionstepOrg = new ActionstepOrg
            {
                Key            = "testOrg",
                Title          = "testOrg",
                CreatedBy      = testUser,
                DateCreatedUtc = DateTime.UtcNow
            };

            dbContext.ActionstepOrgs.Add(actionstepOrg);
            dbContext.SaveChanges();

            var startTime = DateTime.UtcNow;

            var actionstepCredential = new ActionstepCredential
            {
                AccessToken          = "testToken",
                AccessTokenExpiryUtc = startTime.AddMinutes(20),
                ActionstepOrg        = actionstepOrg,
                ApiEndpoint          = new Uri("http://test-endpoint/api"),
                CreatedBy            = testUser,
                DateCreatedUtc       = startTime,
                ExpiresIn            = 60 * 20,
                ReceivedAtUtc        = startTime,
                Owner                 = testUser,
                RefreshToken          = "testRefreshToken",
                RefreshTokenExpiryUtc = startTime.AddDays(20),
                TokenType             = "bearer"
            };

            dbContext.ActionstepCredentials.Add(actionstepCredential);
            dbContext.SaveChanges();
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="tokenSet"></param>
        /// <returns></returns>
        /// <exception cref="KeyNotFoundException">Thrown if a tokenSet could not be found with the specified ID.</exception>
        public async Task <TokenSet> AddOrUpdateTokenSet(TokenSet tokenSet)
        {
            // Use a separate scope for each method call to prevent DBContext caching
            using var scope     = _serviceScopeFactory.CreateScope();
            using var dbContext = scope.ServiceProvider.GetService <WCADbContext>();

            if (tokenSet is null)
            {
                throw new ArgumentNullException(nameof(tokenSet));
            }

            _telemetry.TrackEvent(nameof(AddOrUpdateTokenSet), new Dictionary <string, string>()
            {
                { "TokenSetId", tokenSet.Id },
                { "RefreshLockInfo ExpiresAt", tokenSet.RefreshLockInfo?.LockExpiresAt.ToString() },
                { "RefreshLockInfo LockId", tokenSet.RefreshLockInfo?.LockId.ToString() },
            });

            ActionstepCredential actionstepCredential = null;

            var tokenSetUser = await dbContext.Users.FindAsync(tokenSet.UserId);

            if (tokenSetUser is null)
            {
                throw new UserNotFoundException("Couldn't find user attempting to add or update TokenSet.", tokenSet.UserId);
            }

            if (!string.IsNullOrEmpty(tokenSet.Id))
            {
                var tokenSetId = int.Parse(tokenSet.Id, CultureInfo.InvariantCulture);
                actionstepCredential = await dbContext.ActionstepCredentials
                                       .Include(c => c.Owner)
                                       .Include(c => c.ActionstepOrg)
                                       .SingleOrDefaultAsync(c => c.Id == tokenSetId);
            }

            // If not found by id, attempt to find by user and org
            if (actionstepCredential is null)
            {
                actionstepCredential = await dbContext.ActionstepCredentials
                                       .Include(c => c.Owner)
                                       .Include(c => c.ActionstepOrg)
                                       .ForOwnerAndOrg(tokenSetUser, tokenSet.OrgKey)
                                       .SingleOrDefaultAsync();
            }

            var now = _clock.GetCurrentInstant().ToDateTimeUtc();

            // If still null, then we need to create it
            if (actionstepCredential is null)
            {
                actionstepCredential                = new ActionstepCredential();
                actionstepCredential.Owner          = tokenSetUser;
                actionstepCredential.CreatedBy      = tokenSetUser;
                actionstepCredential.DateCreatedUtc = now;
                dbContext.ActionstepCredentials.Add(actionstepCredential);
            }

            if (actionstepCredential.ActionstepOrg == null || actionstepCredential.ActionstepOrg.Key == null)
            {
                var orgToAssociate = dbContext.ActionstepOrgs.Where(o => o.Key == tokenSet.OrgKey).SingleOrDefault();

                if (orgToAssociate == null)
                {
                    var newOrg = new ActionstepOrg()
                    {
                        Key            = tokenSet.OrgKey,
                        Title          = tokenSet.OrgKey,
                        CreatedBy      = actionstepCredential.Owner,
                        DateCreatedUtc = now,
                        UpdatedBy      = actionstepCredential.Owner,
                        LastUpdatedUtc = now,
                    };

                    EntityEntry <ActionstepOrg> addedOrgEntity = dbContext.ActionstepOrgs.Add(newOrg);
                    orgToAssociate = addedOrgEntity.Entity;
                }

                actionstepCredential.ActionstepOrg = orgToAssociate;
            }
            else
            {
                if (!actionstepCredential.ActionstepOrg.Key.Equals(tokenSet.OrgKey, StringComparison.InvariantCulture))
                {
                    throw new TokenSetOrgKeyMismatchException(
                              "An attempt was made to update a TokenSet, however the Actionstep org key supplied in the TokenSet doesn't match the saved org key stored.",
                              actionstepCredential.ActionstepOrg.Key,
                              tokenSet);
                }
            }

            /// Copies simple field mappings, except things like org because it's a complex relationship in <see cref="ActionstepCredential"/>.
            actionstepCredential.UpdateFromTokenSet(tokenSet);

            actionstepCredential.UpdatedBy        = tokenSetUser;
            actionstepCredential.LastUpdatedUtc   = now;
            actionstepCredential.ConcurrencyStamp = Guid.NewGuid();

            try
            {
                await dbContext.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException dbConcurrencyException)
            {
                throw new TokenSetConcurrencyException(tokenSet, dbConcurrencyException);
            }

            return(actionstepCredential.ToTokenSet());
        }