PageRenderTime 70ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 1ms

/Kudu.FunctionalTests/GitRepositoryManagementTests.cs

https://github.com/moacap/kudu
C# | 1058 lines | 811 code | 153 blank | 94 comment | 1 complexity | fe436797ee466d88cc68c5165f11c611 MD5 | raw file
Possible License(s): Apache-2.0
  1. using System;
  2. using System.IO;
  3. using System.Linq;
  4. using System.Net;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. using Kudu.Core.Deployment;
  8. using Kudu.FunctionalTests.Infrastructure;
  9. using Kudu.TestHarness;
  10. using Xunit;
  11. namespace Kudu.FunctionalTests
  12. {
  13. public class GitRepositoryManagementTests
  14. {
  15. [Fact]
  16. public void PushSimpleRepoShouldDeploy()
  17. {
  18. // Arrange
  19. string repositoryName = "Bakery10";
  20. string appName = KuduUtils.GetRandomWebsiteName("PushSimpleRepo");
  21. string verificationText = "Welcome to Fourth Coffee!";
  22. using (var repo = Git.CreateLocalRepository(repositoryName))
  23. {
  24. ApplicationManager.Run(appName, appManager =>
  25. {
  26. // Act
  27. appManager.GitDeploy(repo.PhysicalPath);
  28. var results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  29. // Assert
  30. Assert.Equal(1, results.Count);
  31. Assert.Equal(DeployStatus.Success, results[0].Status);
  32. KuduAssert.VerifyUrl(appManager.SiteUrl, verificationText);
  33. });
  34. }
  35. }
  36. [Fact]
  37. public void PushRepoWithMultipleProjectsShouldDeploy()
  38. {
  39. // Arrange
  40. string repositoryName = "Mvc3Application";
  41. string appName = KuduUtils.GetRandomWebsiteName("PushMultiProjects");
  42. string verificationText = "Welcome to ASP.NET MVC! - Change1";
  43. using (var repo = Git.CreateLocalRepository(repositoryName))
  44. {
  45. ApplicationManager.Run(appName, appManager =>
  46. {
  47. // Act
  48. appManager.GitDeploy(repo.PhysicalPath);
  49. var results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  50. // Assert
  51. Assert.Equal(1, results.Count);
  52. Assert.Equal(DeployStatus.Success, results[0].Status);
  53. Assert.NotNull(results[0].LastSuccessEndTime);
  54. KuduAssert.VerifyUrl(appManager.SiteUrl, verificationText);
  55. });
  56. }
  57. }
  58. [Fact]
  59. public void PushSimpleWapWithInlineCommand()
  60. {
  61. // Arrange
  62. string repositoryName = "PushSimpleWapWithInlineCommand";
  63. string appName = KuduUtils.GetRandomWebsiteName("PushSimpleWapWithInlineCommand");
  64. string cloneUrl = "https://github.com/KuduApps/CustomBuildScript.git";
  65. using (var repo = Git.Clone(repositoryName, cloneUrl))
  66. {
  67. repo.WriteFile(".deployment", @"
  68. [config]
  69. command = msbuild SimpleWebApplication/SimpleWebApplication.csproj /t:pipelinePreDeployCopyAllFilesToOneFolder /p:_PackageTempDir=""%TARGET%"";AutoParameterizationWebConfigConnectionStrings=false;Configuration=Debug;SolutionDir=""%SOURCE%""");
  70. Git.Commit(repo.PhysicalPath, "Custom build command added");
  71. ApplicationManager.Run(appName, appManager =>
  72. {
  73. // Act
  74. GitDeploymentResult deployResult = appManager.GitDeploy(repo.PhysicalPath);
  75. var results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  76. // Assert
  77. Assert.Equal(1, results.Count);
  78. Assert.Equal(DeployStatus.Success, results[0].Status);
  79. KuduAssert.VerifyUrl(appManager.SiteUrl, "DEBUG");
  80. });
  81. }
  82. }
  83. [Fact]
  84. public void PushSimpleWapWithCustomDeploymentScript()
  85. {
  86. // Arrange
  87. string repositoryName = "WapWithCustomDeploymentScript";
  88. string appName = KuduUtils.GetRandomWebsiteName("WapWithCustomDeploymentScript");
  89. string cloneUrl = "https://github.com/KuduApps/CustomBuildScript.git";
  90. using (var repo = Git.Clone(repositoryName, cloneUrl))
  91. {
  92. repo.WriteFile(".deployment", @"
  93. [config]
  94. command = deploy.cmd");
  95. Git.Commit(repo.PhysicalPath, "Custom build script added");
  96. ApplicationManager.Run(appName, appManager =>
  97. {
  98. // Act
  99. GitDeploymentResult deployResult = appManager.GitDeploy(repo.PhysicalPath);
  100. var results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  101. // Assert
  102. Assert.Equal(1, results.Count);
  103. Assert.Equal(DeployStatus.Success, results[0].Status);
  104. KuduAssert.VerifyUrl(appManager.SiteUrl, "DEBUG");
  105. });
  106. }
  107. }
  108. [Fact]
  109. public void PushSimpleWapWithFailingCustomDeploymentScript()
  110. {
  111. // Arrange
  112. string repositoryName = "WapWithFailingCustomDeploymentScript";
  113. string appName = KuduUtils.GetRandomWebsiteName("WapWithFailingCustomDeploymentScript");
  114. string cloneUrl = "https://github.com/KuduApps/CustomBuildScript.git";
  115. using (var repo = Git.Clone(repositoryName, cloneUrl))
  116. {
  117. repo.WriteFile(".deployment", @"
  118. [config]
  119. command = deploy.cmd");
  120. repo.WriteFile("deploy.cmd", "bogus");
  121. Git.Commit(repo.PhysicalPath, "Updated the deploy file.");
  122. ApplicationManager.Run(appName, appManager =>
  123. {
  124. // Act
  125. GitDeploymentResult deployResult = appManager.GitDeploy(repo.PhysicalPath);
  126. var results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  127. // Assert
  128. Assert.Equal(1, results.Count);
  129. Assert.Equal(DeployStatus.Failed, results[0].Status);
  130. KuduAssert.VerifyLogOutput(appManager, results[0].Id, "'bogus' is not recognized as an internal or external command");
  131. });
  132. }
  133. }
  134. [Fact]
  135. public void WarningsAsErrors()
  136. {
  137. // Arrange
  138. string repositoryName = "WarningsAsErrors";
  139. string appName = KuduUtils.GetRandomWebsiteName("WarningsAsErrors");
  140. string cloneUrl = "https://github.com/KuduApps/WarningsAsErrors.git";
  141. using (var repo = Git.Clone(repositoryName, cloneUrl))
  142. {
  143. ApplicationManager.Run(appName, appManager =>
  144. {
  145. // Act
  146. GitDeploymentResult deployResult = appManager.GitDeploy(repo.PhysicalPath);
  147. var results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  148. // Assert
  149. Assert.Equal(1, results.Count);
  150. Assert.Equal(DeployStatus.Failed, results[0].Status);
  151. Assert.Null(results[0].LastSuccessEndTime);
  152. KuduAssert.VerifyLogOutput(appManager, results[0].Id, "Warning as Error: The variable 'x' is declared but never used");
  153. Assert.True(deployResult.GitTrace.Contains("Warning as Error: The variable 'x' is declared but never used"));
  154. Assert.True(deployResult.GitTrace.Contains("Error - Changes committed to remote repository but your website not updated."));
  155. });
  156. }
  157. }
  158. [Fact]
  159. public void PushRepoWithProjectAndNoSolutionShouldDeploy()
  160. {
  161. // Arrange
  162. string repositoryName = "Mvc3Application_NoSolution";
  163. string appName = KuduUtils.GetRandomWebsiteName("PushRepoWithProjNoSln");
  164. string verificationText = "Kudu Deployment Testing: Mvc3Application_NoSolution";
  165. using (var repo = Git.CreateLocalRepository(repositoryName))
  166. {
  167. ApplicationManager.Run(appName, appManager =>
  168. {
  169. // Act
  170. appManager.GitDeploy(repo.PhysicalPath);
  171. var results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  172. // Assert
  173. Assert.Equal(1, results.Count);
  174. Assert.Equal(DeployStatus.Success, results[0].Status);
  175. KuduAssert.VerifyUrl(appManager.SiteUrl, verificationText);
  176. });
  177. }
  178. }
  179. [Fact]
  180. public void PushRepositoryWithNoDeployableProjectsTreatsAsWebsite()
  181. {
  182. // Arrange
  183. string repositoryName = "PushRepositoryWithNoDeployableProjectsTreatsAsWebsite";
  184. string appName = KuduUtils.GetRandomWebsiteName("PushNoDeployableProj");
  185. string cloneUrl = "https://github.com/KuduApps/NoDeployableProjects.git";
  186. using (var repo = Git.Clone(repositoryName, cloneUrl))
  187. {
  188. ApplicationManager.Run(appName, appManager =>
  189. {
  190. // Act
  191. appManager.GitDeploy(repo.PhysicalPath);
  192. var results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  193. // Assert
  194. Assert.Equal(1, results.Count);
  195. Assert.Equal(DeployStatus.Success, results[0].Status);
  196. KuduAssert.VerifyLogOutput(appManager, results[0].Id, "no deployable projects. Deploying files instead");
  197. });
  198. }
  199. }
  200. [Fact]
  201. public void WapBuildsReleaseMode()
  202. {
  203. // Arrange
  204. string repositoryName = "WapBuildsReleaseMode";
  205. string appName = KuduUtils.GetRandomWebsiteName("WapBuildsRelease");
  206. string cloneUrl = "https://github.com/KuduApps/ConditionalCompilation.git";
  207. using (var repo = Git.Clone(repositoryName, cloneUrl))
  208. {
  209. ApplicationManager.Run(appName, appManager =>
  210. {
  211. // Act
  212. appManager.GitDeploy(repo.PhysicalPath);
  213. var results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  214. // Assert
  215. Assert.Equal(1, results.Count);
  216. Assert.Equal(DeployStatus.Success, results[0].Status);
  217. KuduAssert.VerifyUrl(appManager.SiteUrl, null, "RELEASE MODE", "Context.IsDebuggingEnabled: False");
  218. });
  219. }
  220. }
  221. [Fact]
  222. public void WebsiteWithIISExpressWorks()
  223. {
  224. // Arrange
  225. string repositoryName = "WebsiteWithIISExpressWorks";
  226. string appName = KuduUtils.GetRandomWebsiteName("WebsiteWithIISExpressWorks");
  227. string cloneUrl = "https://github.com/KuduApps/waws.git";
  228. using (var repo = Git.Clone(repositoryName, cloneUrl))
  229. {
  230. ApplicationManager.Run(appName, appManager =>
  231. {
  232. // Act
  233. appManager.GitDeploy(repo.PhysicalPath);
  234. var results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  235. // Assert
  236. Assert.Equal(1, results.Count);
  237. Assert.Equal(DeployStatus.Success, results[0].Status);
  238. KuduAssert.VerifyUrl(appManager.SiteUrl, "Home");
  239. });
  240. }
  241. }
  242. [Fact]
  243. public void PushAppChangesShouldTriggerBuild()
  244. {
  245. // Arrange
  246. string repositoryName = "Mvc3Application";
  247. string appName = KuduUtils.GetRandomWebsiteName("PushAppChanges");
  248. string verificationText = "Welcome to ASP.NET MVC!";
  249. using (var repo = Git.CreateLocalRepository(repositoryName))
  250. {
  251. ApplicationManager.Run(appName, appManager =>
  252. {
  253. // Act
  254. appManager.GitDeploy(repo.PhysicalPath);
  255. Git.Revert(repo.PhysicalPath);
  256. appManager.GitDeploy(repo.PhysicalPath);
  257. var results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  258. // Assert
  259. Assert.Equal(2, results.Count);
  260. Assert.Equal(DeployStatus.Success, results[0].Status);
  261. KuduAssert.VerifyUrl(appManager.SiteUrl, verificationText);
  262. });
  263. }
  264. }
  265. [Fact]
  266. public void AppNameWithSignalRWorks()
  267. {
  268. // Arrange
  269. string repositoryName = "Mvc3Application";
  270. string appName = KuduUtils.GetRandomWebsiteName("signalroverflow");
  271. string verificationText = "Welcome to ASP.NET MVC!";
  272. using (var repo = Git.CreateLocalRepository(repositoryName))
  273. {
  274. ApplicationManager.Run(appName, appManager =>
  275. {
  276. // Act
  277. appManager.GitDeploy(repo.PhysicalPath);
  278. var results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  279. // Assert
  280. Assert.Equal(1, results.Count);
  281. Assert.Equal(DeployStatus.Success, results[0].Status);
  282. KuduAssert.VerifyUrl(appManager.SiteUrl, verificationText);
  283. });
  284. }
  285. }
  286. [Fact]
  287. public void DeletesToRepositoryArePropagatedForWaps()
  288. {
  289. string repositoryName = "Mvc3Application";
  290. string appName = KuduUtils.GetRandomWebsiteName("DeletesToRepoForWaps");
  291. using (var repo = Git.CreateLocalRepository(repositoryName))
  292. {
  293. ApplicationManager.Run(appName, appManager =>
  294. {
  295. string deletePath = Path.Combine(repo.PhysicalPath, @"Mvc3Application\Controllers\AccountController.cs");
  296. string projectPath = Path.Combine(repo.PhysicalPath, @"Mvc3Application\Mvc3Application.csproj");
  297. // Act
  298. appManager.GitDeploy(repo.PhysicalPath);
  299. var results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  300. // Assert
  301. Assert.Equal(1, results.Count);
  302. Assert.Equal(DeployStatus.Success, results[0].Status);
  303. KuduAssert.VerifyUrl(appManager.SiteUrl + "Account/LogOn", statusCode: HttpStatusCode.OK);
  304. File.Delete(deletePath);
  305. File.WriteAllText(projectPath, File.ReadAllText(projectPath).Replace(@"<Compile Include=""Controllers\AccountController.cs"" />", ""));
  306. Git.Commit(repo.PhysicalPath, "Deleted the filez");
  307. appManager.GitDeploy(repo.PhysicalPath);
  308. results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  309. // Assert
  310. Assert.Equal(2, results.Count);
  311. Assert.Equal(DeployStatus.Success, results[1].Status);
  312. KuduAssert.VerifyUrl(appManager.SiteUrl + "Account/LogOn", statusCode: HttpStatusCode.NotFound);
  313. });
  314. }
  315. }
  316. [Fact]
  317. public void PushShouldOverwriteModifiedFilesInRepo()
  318. {
  319. // Arrange
  320. string repositoryName = "Mvc3Application";
  321. string appName = KuduUtils.GetRandomWebsiteName("PushOverwriteModified");
  322. string verificationText = "Welcome to ASP.NET MVC!";
  323. using (var repo = Git.CreateLocalRepository(repositoryName))
  324. {
  325. ApplicationManager.Run(appName, appManager =>
  326. {
  327. // Act
  328. appManager.GitDeploy(repo.PhysicalPath);
  329. KuduAssert.VerifyUrl(appManager.SiteUrl, verificationText);
  330. appManager.ProjectSystem.WriteAllText("Views/Home/Index.cshtml", "Hello world!");
  331. // Sleep a little since it's a remote call
  332. Thread.Sleep(500);
  333. KuduAssert.VerifyUrl(appManager.SiteUrl, "Hello world!");
  334. // Make an unrelated change (newline to the end of web.config)
  335. repo.AppendFile(@"Mvc3Application\Web.config", "\n");
  336. Git.Commit(repo.PhysicalPath, "This is a test");
  337. appManager.GitDeploy(repo.PhysicalPath);
  338. var results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  339. // Assert
  340. Assert.Equal(2, results.Count);
  341. Assert.Equal(DeployStatus.Success, results[0].Status);
  342. KuduAssert.VerifyUrl(appManager.SiteUrl, verificationText);
  343. });
  344. }
  345. }
  346. [Fact]
  347. public void GoingBackInTimeShouldOverwriteModifiedFilesInRepo()
  348. {
  349. // Arrange
  350. string repositoryName = "Mvc3Application";
  351. string appName = KuduUtils.GetRandomWebsiteName("GoBackOverwriteModified");
  352. string verificationText = "Welcome to ASP.NET MVC!";
  353. using (var repo = Git.CreateLocalRepository(repositoryName))
  354. {
  355. string id = repo.CurrentId;
  356. ApplicationManager.Run(appName, appManager =>
  357. {
  358. // Act
  359. appManager.GitDeploy(repositoryName);
  360. KuduAssert.VerifyUrl(appManager.SiteUrl, verificationText);
  361. repo.AppendFile(@"Mvc3Application\Views\Home\Index.cshtml", "Say Whattttt!");
  362. // Make a small changes and commit them to the local repo
  363. Git.Commit(repositoryName, "This is a small changes");
  364. // Push those changes
  365. appManager.GitDeploy(repositoryName);
  366. // Make a server site change and verify it shows up
  367. appManager.ProjectSystem.WriteAllText("Views/Home/Index.cshtml", "Hello world!");
  368. Thread.Sleep(500);
  369. KuduAssert.VerifyUrl(appManager.SiteUrl, "Hello world!");
  370. // Now go back in time
  371. appManager.DeploymentManager.DeployAsync(id).Wait();
  372. var results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  373. // Assert
  374. Assert.Equal(2, results.Count);
  375. Assert.Equal(DeployStatus.Success, results[0].Status);
  376. KuduAssert.VerifyUrl(appManager.SiteUrl, verificationText);
  377. });
  378. }
  379. }
  380. [Fact]
  381. public void DeletesToRepositoryArePropagatedForNonWaps()
  382. {
  383. string repositoryName = "Bakery10";
  384. string appName = KuduUtils.GetRandomWebsiteName("DeleteForNonWaps");
  385. using (var repo = Git.CreateLocalRepository(repositoryName))
  386. {
  387. ApplicationManager.Run(appName, appManager =>
  388. {
  389. string deletePath = Path.Combine(repo.PhysicalPath, @"Styles");
  390. // Act
  391. appManager.GitDeploy(repo.PhysicalPath);
  392. // Assert
  393. var results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  394. Assert.Equal(1, results.Count);
  395. Assert.Equal(DeployStatus.Success, results[0].Status);
  396. KuduAssert.VerifyUrl(appManager.SiteUrl + "Styles/Site.css", statusCode: HttpStatusCode.OK);
  397. Directory.Delete(deletePath, recursive: true);
  398. Git.Commit(repo.PhysicalPath, "Deleted all styles");
  399. appManager.GitDeploy(repo.PhysicalPath);
  400. results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  401. // Assert
  402. Assert.Equal(2, results.Count);
  403. Assert.Equal(DeployStatus.Success, results[1].Status);
  404. KuduAssert.VerifyUrl(appManager.SiteUrl + "Styles/Site.css", statusCode: HttpStatusCode.NotFound);
  405. });
  406. }
  407. }
  408. [Fact]
  409. public void FirstPushDeletesPriorContent()
  410. {
  411. string repositoryName = "Bakery10";
  412. string appName = KuduUtils.GetRandomWebsiteName("FirstPushDelPrior");
  413. using (var repo = Git.CreateLocalRepository(repositoryName))
  414. {
  415. ApplicationManager.Run(appName, appManager =>
  416. {
  417. appManager.ProjectSystem.WriteAllText("foo.txt", "This is a test file");
  418. string url = appManager.SiteUrl + "/foo.txt";
  419. Thread.Sleep(500);
  420. KuduAssert.VerifyUrl(url, "This is a test file");
  421. // Act
  422. appManager.GitDeploy(repo.PhysicalPath);
  423. // Assert
  424. var results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  425. Assert.Equal(1, results.Count);
  426. Assert.Equal(DeployStatus.Success, results[0].Status);
  427. KuduAssert.VerifyUrl(appManager.SiteUrl);
  428. KuduAssert.VerifyUrl(url, statusCode: HttpStatusCode.NotFound);
  429. });
  430. }
  431. }
  432. [Fact]
  433. public void PushingToNonMasterBranchNoOps()
  434. {
  435. string repositoryName = "PushingToNonMasterBranchNoOps";
  436. string appName = KuduUtils.GetRandomWebsiteName("PushToNonMaster");
  437. string cloneUrl = "https://github.com/KuduApps/RepoWithMultipleBranches.git";
  438. using (var repo = Git.Clone(repositoryName, cloneUrl))
  439. {
  440. Git.CheckOut(repo.PhysicalPath, "test");
  441. ApplicationManager.Run(appName, appManager =>
  442. {
  443. // Act
  444. appManager.GitDeploy(repo.PhysicalPath, "test", "test");
  445. var results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  446. // Assert
  447. Assert.Equal(0, results.Count);
  448. KuduAssert.VerifyUrl(appManager.SiteUrl, "The web site is under construction");
  449. });
  450. }
  451. }
  452. [Fact]
  453. public void PushingConfiguredBranch()
  454. {
  455. string repositoryName = "PushingConfiguredBranch";
  456. string appName = KuduUtils.GetRandomWebsiteName("PushingConfiguredBranch");
  457. string cloneUrl = "https://github.com/KuduApps/RepoWithMultipleBranches.git";
  458. using (var repo = Git.Clone(repositoryName, cloneUrl))
  459. {
  460. Git.CheckOut(repo.PhysicalPath, "test");
  461. ApplicationManager.Run(appName, appManager =>
  462. {
  463. // Act
  464. appManager.SettingsManager.SetValue("branch", "test").Wait();
  465. appManager.GitDeploy(repo.PhysicalPath, "test", "test");
  466. var results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  467. // Assert
  468. Assert.Equal(1, results.Count);
  469. KuduAssert.VerifyUrl(appManager.SiteUrl, "Test branch");
  470. });
  471. }
  472. }
  473. [Fact]
  474. public void PushingNonMasterBranchToMasterBranchShouldDeploy()
  475. {
  476. string repositoryName = "PushingNonMasterBranchToMasterBranchShouldDeploy";
  477. string appName = KuduUtils.GetRandomWebsiteName("PushNonMasterToMaster");
  478. string cloneUrl = "https://github.com/KuduApps/RepoWithMultipleBranches.git";
  479. using (var repo = Git.Clone(repositoryName, cloneUrl))
  480. {
  481. Git.CheckOut(repo.PhysicalPath, "test");
  482. ApplicationManager.Run(appName, appManager =>
  483. {
  484. // Act
  485. appManager.GitDeploy(repo.PhysicalPath, "test", "master");
  486. var results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  487. // Assert
  488. Assert.Equal(1, results.Count);
  489. KuduAssert.VerifyUrl(appManager.SiteUrl, "Test branch");
  490. });
  491. }
  492. }
  493. [Fact]
  494. public void CloneFromEmptyRepoAndPushShouldDeploy()
  495. {
  496. string repositoryName = "CloneFromEmptyRepoAndPushShouldDeploy";
  497. string appName = KuduUtils.GetRandomWebsiteName("CloneEmptyAndPush");
  498. ApplicationManager.Run(appName, appManager =>
  499. {
  500. // Act
  501. using (var repo = Git.Clone(repositoryName, appManager.GitUrl, createDirectory: true))
  502. {
  503. // Add a file
  504. repo.WriteFile("hello.txt", "Wow");
  505. Git.Commit(repo.PhysicalPath, "Added hello.txt");
  506. string helloUrl = appManager.SiteUrl + "/hello.txt";
  507. appManager.GitDeploy(repo.PhysicalPath);
  508. var results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  509. // Assert
  510. Assert.Equal(1, results.Count);
  511. KuduAssert.VerifyUrl(helloUrl, "Wow");
  512. }
  513. });
  514. }
  515. [Fact]
  516. public void PushThenClone()
  517. {
  518. string repositoryName = "Bakery10";
  519. string appName = KuduUtils.GetRandomWebsiteName("PushThenClone");
  520. using (var repo = Git.CreateLocalRepository(repositoryName))
  521. {
  522. ApplicationManager.Run(appName, appManager =>
  523. {
  524. // Act
  525. appManager.GitDeploy(repo.PhysicalPath);
  526. using (var clonedRepo = Git.Clone(repositoryName, appManager.GitUrl, createDirectory: true))
  527. {
  528. Assert.True(clonedRepo.FileExists("Default.cshtml"));
  529. }
  530. });
  531. }
  532. }
  533. [Fact]
  534. public void CloneFromNewRepoShouldHaveBeEmpty()
  535. {
  536. string repositoryName = "CloneFromNewRepoShouldHaveFile";
  537. string appName = KuduUtils.GetRandomWebsiteName("CloneNew");
  538. ApplicationManager.Run(appName, appManager =>
  539. {
  540. using (var repo = Git.Clone(repositoryName, appManager.GitUrl, createDirectory: true))
  541. {
  542. Assert.False(repo.FileExists("index.html"));
  543. }
  544. });
  545. }
  546. [Fact]
  547. public void ClonesInParallel()
  548. {
  549. string appName = KuduUtils.GetRandomWebsiteName("ClonesInParallel");
  550. ApplicationManager.Run(appName, appManager =>
  551. {
  552. var t1 = Task.Factory.StartNew(() => DoClone("PClone1", appManager));
  553. var t2 = Task.Factory.StartNew(() => DoClone("PClone2", appManager));
  554. var t3 = Task.Factory.StartNew(() => DoClone("PClone3", appManager));
  555. Task.WaitAll(t1, t2, t3);
  556. });
  557. }
  558. private static void DoClone(string repositoryName, ApplicationManager appManager)
  559. {
  560. using (var repo = Git.Clone(repositoryName, appManager.GitUrl, createDirectory: true))
  561. {
  562. Assert.False(repo.FileExists("index.html"));
  563. }
  564. }
  565. [Fact]
  566. public void GoingBackInTimeDeploysOldFiles()
  567. {
  568. string repositoryName = "Bakery10";
  569. string appName = KuduUtils.GetRandomWebsiteName("GoBackDeployOld");
  570. using (var repo = Git.CreateLocalRepository(repositoryName))
  571. {
  572. string originalCommitId = repo.CurrentId;
  573. ApplicationManager.Run(appName, appManager =>
  574. {
  575. // Deploy the app
  576. appManager.GitDeploy(repo.PhysicalPath);
  577. var results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  578. Assert.Equal(1, results.Count);
  579. KuduAssert.VerifyUrl(appManager.SiteUrl);
  580. // Add a file
  581. File.WriteAllText(Path.Combine(repo.PhysicalPath, "hello.txt"), "Wow");
  582. Git.Commit(repo.PhysicalPath, "Added hello.txt");
  583. string helloUrl = appManager.SiteUrl + "/hello.txt";
  584. // Deploy those changes
  585. appManager.GitDeploy(repo.PhysicalPath);
  586. results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  587. Assert.Equal(2, results.Count);
  588. Assert.Equal(DeployStatus.Success, results[1].Status);
  589. KuduAssert.VerifyUrl(helloUrl, "Wow");
  590. // Go back to the first deployment
  591. appManager.DeploymentManager.DeployAsync(originalCommitId).Wait();
  592. results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  593. KuduAssert.VerifyUrl(helloUrl, statusCode: HttpStatusCode.NotFound);
  594. Assert.Equal(2, results.Count);
  595. });
  596. }
  597. }
  598. [Fact(Skip = "NPM issue")]
  599. public void NpmSiteInstallsPackages()
  600. {
  601. string repositoryName = "NpmSiteInstallsPackages";
  602. string appName = KuduUtils.GetRandomWebsiteName("NpmInstallsPkg");
  603. string cloneUrl = "https://github.com/KuduApps/NpmSite.git";
  604. using (var repo = Git.Clone(repositoryName, cloneUrl))
  605. {
  606. ApplicationManager.Run(appName, appManager =>
  607. {
  608. // Act
  609. appManager.GitDeploy(repo.PhysicalPath);
  610. var results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  611. var files = appManager.ProjectSystem.GetProject().Files.ToList();
  612. // Assert
  613. Assert.Equal(1, results.Count);
  614. Assert.Equal(DeployStatus.Success, results[0].Status);
  615. Assert.True(files.Any(f => f.StartsWith("node_modules/express")));
  616. });
  617. }
  618. }
  619. [Fact(Skip = "NPM issue")]
  620. public void FailedNpmFailsDeployment()
  621. {
  622. string repositoryName = "FailedNpmFailsDeployment";
  623. string appName = KuduUtils.GetRandomWebsiteName("FailedNpm");
  624. string cloneUrl = "https://github.com/KuduApps/NpmSite.git";
  625. using (var repo = Git.Clone(repositoryName, cloneUrl))
  626. {
  627. ApplicationManager.Run(appName, appManager =>
  628. {
  629. // Replace the express dependency with something that doesn't exist
  630. repo.Replace("package.json", "express", "MadeUpKuduPackage");
  631. Git.Commit(repo.PhysicalPath, "Added fake package to package.json");
  632. // Act
  633. appManager.GitDeploy(repo.PhysicalPath);
  634. var results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  635. // Assert
  636. Assert.Equal(1, results.Count);
  637. Assert.Equal(DeployStatus.Failed, results[0].Status);
  638. KuduAssert.VerifyLogOutput(appManager, results[0].Id, "'MadeUpKuduPackage' is not in the npm registry.");
  639. });
  640. }
  641. }
  642. [Fact]
  643. public void CustomNodeScript()
  644. {
  645. string repositoryName = "CustomNodeScript";
  646. string appName = KuduUtils.GetRandomWebsiteName("CustomNodeScript");
  647. string webConfig = @"
  648. <?xml version=""1.0"" encoding=""utf-8""?>
  649. <configuration>
  650. <system.webServer>
  651. <handlers>
  652. <add name=""iisnode"" path=""server.js"" verb=""*"" modules=""iisnode""/>
  653. </handlers>
  654. <rewrite>
  655. <rules>
  656. <rule name=""StaticContent"">
  657. <action type=""Rewrite"" url=""public{REQUEST_URI}""/>
  658. </rule>
  659. <rule name=""DynamicContent"">
  660. <conditions>
  661. <add input=""{REQUEST_FILENAME}"" matchType=""IsFile"" negate=""True""/>
  662. </conditions>
  663. <action type=""Rewrite"" url=""server.js""/>
  664. </rule>
  665. </rules>
  666. </rewrite>
  667. <iisnode
  668. nodeProcessCommandLine=""&quot;%programfiles(x86)%\nodejs\node.exe&quot;""
  669. debuggingEnabled=""false""
  670. logDirectory=""..\..\LogFiles\nodejs""
  671. watchedFiles=""*.js;iisnode.yml;node_modules\*;views\*.jade;views\*.ejb;routes\*.js"" />
  672. </system.webServer>
  673. </configuration>";
  674. var path = Git.GetRepositoryPath(repositoryName);
  675. using (var repo = Git.Init(path))
  676. {
  677. repo.WriteFile("build.js", String.Format(@"var fs = require('fs');
  678. console.log('Creating server.js on the fly!');
  679. console.log('target is ' + process.env.TARGET);
  680. fs.writeFileSync(process.env.TARGET + '\server.js', ""var http = require('http'); http.createServer(function (req, res) {{ res.writeHead(200, {{'Content-Type': 'text/html'}}); res.end('Hello, world! [helloworld sample; iisnode version is ' + process.env.IISNODE_VERSION + ', node version is ' + process.version + ']'); }}).listen(process.env.PORT);"");
  681. console.log('Done!');", webConfig));
  682. repo.WriteFile(".deployment", @"
  683. [config]
  684. command = node build.js
  685. ");
  686. repo.WriteFile("web.config", webConfig);
  687. Git.Commit(repo.PhysicalPath, "Added build.js");
  688. ApplicationManager.Run(appName, appManager =>
  689. {
  690. // Act
  691. appManager.GitDeploy(repo.PhysicalPath);
  692. var results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  693. var files = appManager.ProjectSystem.GetProject().Files.ToList();
  694. // Assert
  695. Assert.Equal(1, results.Count);
  696. Assert.Equal(DeployStatus.Success, results[0].Status);
  697. KuduAssert.VerifyUrl(appManager.SiteUrl);
  698. });
  699. }
  700. }
  701. [Fact]
  702. public void NodeHelloWorldNoConfig()
  703. {
  704. string repositoryName = "NodeHelloWorldNoConfig";
  705. string appName = KuduUtils.GetRandomWebsiteName("NodeConfig");
  706. string cloneUrl = "https://github.com/KuduApps/NodeHelloWorldNoConfig.git";
  707. using (var repo = Git.Clone(repositoryName, cloneUrl))
  708. {
  709. ApplicationManager.Run(appName, appManager =>
  710. {
  711. // Act
  712. appManager.GitDeploy(repo.PhysicalPath);
  713. var results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  714. var files = appManager.ProjectSystem.GetProject().Files.ToList();
  715. // Assert
  716. Assert.Equal(1, results.Count);
  717. Assert.Equal(DeployStatus.Success, results[0].Status);
  718. // Make sure a web.config file got created at deployment time
  719. Assert.True(files.Contains("web.config"));
  720. });
  721. }
  722. }
  723. [Fact]
  724. public void RedeployNodeSite()
  725. {
  726. string repositoryName = "RedeployNodeSite";
  727. string appName = KuduUtils.GetRandomWebsiteName("RedeployNodeSite");
  728. string cloneUrl = "https://github.com/KuduApps/NodeHelloWorldNoConfig.git";
  729. using (var repo = Git.Clone(repositoryName, cloneUrl))
  730. {
  731. ApplicationManager.Run(appName, appManager =>
  732. {
  733. // Act
  734. appManager.GitDeploy(repo.PhysicalPath);
  735. var results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  736. // Assert
  737. Assert.Equal(1, results.Count);
  738. Assert.Equal(DeployStatus.Success, results[0].Status);
  739. string id = results[0].Id;
  740. repo.Replace("server.js", "world", "world2");
  741. Git.Commit(repo.PhysicalPath, "Made a small change");
  742. appManager.GitDeploy(repo.PhysicalPath);
  743. results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  744. Assert.Equal(2, results.Count);
  745. Assert.Equal(DeployStatus.Success, results[1].Status);
  746. appManager.DeploymentManager.DeployAsync(id).Wait();
  747. results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  748. Assert.Equal(2, results.Count);
  749. Assert.Equal(DeployStatus.Success, results[0].Status);
  750. Assert.Equal(DeployStatus.Success, results[1].Status);
  751. });
  752. }
  753. }
  754. [Fact]
  755. public void GetResultsWithMaxItemsAndExcludeFailed()
  756. {
  757. // Arrange
  758. string repositoryName = "Mvc3Application";
  759. string appName = KuduUtils.GetRandomWebsiteName("RsltMaxItemXcldFailed");
  760. using (var repo = Git.CreateLocalRepository(repositoryName))
  761. {
  762. ApplicationManager.Run(appName, appManager =>
  763. {
  764. string homeControllerPath = Path.Combine(repo.PhysicalPath, @"Mvc3Application\Controllers\HomeController.cs");
  765. // Act, Initial Commit
  766. appManager.GitDeploy(repo.PhysicalPath);
  767. // Assert
  768. var results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  769. Assert.Equal(1, results.Count);
  770. Assert.Equal(DeployStatus.Success, results[0].Status);
  771. KuduAssert.VerifyUrl(appManager.SiteUrl, "Welcome to ASP.NET MVC! - Change1");
  772. // Act, Change 2
  773. File.WriteAllText(homeControllerPath, File.ReadAllText(homeControllerPath).Replace(" - Change1", " - Change2"));
  774. Git.Commit(repo.PhysicalPath, "Change 2!");
  775. appManager.GitDeploy(repo.PhysicalPath);
  776. // Assert
  777. results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  778. Assert.Equal(2, results.Count);
  779. Assert.Equal(DeployStatus.Success, results[0].Status);
  780. Assert.Equal(DeployStatus.Success, results[1].Status);
  781. KuduAssert.VerifyUrl(appManager.SiteUrl, "Welcome to ASP.NET MVC! - Change2");
  782. // Act, Invalid Change build-break change and commit
  783. File.WriteAllText(homeControllerPath, File.ReadAllText(homeControllerPath).Replace("Index()", "Index;"));
  784. Git.Commit(repo.PhysicalPath, "Invalid Change!");
  785. appManager.GitDeploy(repo.PhysicalPath);
  786. // Assert
  787. results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  788. Assert.Equal(3, results.Count);
  789. Assert.Equal(DeployStatus.Failed, results[0].Status);
  790. Assert.Equal(DeployStatus.Success, results[1].Status);
  791. Assert.Equal(DeployStatus.Success, results[2].Status);
  792. KuduAssert.VerifyUrl(appManager.SiteUrl, "Welcome to ASP.NET MVC! - Change2");
  793. // Test maxItems = 2
  794. results = appManager.DeploymentManager.GetResultsAsync(maxItems: 2).Result.ToList();
  795. Assert.Equal(2, results.Count);
  796. Assert.Equal(DeployStatus.Failed, results[0].Status);
  797. Assert.Equal(DeployStatus.Success, results[1].Status);
  798. // Test excludeFailed = true
  799. results = appManager.DeploymentManager.GetResultsAsync(excludeFailed: true).Result.ToList();
  800. Assert.Equal(2, results.Count);
  801. Assert.Equal(DeployStatus.Success, results[0].Status);
  802. Assert.Equal(DeployStatus.Success, results[1].Status);
  803. // Test maxItems = 1, excludeFailed = true
  804. results = appManager.DeploymentManager.GetResultsAsync(maxItems: 1, excludeFailed: true).Result.ToList();
  805. Assert.Equal(1, results.Count);
  806. Assert.Equal(DeployStatus.Success, results[0].Status);
  807. Assert.True(results[0].Current);
  808. });
  809. }
  810. }
  811. [Fact]
  812. public void SpecificDeploymentConfiguration()
  813. {
  814. VerifyDeploymentConfiguration("SpecificDeployConfig",
  815. "WebApplication1",
  816. "This is the application I want deployed");
  817. }
  818. [Fact]
  819. public void SpecificDeploymentConfigurationForProjectFile()
  820. {
  821. VerifyDeploymentConfiguration("DeployConfigForProj",
  822. "WebApplication1/WebApplication1.csproj",
  823. "This is the application I want deployed");
  824. }
  825. [Fact]
  826. public void SpecificDeploymentConfigurationForWebsite()
  827. {
  828. VerifyDeploymentConfiguration("DeployConfigForWeb",
  829. "WebSite1",
  830. "This is a website!");
  831. }
  832. [Fact]
  833. public void SpecificDeploymentConfigurationForWebsiteWithSlash()
  834. {
  835. VerifyDeploymentConfiguration("DeployConfigWithSlash",
  836. "/WebSite1",
  837. "This is a website!");
  838. }
  839. [Fact]
  840. public void SpecificDeploymentConfigurationForWebsiteNotPartOfSolution()
  841. {
  842. VerifyDeploymentConfiguration("SpecificDeploymentConfigurationForWebsiteNotPartOfSolution",
  843. "WebSiteRemovedFromSolution",
  844. "This web site was removed from solution!");
  845. }
  846. [Fact]
  847. public void SpecificDeploymentConfigurationForWebProjectNotPartOfSolution()
  848. {
  849. VerifyDeploymentConfiguration("SpecificDeploymentConfigurationForWebProjectNotPartOfSolution",
  850. "MvcApplicationRemovedFromSolution",
  851. "This web project was removed from solution!");
  852. }
  853. [Fact]
  854. public void SpecificDeploymentConfigurationForNonDeployableProjectFile()
  855. {
  856. VerifyDeploymentConfiguration("SpecificDeploymentConfigurationForNonDeployableProjectFile",
  857. "MvcApplicationRemovedFromSolution.Tests/MvcApplicationRemovedFromSolution.Tests.csproj",
  858. "The web site is under construction",
  859. DeployStatus.Failed);
  860. }
  861. [Fact]
  862. public void SpecificDeploymentConfigurationForNonDeployableProject()
  863. {
  864. VerifyDeploymentConfiguration("SpecificDeploymentConfigurationForNonDeployableProject",
  865. "MvcApplicationRemovedFromSolution.Tests",
  866. "The web site is under construction",
  867. DeployStatus.Failed,
  868. "is not a deployable project");
  869. }
  870. [Fact]
  871. public void SpecificDeploymentConfigurationForDirectoryThatDoesNotExist()
  872. {
  873. VerifyDeploymentConfiguration("SpecificDeploymentConfigurationForDirectoryThatDoesNotExist",
  874. "IDoNotExist",
  875. "The web site is under construction",
  876. DeployStatus.Failed);
  877. }
  878. private void VerifyDeploymentConfiguration(string siteName, string targetProject, string expectedText, DeployStatus expectedStatus = DeployStatus.Success, string expectedLog = null)
  879. {
  880. string name = KuduUtils.GetRandomWebsiteName(siteName);
  881. string cloneUrl = "https://github.com/KuduApps/SpecificDeploymentConfiguration.git";
  882. using (var repo = Git.Clone(name, cloneUrl))
  883. {
  884. ApplicationManager.Run(name, appManager =>
  885. {
  886. string deploymentFile = Path.Combine(repo.PhysicalPath, @".deployment");
  887. File.WriteAllText(deploymentFile, String.Format(@"[config]
  888. project = {0}", targetProject));
  889. Git.Commit(name, "Updated configuration");
  890. // Act
  891. appManager.GitDeploy(repo.PhysicalPath);
  892. var results = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
  893. // Assert
  894. Assert.Equal(1, results.Count);
  895. Assert.Equal(expectedStatus, results[0].Status);
  896. KuduAssert.VerifyUrl(appManager.SiteUrl, expectedText);
  897. if (!String.IsNullOrEmpty(expectedLog))
  898. {
  899. KuduAssert.VerifyLogOutput(appManager, results[0].Id, expectedLog);
  900. }
  901. });
  902. }
  903. }
  904. }
  905. }