/// <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++; } } }
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; }
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(); }
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(); }
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(); }