public async Task Check_Latest_Published_Apk_File_OK() { BuildTestData(); var date = DateTime.UtcNow.AddMinutes(-20); var modifiedArtifact2_1 = new ProductArtifact { ProductId = product1.Id, ProductBuildId = productBuild2.Id, ArtifactType = "apk", Url = "https://sil-prd-aps-artifacts.s3.amazonaws.com/prd/jobs/build_scriptureappbuilder_1/2880/test-4.7.apk", ContentType = "application/octet-stream", LastModified = date }; var webRequestWrapper = _fixture.GetService <WebRequestWrapper>(); var webRequestWrapperMock = Mock.Get(webRequestWrapper); webRequestWrapperMock.Reset(); webRequestWrapperMock.Setup(x => x.GetFileInfo(It.Is <ProductArtifact>(a => a.ArtifactType == "apk"))) .Returns(modifiedArtifact2_1); var url = $"/api/products/{product1.Id}/files/published/apk"; var response = await Head(url, DateTime.UtcNow.ToUniversalTime().ToString("r")); Assert.Equal(HttpStatusCode.OK, response.StatusCode); }
protected async Task <DateTime?> AddProductArtifactAsync(string key, string value, Guid productId, ProductBuild productBuild) { var productArtifact = new ProductArtifact { ProductId = productId, ProductBuildId = productBuild.Id, ArtifactType = key, Url = value }; var updatedArtifact = WebRequestWrapper.GetFileInfo(productArtifact); await ProductArtifactRepository.CreateAsync(updatedArtifact); #pragma warning disable RECS0061 // Warns when a culture-aware 'EndsWith' call is used by default. if (key == "version" && updatedArtifact.ContentType == "application/json") #pragma warning restore RECS0061 // Warns when a culture-aware 'EndsWith' call is used by default. { var contents = WebClient.DownloadString(value); var version = JsonConvert.DeserializeObject <Dictionary <string, string> >(contents); if (version.ContainsKey("version")) { productBuild.Version = version["version"]; await ProductBuildRepository.UpdateAsync(productBuild); } } return(updatedArtifact.LastModified); }
public async Task Get_Build_Get_ConsoleText() { BuildTestData(); var buildBuildService = _fixture.GetService <BuildEngineBuildService>(); var mockBuildEngine = Mock.Get(buildBuildService.BuildEngineApi); var mockWebRequestWrapper = Mock.Get(buildBuildService.WebRequestWrapper); var mockWebClient = Mock.Get(buildBuildService.WebClient); mockBuildEngine.Reset(); mockWebRequestWrapper.Reset(); mockWebClient.Reset(); var productBuild = AddEntity <AppDbContext, ProductBuild>(new ProductBuild { ProductId = product2.Id, BuildId = product2.WorkflowBuildId }); var buildResponse = new BuildResponse { Id = 2, JobId = 1, Status = "completed", Result = "FAILURE", Error = "Error", Artifacts = new Dictionary <string, string>() { { "consoleText", "https://sil-stg-aps-artifacts.s3.amazonaws.com/stg/jobs/build_scriptureappbuilder_1/2/English_Greek-4.7-output.log" } } }; var modifiedArtifact1 = new ProductArtifact { ProductId = product2.Id, ArtifactType = "consoleText", Url = "https://sil-stg-aps-artifacts.s3.amazonaws.com/stg/jobs/build_scriptureappbuilder_1/2/English_Greek-4.7-output.log", ContentType = "text/plain", FileSize = 1831, LastModified = DateTime.UtcNow }; mockBuildEngine.Setup(x => x.GetBuild(It.IsAny <int>(), It.IsAny <int>())).Returns(buildResponse); mockWebRequestWrapper.Setup(x => x.GetFileInfo(It.Is <ProductArtifact>(a => a.ArtifactType == "consoleText"))) .Returns(modifiedArtifact1); var consoleText = await buildBuildService.GetConsoleText(product2.Id); Assert.Equal("https://sil-stg-aps-artifacts.s3.amazonaws.com/stg/jobs/build_scriptureappbuilder_1/2/English_Greek-4.7-output.log", consoleText); }
public virtual ProductArtifact GetFileInfo(ProductArtifact artifact) { var modifiedArtifact = artifact; try { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(artifact.Url); request.Method = "HEAD"; using (HttpWebResponse resp = (HttpWebResponse)(request.GetResponse())) { modifiedArtifact.ContentType = resp.ContentType; modifiedArtifact.LastModified = resp.LastModified.ToUniversalTime(); if (resp.ContentType != "text/html") { modifiedArtifact.FileSize = resp.ContentLength; } } } catch (Exception) { } return(modifiedArtifact); }
public async Task Build_Check_BuildAsync() { BuildTestData(); var buildBuildService = _fixture.GetService <BuildEngineBuildService>(); var mockBuildEngine = Mock.Get(buildBuildService.BuildEngineApi); var mockWebRequestWrapper = Mock.Get(buildBuildService.WebRequestWrapper); var mockWebClient = Mock.Get(buildBuildService.WebClient); mockBuildEngine.Reset(); mockWebRequestWrapper.Reset(); mockWebClient.Reset(); var modifiedArtifact1 = new ProductArtifact { ProductId = product1.Id, ArtifactType = "apk", Url = "https://sil-stg-aps-artifacts.s3.amazonaws.com/stg/jobs/build_scriptureappbuilder_1/2/English_Greek-4.7.apk", ContentType = "application/octet-stream", FileSize = 8684905, LastModified = DateTime.UtcNow }; var modifiedArtifact2 = new ProductArtifact { ProductId = product1.Id, ArtifactType = "about", Url = "https://sil-stg-aps-artifacts.s3.amazonaws.com/stg/jobs/build_scriptureappbuilder_1/2/about.txt", ContentType = "text/plain", FileSize = 1831, LastModified = DateTime.UtcNow }; var modifiedArtifact3 = new ProductArtifact { ProductId = product1.Id, ArtifactType = "version", Url = "https://sil-stg-aps-artifacts.s3.amazonaws.com/stg/jobs/build_scriptureappbuilder_1/2/version.json", ContentType = "application/json", FileSize = 1831, LastModified = DateTime.UtcNow }; var artifacts = new Dictionary <string, string>() { { "apk", "https://sil-stg-aps-artifacts.s3.amazonaws.com/stg/jobs/build_scriptureappbuilder_1/2/English_Greek-4.7.apk" }, { "about", "https://sil-stg-aps-artifacts.s3.amazonaws.com/stg/jobs/build_scriptureappbuilder_1/2/about.txt" }, { "version", "https://sil-stg-aps-artifacts.s3.amazonaws.com/stg/jobs/build_scriptureappbuilder_1/2/version.json" } }; product2.WorkflowBuildId = 42; var productBuild = AddEntity <AppDbContext, ProductBuild>(new ProductBuild { ProductId = product2.Id, BuildId = 42, }); var buildResponse = new BuildResponse { Id = 2, JobId = 1, Status = "completed", Result = "SUCCESS", Error = "", Artifacts = artifacts }; mockBuildEngine.Setup(x => x.GetBuild(It.Is <int>(i => i == product2.WorkflowJobId), It.Is <int>(b => b == product2.WorkflowBuildId))) .Returns(buildResponse); mockWebRequestWrapper.Setup(x => x.GetFileInfo(It.Is <ProductArtifact>(a => a.ArtifactType == "apk"))) .Returns(modifiedArtifact1); mockWebRequestWrapper.Setup(x => x.GetFileInfo(It.Is <ProductArtifact>(a => a.ArtifactType == "about"))) .Returns(modifiedArtifact2); mockWebRequestWrapper.Setup(x => x.GetFileInfo(It.Is <ProductArtifact>(a => a.ArtifactType == "version"))) .Returns(modifiedArtifact3); mockWebClient.Setup(x => x.DownloadString(It.Is <string>(addr => addr == modifiedArtifact3.Url))) .Returns("{ \"version\" : \"4.7.6\", \"versionName\" : \"4.7\", \"versionCode\" : \"6\" } "); await buildBuildService.CheckBuildAsync(product2.Id); mockBuildEngine.Verify(x => x.SetEndpoint( It.Is <String>(u => u == org1.BuildEngineUrl), It.Is <String>(t => t == org1.BuildEngineApiAccessToken) )); var modifiedArtifacts = ReadTestData <AppDbContext, ProductArtifact>(); Assert.Equal(3, modifiedArtifacts.Count); var modifiedApk = modifiedArtifacts.First(a => a.ArtifactType == modifiedArtifact1.ArtifactType); Assert.Equal(modifiedArtifact1.Url, modifiedApk.Url); Assert.Equal(modifiedArtifact1.ContentType, modifiedApk.ContentType); Assert.Equal(modifiedArtifact1.FileSize, modifiedApk.FileSize); var modifiedProductBuilds = ReadTestData <AppDbContext, ProductBuild>(); Assert.Equal(1, modifiedProductBuilds.Count); var build = modifiedProductBuilds.First(); Assert.Equal("4.7.6", build.Version); }
protected async Task <DateTime?> AddProductArtifactAsync(string key, string value, Product product, ProductBuild productBuild, bool successful) { var productArtifact = new ProductArtifact { ProductId = product.Id, ProductBuildId = productBuild.Id, ArtifactType = key, Url = value }; var updatedArtifact = WebRequestWrapper.GetFileInfo(productArtifact); var existingArtifact = await ProductArtifactRepository .Get().Where(a => a.ProductId == product.Id && a.ProductBuildId == productBuild.Id && a.ArtifactType == key && a.Url == value) .FirstOrDefaultAsync(); if (existingArtifact != null) { // Not sure why we are getting multiple of these, but we don't want multiple entries. // Should we ignore it or update? Ignore for now. Updating threw exceptions Log.Information($"Updating Artifact: Id={existingArtifact.Id}"); updatedArtifact.Id = existingArtifact.Id; // await ProductArtifactRepository.UpdateAsync(updatedArtifact); } else { var newArtifact = await ProductArtifactRepository.CreateAsync(updatedArtifact); Log.Information($"Created Artifact: Id={newArtifact.Id}"); } // On version.json, update the ProductBuild.Version if (key == "version" && updatedArtifact.ContentType == "application/json") { try { var contents = WebClient.DownloadString(value); var version = JsonConvert.DeserializeObject <Dictionary <string, object> >(contents); if (version.ContainsKey("version")) { productBuild.Version = version["version"] as String; await ProductBuildRepository.UpdateAsync(productBuild); if (successful) { product.VersionBuilt = version["version"] as String; await ProductRepository.UpdateAsync(product); } } } catch (Exception ex) { Log.Error(ex, $"Parsing {key}: {value}"); } } // On play-listing-manifest.json, update the Project.DefaultLanguage if (key == "play-listing-manifest" && updatedArtifact.ContentType == "application/json") { try { var contents = WebClient.DownloadString(value); var manifest = JsonConvert.DeserializeObject <Dictionary <string, object> >(contents); if (manifest.ContainsKey("default-language")) { var languageName = manifest["default-language"] as String; StoreLanguage storeLanguage = await LanguageRepository.Get().Where(lang => lang.Name == languageName).FirstOrDefaultAsync(); if (storeLanguage != null) { product.StoreLanguageId = storeLanguage.Id; await ProductRepository.UpdateAsync(product); } } } catch (Exception ex) { Log.Error(ex, $"Parsing {key}: {value}"); } } return(updatedArtifact.LastModified); }
public async Task Get_Build_Check_Failure_Default_Build_Engine() { BuildTestData(); var buildBuildService = _fixture.GetService <BuildEngineBuildService>(); var mockBuildEngine = Mock.Get(buildBuildService.BuildEngineApi); var mockWebRequestWrapper = Mock.Get(buildBuildService.WebRequestWrapper); var mockWebClient = Mock.Get(buildBuildService.WebClient); mockBuildEngine.Reset(); mockWebRequestWrapper.Reset(); mockWebClient.Reset(); var productBuild = AddEntity <AppDbContext, ProductBuild>(new ProductBuild { ProductId = product3.Id, BuildId = product3.WorkflowBuildId }); var buildResponse = new BuildResponse { Id = 2, JobId = 1, Status = "completed", Result = "FAILURE", Error = "Error", Artifacts = new Dictionary <string, string>() { { "consoleText", "https://sil-stg-aps-artifacts.s3.amazonaws.com/stg/jobs/build_scriptureappbuilder_1/2/English_Greek-4.7-output.log" } } }; var modifiedArtifact1 = new ProductArtifact { ProductId = product3.Id, ArtifactType = "consoleText", Url = "https://sil-stg-aps-artifacts.s3.amazonaws.com/stg/jobs/build_scriptureappbuilder_1/2/English_Greek-4.7-output.log", ContentType = "text/plain", FileSize = 1831, LastModified = DateTime.UtcNow }; mockBuildEngine.Setup(x => x.GetBuild(It.IsAny <int>(), It.IsAny <int>())).Returns(buildResponse); mockWebRequestWrapper.Setup(x => x.GetFileInfo(It.Is <ProductArtifact>(a => a.ArtifactType == "consoleText"))) .Returns(modifiedArtifact1); await buildBuildService.CheckBuildAsync(product3.Id); var builds = ReadTestData <AppDbContext, ProductBuild>(); Assert.Single(builds); var modifiedProductBuild = builds.FirstOrDefault(); Assert.False(modifiedProductBuild.Success); // Verify that notifications are sent to the user and the org admin var notifications = ReadTestData <AppDbContext, Notification>(); Assert.Equal(2, notifications.Count); Assert.Equal($"{{\"projectName\":\"Test Project2\",\"productName\":\"TestProd1\",\"buildStatus\":\"completed\",\"buildError\":\"Error\",\"buildEngineUrl\":\"https://buildengine.testorg2/build-admin/view?id=2\",\"consoleText\":\"https://sil-stg-aps-artifacts.s3.amazonaws.com/stg/jobs/build_scriptureappbuilder_1/2/English_Greek-4.7-output.log\",\"projectId\":{product3.ProjectId},\"jobId\":2,\"buildId\":2,\"projectUrl\":\"https://dev.scriptoria.io/projects/2\"}}", notifications[0].MessageSubstitutionsJson); Assert.Equal("buildFailedAdmin", notifications[0].MessageId); Assert.Equal("https://sil-stg-aps-artifacts.s3.amazonaws.com/stg/jobs/build_scriptureappbuilder_1/2/English_Greek-4.7-output.log", notifications[0].LinkUrl); }
public async Task Build_Check_BuildAsync() { BuildTestData(); var buildBuildService = _fixture.GetService <BuildEngineBuildService>(); var mockBuildEngine = Mock.Get(buildBuildService.BuildEngineApi); var mockWebRequestWrapper = Mock.Get(buildBuildService.WebRequestWrapper); var mockWebClient = Mock.Get(buildBuildService.WebClient); mockBuildEngine.Reset(); mockWebRequestWrapper.Reset(); mockWebClient.Reset(); var modifiedArtifact1 = new ProductArtifact { ProductId = product1.Id, ArtifactType = "apk", Url = "https://sil-stg-aps-artifacts.s3.amazonaws.com/stg/jobs/build_scriptureappbuilder_1/2/English_Greek-4.7.apk", ContentType = "application/octet-stream", FileSize = 8684905, LastModified = DateTime.UtcNow }; var modifiedArtifact2 = new ProductArtifact { ProductId = product1.Id, ArtifactType = "about", Url = "https://sil-stg-aps-artifacts.s3.amazonaws.com/stg/jobs/build_scriptureappbuilder_1/2/about.txt", ContentType = "text/plain", FileSize = 1831, LastModified = DateTime.UtcNow }; var modifiedArtifact3 = new ProductArtifact { ProductId = product1.Id, ArtifactType = "version", Url = "https://sil-stg-aps-artifacts.s3.amazonaws.com/stg/jobs/build_scriptureappbuilder_1/2/version.json", ContentType = "application/json", FileSize = 1831, LastModified = DateTime.UtcNow }; var modifiedArtifact4 = new ProductArtifact { ProductId = product1.Id, ArtifactType = "play-listing-manifest", Url = "https://sil-stg-aps-artifacts.s3.amazonaws.com/stg/jobs/build_scriptureappbuilder_1/2/play-listing/manifest.json", ContentType = "application/json", FileSize = 1831, LastModified = DateTime.UtcNow }; var storetype = AddEntity <AppDbContext, StoreType>(new StoreType { Id = 1, Name = "google_play_store", Description = "Google Play Store" }); var language = AddEntity <AppDbContext, StoreLanguage>(new StoreLanguage { Id = 1, Name = "en-US", Description = "English (United States) – en-US", StoreTypeId = 1 }); var artifacts = new Dictionary <string, string>() { { "apk", "https://sil-stg-aps-artifacts.s3.amazonaws.com/stg/jobs/build_scriptureappbuilder_1/2/English_Greek-4.7.apk" }, { "about", "https://sil-stg-aps-artifacts.s3.amazonaws.com/stg/jobs/build_scriptureappbuilder_1/2/about.txt" }, { "version", "https://sil-stg-aps-artifacts.s3.amazonaws.com/stg/jobs/build_scriptureappbuilder_1/2/version.json" }, { "play-listing-manifest", "https://sil-stg-aps-artifacts.s3.amazonaws.com/stg/jobs/build_scriptureappbuilder_1/2/play-listing/manifest.json" } }; product2.WorkflowBuildId = 42; var productBuild = AddEntity <AppDbContext, ProductBuild>(new ProductBuild { ProductId = product2.Id, BuildId = 42, }); var buildResponse = new BuildResponse { Id = 2, JobId = 1, Status = "completed", Result = "SUCCESS", Error = "", Artifacts = artifacts }; mockBuildEngine.Setup(x => x.GetBuild(It.Is <int>(i => i == product2.WorkflowJobId), It.Is <int>(b => b == product2.WorkflowBuildId))) .Returns(buildResponse); mockWebRequestWrapper.Setup(x => x.GetFileInfo(It.Is <ProductArtifact>(a => a.ArtifactType == "apk"))) .Returns(modifiedArtifact1); mockWebRequestWrapper.Setup(x => x.GetFileInfo(It.Is <ProductArtifact>(a => a.ArtifactType == "about"))) .Returns(modifiedArtifact2); mockWebRequestWrapper.Setup(x => x.GetFileInfo(It.Is <ProductArtifact>(a => a.ArtifactType == "version"))) .Returns(modifiedArtifact3); mockWebRequestWrapper.Setup(x => x.GetFileInfo(It.Is <ProductArtifact>(a => a.ArtifactType == "play-listing-manifest"))) .Returns(modifiedArtifact4); mockWebClient.Setup(x => x.DownloadString(It.Is <string>(addr => addr == modifiedArtifact3.Url))) .Returns("{ \"version\" : \"4.7.6\", \"versionName\" : \"4.7\", \"versionCode\" : \"6\" } "); mockWebClient.Setup(x => x.DownloadString(It.Is <string>(addr => addr == modifiedArtifact4.Url))) .Returns("{ \"default-language\" : \"en-US\" }"); await buildBuildService.CheckBuildAsync(product2.Id); mockBuildEngine.Verify(x => x.SetEndpoint( It.Is <String>(u => u == org1.BuildEngineUrl), It.Is <String>(t => t == org1.BuildEngineApiAccessToken) )); var modifiedArtifacts = ReadTestData <AppDbContext, ProductArtifact>(); Assert.Equal(4, modifiedArtifacts.Count); var modifiedApk = modifiedArtifacts.First(a => a.ArtifactType == modifiedArtifact1.ArtifactType); Assert.Equal(modifiedArtifact1.Url, modifiedApk.Url); Assert.Equal(modifiedArtifact1.ContentType, modifiedApk.ContentType); Assert.Equal(modifiedArtifact1.FileSize, modifiedApk.FileSize); var modifiedProductBuilds = ReadTestData <AppDbContext, ProductBuild>(); Assert.Single(modifiedProductBuilds); var build = modifiedProductBuilds.First(); Assert.Equal("4.7.6", build.Version); Assert.True(build.Success); var modifiedProduct = ReadTestData <AppDbContext, Product>().Where(p => p.Id == product2.Id); Assert.Single(modifiedProduct); var product = modifiedProduct.First(); Assert.Equal("en-US", product.StoreLanguage.Name); Assert.Equal("4.7.6", product.VersionBuilt); // One notification should be sent to owner on successful build var notifications = ReadTestData <AppDbContext, Notification>(); Assert.Single(notifications); Assert.Equal("{\"projectName\":\"Test Project1\",\"productName\":\"TestProd1\"}", notifications[0].MessageSubstitutionsJson); Assert.Equal("buildCompletedSuccessfully", notifications[0].MessageId); }
public async Task Get_Build_Check_Failure_Missing_ConsoleLog_Default_Build_Engine() { BuildTestData(); var buildBuildService = _fixture.GetService <BuildEngineBuildService>(); var mockBuildEngine = Mock.Get(buildBuildService.BuildEngineApi); var mockWebRequestWrapper = Mock.Get(buildBuildService.WebRequestWrapper); var mockWebClient = Mock.Get(buildBuildService.WebClient); mockBuildEngine.Reset(); mockWebRequestWrapper.Reset(); mockWebClient.Reset(); var productBuild = AddEntity <AppDbContext, ProductBuild>(new ProductBuild { ProductId = product3.Id, BuildId = product3.WorkflowBuildId }); var buildResponse = new BuildResponse { Id = 2, JobId = 1, Status = "completed", Result = "FAILURE", Error = "Error", Artifacts = new Dictionary <string, string>() { { "cloudWatch", "https://console.aws.amazon.com/cloudwatch/home?region=us-east-1#logEvent:group=/aws/codebuild/build_app-cth;stream=25de05b1-3a4c-4b5f-a423-e706348d9622" } } }; var modifiedArtifact1 = new ProductArtifact { ProductId = product3.Id, ArtifactType = "cloudWatch", Url = "https://console.aws.amazon.com/cloudwatch/home?region=us-east-1#logEvent:group=/aws/codebuild/build_app-cth;stream=25de05b1-3a4c-4b5f-a423-e706348d9622", LastModified = DateTime.UtcNow }; mockBuildEngine.Setup(x => x.GetBuild(It.IsAny <int>(), It.IsAny <int>())).Returns(buildResponse); mockWebRequestWrapper.Setup(x => x.GetFileInfo(It.Is <ProductArtifact>(a => a.ArtifactType == "cloudWatch"))) .Returns(modifiedArtifact1); await buildBuildService.CheckBuildAsync(product3.Id); var builds = ReadTestData <AppDbContext, ProductBuild>(); Assert.Single(builds); var modifiedProductBuild = builds.FirstOrDefault(); Assert.False(modifiedProductBuild.Success); // Verify that notifications are sent to the user and the org admin var notifications = ReadTestData <AppDbContext, Notification>(); Assert.Equal(2, notifications.Count); Assert.Equal($"{{\"projectName\":\"Test Project2\",\"productName\":\"TestProd1\",\"buildStatus\":\"completed\",\"buildError\":\"Error\",\"buildEngineUrl\":\"https://buildengine.testorg2/build-admin/view?id=2\",\"consoleText\":null,\"projectId\":{product3.ProjectId},\"jobId\":2,\"buildId\":2,\"projectUrl\":\"https://dev.scriptoria.io/projects/2\"}}", notifications[0].MessageSubstitutionsJson); Assert.Equal("buildFailedAdmin", notifications[0].MessageId); Assert.Null(notifications[0].LinkUrl); }