/// <summary>
        /// Migrate with inifinte retry.
        /// </summary>
        /// <param name="dbContext"></param>
        private void Migrate(ManageCoursesDbContext dbContext)
        {
            // If the migration fails and throws then the app ends up in a broken state so don't let that happen.
            // If the migrations failed and the exception was swallowed then the code could make assumptions that result in corrupt data so don't let execution continue till this has worked.
            int migrationAttempt = 1;

            while (true)
            {
                try
                {
                    _logger.LogInformation($"Running Database.EnsureCreated. Attempt {migrationAttempt} of ∞");
                    dbContext.Database.EnsureCreated();
                    _logger.LogInformation($"Running Database.EnsureCreated succeeded. Attempt {migrationAttempt} of ∞");
                    break; // success!
                }
                catch (Exception ex)
                {
                    const int maxDelayMs = 60 * 1000;
                    int       delayMs    = 1000 * migrationAttempt;
                    if (delayMs > maxDelayMs)
                    {
                        delayMs = maxDelayMs;
                    }
                    // exception included in message string because app insights isn't showing the messages and kudo log stream only shows the message string.
                    _logger.LogError($"Failed to apply EF migrations. Attempt {migrationAttempt} of ∞. Waiting for {delayMs}ms before trying again.\n{ex}", ex);
                    new TelemetryClient().TrackException(ex);
                    Thread.Sleep(delayMs);
                    migrationAttempt++;
                }
            }
        }
Exemplo n.º 2
0
 public UcasDataMigrator(ManageCoursesDbContext manageCoursesDbContext, ILogger logger, UcasPayload payload,
                         IClock clock = null, RecruitmentCycle recruitmentCycle = null)
 {
     _context          = manageCoursesDbContext;
     _logger           = logger;
     _clock            = clock ?? new Clock();
     this.payload      = payload;
     _recruitmentCycle = recruitmentCycle;
 }
Exemplo n.º 3
0
 public virtual void BaseOneTimeSetUp()
 {
     Config     = TestConfigBuilder.BuildTestConfig();
     Context    = ContextLoader.GetDbContext(Config, EnableRetryOnFailure);
     TestConfig = new TestConfigReader(Config);
     Context.Database.EnsureDeleted();
     Context.Database.EnsureCreated();
     MockClock = new Mock <IClock>();
     MockClock.SetupGet(c => c.UtcNow).Returns(() => MockTime);
     OneTimeSetup();
 }
Exemplo n.º 4
0
        public static void AddTestReferenceData(this ManageCoursesDbContext context, string username, RecruitmentCycle recruitmentCycle)
        {
            User user = new User
            {
                FirstName          = "Joe",
                LastName           = "Bloggs",
                Email              = username,
                AcceptTermsDateUtc = DateTime.UtcNow
            };

            context.Users.Add(user);

            Organisation organisation = new Organisation
            {
                Name  = "Joe's school",
                OrgId = "123"
            };

            context.Organisations.Add(organisation);

            Provider provider = new Provider
            {
                ProviderName     = "Joe's school @ UCAS",
                ProviderCode     = "ABC",
                RecruitmentCycle = recruitmentCycle,
            };

            context.Providers.Add(provider);

            context.OrganisationUsers.Add(new OrganisationUser {
                User         = user,
                Organisation = organisation
            });

            context.OrganisationProviders.Add(new OrganisationProvider {
                Provider     = provider,
                Organisation = organisation
            });
        }
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ManageCoursesDbContext dbContext)
        {
            Migrate(dbContext);

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.SetSecurityHeaders();
            }

            // Enable the Swagger UI middleware and the Swagger generator
            app.UseSwaggerUi3(typeof(Startup).GetTypeInfo().Assembly, settings =>
            {
                settings.GeneratorSettings.DefaultPropertyNameHandling =
                    PropertyNameHandling.CamelCase;

                settings.PostProcess = document =>
                {
                    document.Info.Version     = "v1";
                    document.Info.Title       = "Manage courses API";
                    document.Info.Description = "An API for managing course data";
                };
                settings.GeneratorSettings.DocumentProcessors.Add(new SecurityDefinitionAppender(BearerTokenDefaults.AuthenticationScheme, new SwaggerSecurityScheme
                {
                    Type        = SwaggerSecuritySchemeType.ApiKey,
                    Description = "In order to interactive with the api please input `Bearer {code}`",
                    In          = SwaggerSecurityApiKeyLocation.Header,
                    Name        = "Authorization"
                }));

                settings.GeneratorSettings.OperationProcessors.Add(new OperationSecurityScopeProcessor(BearerTokenDefaults.AuthenticationScheme));
            });

            app.UseAuthentication();
            app.UseMvc();
        }
Exemplo n.º 6
0
        public void BaseSetup()
        {
            // get a fresh context every time to avoid stale in-memory data contaminating subsequent tests
            Context = ContextLoader.GetDbContext(Config, EnableRetryOnFailure);
            // Truncate (delete all data from) all tables, following FK constraints by virtue of CASCADE
            // https://stackoverflow.com/questions/2829158/truncating-all-tables-in-a-postgres-database/12082038#12082038
            Context.Database.ExecuteSqlCommandAsync(@"
                DO
                $func$
                BEGIN
                   EXECUTE
                   (SELECT 'TRUNCATE TABLE ' || string_agg(oid::regclass::text, ', ') || ' CASCADE'
                    FROM   pg_class
                    WHERE  relkind = 'r'  -- only tables
                    AND    relnamespace = 'public'::regnamespace
                   );
                END
                $func$;").Wait();

            // reset clock
            MockTime = new DateTime(1977, 1, 2, 3, 4, 5, 7);

            Context.RecruitmentCycles.AddRange(
                new List <RecruitmentCycle>
            {
                new RecruitmentCycle {
                    Year = RecruitmentCycle.CurrentYear
                },
                new RecruitmentCycle {
                    Year = "2020"
                },
            });
            Context.SaveChanges();

            // allow derived tests to do their own setup
            Setup();
        }
        private static void SaveReferenceDataPayload(ManageCoursesDbContext context)
        {
            var users = new List <User>
            {
                new User
                {
                    FirstName = "FirstName_1",
                    LastName  = "LastName_1",
                    Email     = TestUserEmail1
                },
                new User
                {
                    FirstName = "FirstName_2",
                    LastName  = "LastName_2",
                    Email     = TestUserEmail2
                },
                new User
                {
                    FirstName = "FirstName_3",
                    LastName  = "LastName_3",
                    Email     = TestUserEmail3
                }
            };
            const string orgId2        = "OrgId_2";
            var          organisations = new List <Organisation> {
                new Organisation {
                    OrgId = OrgId1
                },
                new Organisation {
                    OrgId = orgId2
                }
            };

            var providers = new List <Provider>
            {
                new ProviderBuilder().WithCode(InstCode1),
                new ProviderBuilder().WithCode(InstCode2),
            };

            var organisationProviders = new List <OrganisationProvider>
            {
                new OrganisationProvider {
                    Provider     = providers[1],
                    Organisation = organisations[1],
                }
            };
            var organisationUsers = new List <OrganisationUser>
            {
                new OrganisationUser {
                    User = users[1],
                },
                new OrganisationUser {
                    User         = users[2],
                    Organisation = organisations[0]
                }
            };

            context.Users.AddRange(users);
            context.Organisations.AddRange(organisations);
            context.Providers.AddRange(providers);
            context.OrganisationUsers.AddRange(organisationUsers);
            context.OrganisationProviders.AddRange(organisationProviders);
            context.Save();
        }