public async Task ArcadeChannels_DefaultChannels() { string repoUrl = GetRepoUrl(repoName); string testChannelName1 = "Test Channel Default 1"; string testChannelName2 = "Test Channel Default 2"; await using (AsyncDisposableValue <string> channel1 = await CreateTestChannelAsync(testChannelName1).ConfigureAwait(false)) { await using (AsyncDisposableValue <string> channel2 = await CreateTestChannelAsync(testChannelName2).ConfigureAwait(false)) { await AddDefaultTestChannelAsync(testChannelName1, repoUrl, branchNameWithRefsHeads).ConfigureAwait(false); await AddDefaultTestChannelAsync(testChannelName2, repoUrl, branchNameWithRefsHeads).ConfigureAwait(false); string defaultChannels = await GetDefaultTestChannelsAsync(repoUrl, branchName).ConfigureAwait(false); StringAssert.Contains(testChannelName1, defaultChannels, $"{testChannelName1} is not a default channel"); StringAssert.Contains(testChannelName2, defaultChannels, $"{testChannelName2} is not a default channel"); await DeleteDefaultTestChannelAsync(testChannelName1, repoUrl, branchName); await DeleteDefaultTestChannelAsync(testChannelName2, repoUrl, branchName); defaultChannels = await GetDefaultTestChannelsAsync(repoUrl, branchName).ConfigureAwait(false); StringAssert.DoesNotContain(testChannelName1, defaultChannels, $"{testChannelName1} was not deleted from default channels"); StringAssert.DoesNotContain(testChannelName2, defaultChannels, $"{testChannelName2} was not deleted from default channels"); } } }
public async Task <AsyncDisposableValue <string> > CreateSubscriptionAsync(string yamlDefinition) { string output = await RunDarcAsyncWithInput(yamlDefinition, "add-subscription", "-q", "--read-stdin", "--no-trigger").ConfigureAwait(false); Match match = Regex.Match(output, "Successfully created new subscription with id '([a-f0-9-]+)'"); if (match.Success) { string subscriptionId = match.Groups[1].Value; return(AsyncDisposableValue.Create(subscriptionId, async() => { TestContext.WriteLine($"Cleaning up Test Subscription {subscriptionId}"); try { await RunDarcAsync("delete-subscriptions", "--id", subscriptionId, "--quiet").ConfigureAwait(false); } catch (MaestroTestException) { // If this throws an exception the most likely cause is that the subscription was deleted as part of the test case } })); } throw new MaestroTestException("Unable to create subscription."); }
public async Task <AsyncDisposableValue <string> > CreateTestChannelAsync(string testChannelName) { try { await RunDarcAsync("delete-channel", "--name", testChannelName).ConfigureAwait(false); } catch (MaestroTestException) { // Ignore failures from delete-channel, its just a pre-cleanup that isn't really part of the test } await RunDarcAsync("add-channel", "--name", testChannelName, "--classification", "test").ConfigureAwait(false); return(AsyncDisposableValue.Create(testChannelName, async() => { TestContext.WriteLine($"Cleaning up Test Channel {testChannelName}"); try { string doubleDelete = await RunDarcAsync("delete-channel", "--name", testChannelName).ConfigureAwait(false); } catch (MaestroTestException) { // Ignore failures from delete-channel, this delete is here to ensure that the channel is deleted // even if the test does not do an explicit delete as part of the test } })); }
public async Task ArcadeChannels_EndToEnd() { _parameters = await TestParameters.GetAsync(); SetTestParameters(_parameters); // Create a new channel string testChannelName = $"Test Channel End to End {Environment.MachineName}"; await using (AsyncDisposableValue <string> channel = await CreateTestChannelAsync(testChannelName).ConfigureAwait(false)) { // Get the channel and make sure it's there string returnedChannel = await GetTestChannelsAsync().ConfigureAwait(false); StringAssert.Contains(testChannelName, returnedChannel, "Channel was not created or could not be retrieved"); // Delete the channel await DeleteTestChannelAsync(testChannelName).ConfigureAwait(false); // Get the channel and make sure it was deleted string returnedChannel2 = await GetTestChannelsAsync().ConfigureAwait(false); StringAssert.DoesNotContain(testChannelName, returnedChannel2, "Channel was not deleted"); } }
public async Task NonBatchedAzDoFlowTestBase(string targetBranch, string channelName, IImmutableList <AssetData> sourceAssets, List <DependencyDetail> expectedDependencies, bool allChecks = false, bool isFeedTest = false, string[] expectedFeeds = null, string[] notExpectedFeeds = null) { string targetRepoName = TestRepository.TestRepo2Name; string sourceRepoName = TestRepository.TestRepo1Name; string testChannelName = channelName; string sourceRepoUri = GetAzDoRepoUrl(sourceRepoName); string targetRepoUri = GetAzDoRepoUrl(targetRepoName); TestContext.WriteLine($"Creating test channel {testChannelName}"); await using AsyncDisposableValue <string> testChannel = await CreateTestChannelAsync(testChannelName).ConfigureAwait(false); await using AsyncDisposableValue <string> subscription1Id = await CreateSubscriptionForEndToEndTests( testChannelName, sourceRepoName, targetRepoName, targetBranch, allChecks, true); TestContext.WriteLine("Set up build for intake into target repository"); Build build = await CreateBuildAsync(sourceRepoUri, TestRepository.SourceBranch, TestRepository.CoherencyTestRepo1Commit, sourceBuildNumber, sourceAssets); await AddBuildToChannelAsync(build.Id, testChannelName); TestContext.WriteLine("Cloning target repo to prepare the target branch"); TemporaryDirectory reposFolder = await CloneAzDoRepositoryAsync(targetRepoName, targetBranch); using (ChangeDirectory(reposFolder.Directory)) { await using (await CheckoutBranchAsync(targetBranch)) { TestContext.WriteLine("Adding dependencies to target repo"); await AddDependenciesToLocalRepo(reposFolder.Directory, sourceAssets.ToList(), sourceRepoUri); TestContext.WriteLine("Pushing branch to remote"); await GitCommitAsync("Add dependencies"); await using (await PushGitBranchAsync("origin", targetBranch)) { TestContext.WriteLine("Trigger the dependency update"); await TriggerSubscriptionAsync(subscription1Id.Value); TestContext.WriteLine($"Waiting on PR to be opened in {targetRepoUri}"); if (allChecks) { await CheckNonBatchedAzDoPullRequest(sourceRepoName, targetRepoName, targetBranch, expectedDependencies, reposFolder.Directory, isCompleted : true, isUpdated : false); return; } if (isFeedTest) { await CheckNonBatchedAzDoPullRequest(sourceRepoName, targetRepoName, targetBranch, expectedDependencies, reposFolder.Directory, isCompleted : false, isUpdated : false, expectedFeeds : expectedFeeds, notExpectedFeeds : notExpectedFeeds); return; } } } } }
public async Task AutoMergeFlowTestBase(string targetRepo, string sourceRepo, string targetBranch, string testChannelName, List <string> args) { string targetRepoUri = GetRepoUrl(targetRepo); var sourceRepoUri = GetRepoUrl(sourceRepo); var sourceBranch = "dependencyflow-tests"; var sourceCommit = "0b36b99e29b1751403e23cfad0a7dff585818051"; var sourceBuildNumber = _random.Next(int.MaxValue).ToString(); ImmutableList <AssetData> sourceAssets = ImmutableList.Create <AssetData>() .Add(new AssetData(true) { Name = "Foo", Version = "1.1.0", }) .Add(new AssetData(true) { Name = "Bar", Version = "2.1.0", }); TestContext.WriteLine($"Creating test channel {testChannelName}"); await using AsyncDisposableValue <string> channel = await CreateTestChannelAsync(testChannelName).ConfigureAwait(false); TestContext.WriteLine($"Adding a subscription from ${sourceRepo} to ${targetRepo}"); await using AsyncDisposableValue <string> sub = await CreateSubscriptionAsync(testChannelName, sourceRepo, targetRepo, targetBranch, "none", "maestro-auth-test", additionalOptions : args); TestContext.WriteLine("Set up build for intake into target repository"); Build build = await CreateBuildAsync(sourceRepoUri, sourceBranch, sourceCommit, sourceBuildNumber, sourceAssets); await using IAsyncDisposable _ = await AddBuildToChannelAsync(build.Id, testChannelName); TestContext.WriteLine("Cloning target repo to prepare the target branch"); using TemporaryDirectory repo = await CloneRepositoryAsync(targetRepo); using (ChangeDirectory(repo.Directory)) { await RunGitAsync("checkout", "-b", targetBranch).ConfigureAwait(false); TestContext.WriteLine("Adding dependencies to target repo"); await AddDependenciesToLocalRepo(repo.Directory, "Foo", sourceRepoUri); await AddDependenciesToLocalRepo(repo.Directory, "Bar", sourceRepoUri); TestContext.WriteLine("Pushing branch to remote"); await RunGitAsync("commit", "-am", "Add dependencies."); await using IAsyncDisposable ___ = await PushGitBranchAsync("origin", targetBranch); await TriggerSubscriptionAsync(sub.Value); TestContext.WriteLine($"Waiting on PR to be opened in ${targetRepoUri}"); bool testResult = await CheckGithubPullRequestChecks(targetRepo, targetBranch); Assert.IsTrue(testResult); } }
public async Task <AsyncDisposableValue <string> > CreateSubscriptionAsync( string sourceChannelName, string sourceRepo, string targetRepo, string targetBranch, string updateFrequency, string sourceOrg = "dotnet", List <string> additionalOptions = null, bool sourceIsAzDo = false, bool targetIsAzDo = false, bool trigger = false) { string sourceUrl = sourceIsAzDo ? GetAzDoRepoUrl(sourceRepo) : GetRepoUrl(sourceOrg, sourceRepo); string targetUrl = targetIsAzDo ? GetAzDoRepoUrl(targetRepo) : GetRepoUrl(targetRepo); string[] command = { "add-subscription", "-q", "--channel", sourceChannelName, "--source-repo", sourceUrl, "--target-repo", targetUrl, "--target-branch", targetBranch, "--update-frequency", updateFrequency, trigger? "--trigger" : "--no-trigger" }; if (additionalOptions != null) { command = command.Concat(additionalOptions).ToArray(); } string output = await RunDarcAsync(command).ConfigureAwait(false); Match match = Regex.Match(output, "Successfully created new subscription with id '([a-f0-9-]+)'"); if (!match.Success) { throw new MaestroTestException("Unable to create subscription."); } string subscriptionId = match.Groups[1].Value; return(AsyncDisposableValue.Create(subscriptionId, async() => { TestContext.WriteLine($"Cleaning up Test Subscription {subscriptionId}"); try { await RunDarcAsync("delete-subscriptions", "--id", subscriptionId, "--quiet").ConfigureAwait(false); } catch (MaestroTestException) { // If this throws an exception the most likely cause is that the subscription was deleted as part of the test case } })); }
internal async Task <AsyncDisposableValue <Microsoft.DotNet.DarcLib.PullRequest> > GetAzDoPullRequestAsync(int pullRequestId, string targetRepoName, string targetBranch, bool isUpdated, string expectedPRTitle = null) { string repoUri = GetAzDoRepoUrl(targetRepoName); (string accountName, string projectName, string repoName) = Microsoft.DotNet.DarcLib.AzureDevOpsClient.ParseRepoUri(repoUri); string apiBaseUrl = GetAzDoApiRepoUrl(targetRepoName); if (string.IsNullOrEmpty(expectedPRTitle)) { throw new ArgumentNullException(expectedPRTitle, "ExpectedPRTitle must be defined for AzDo PRs that require an update."); } for (int tries = 10; tries > 0; tries--) { Microsoft.DotNet.DarcLib.PullRequest pr = await AzDoClient.GetPullRequestAsync($"{apiBaseUrl}/pullRequests/{pullRequestId}"); string trimmedTitle = Regex.Replace(pr.Title, @"\s+", " "); if (!isUpdated || trimmedTitle == expectedPRTitle) { return(AsyncDisposableValue.Create(pr, async() => { TestContext.WriteLine($"Cleaning up pull request {pr.Title}"); try { JObject content = await _parameters.AzDoClient.ExecuteAzureDevOpsAPIRequestAsync( HttpMethod.Patch, accountName, projectName, $"_apis/git/repositories/{targetRepoName}/pullrequests/{pullRequestId}", new NUnitLogger(), "{ \"status\" : \"abandoned\"}" ); } catch { // If this throws it means that it was cleaned up by a different clean up method first } })); } await Task.Delay(60 * 1000).ConfigureAwait(false); } throw new MaestroTestException($"The created pull request for {targetRepoName} targeting {targetBranch} was not updated with subsequent subscriptions after creation"); }
public async Task ArcadeChannels_EndToEnd() { // Create a new channel string testChannelName = "Test Channel End to End"; await using (AsyncDisposableValue <string> channel = await CreateTestChannelAsync(testChannelName).ConfigureAwait(false)) { // Get the channel and make sure it's there string returnedChannel = await GetTestChannelsAsync().ConfigureAwait(false); StringAssert.Contains(testChannelName, returnedChannel); // Delete the channel await DeleteTestChannelAsync(testChannelName).ConfigureAwait(false); // Get the channel and make sure it was deleted string returnedChannel2 = await GetTestChannelsAsync().ConfigureAwait(false); StringAssert.DoesNotContain(testChannelName, returnedChannel2); } }
public async Task <AsyncDisposableValue <string> > CreateTestChannelAsync(string testChannelName) { string message = ""; try { message = await RunDarcAsync("delete-channel", "--name", testChannelName).ConfigureAwait(false); } catch (MaestroTestException) { // If there are subscriptions associated the the channel then a previous test clean up failed // Run a subscription clean up and try again try { await DeleteSubscriptionsForChannel(testChannelName).ConfigureAwait(false); await RunDarcAsync("delete-channel", "--name", testChannelName).ConfigureAwait(false); } catch (MaestroTestException) { // Otherwise ignore failures from delete-channel, its just a pre-cleanup that isn't really part of the test // And if the test previously succeeded then it'll fail because the channel doesn't exist } } await RunDarcAsync("add-channel", "--name", testChannelName, "--classification", "test").ConfigureAwait(false); return(AsyncDisposableValue.Create(testChannelName, async() => { TestContext.WriteLine($"Cleaning up Test Channel {testChannelName}"); try { string doubleDelete = await RunDarcAsync("delete-channel", "--name", testChannelName).ConfigureAwait(false); } catch (MaestroTestException) { // Ignore failures from delete-channel on cleanup, this delete is here to ensure that the channel is deleted // even if the test does not do an explicit delete as part of the test. Other failures are typical that the channel has already been deleted. } })); }
public async Task <AsyncDisposableValue <string> > CreateSubscriptionAsync(string sourceChannelName, string sourceRepo, string targetRepo, string targetBranch, string updateFrequency) { string output = await RunDarcAsync("add-subscription", "-q", "--no-trigger", "--channel", sourceChannelName, "--source-repo", GetRepoUrl("dotnet", sourceRepo), "--target-repo", GetRepoUrl(targetRepo), "--target-branch", targetBranch, "--update-frequency", updateFrequency).ConfigureAwait(false); Match match = Regex.Match(output, "Successfully created new subscription with id '([a-f0-9-]+)'"); if (match.Success) { string subscriptionId = match.Groups[1].Value; return(AsyncDisposableValue.Create(subscriptionId, async() => { TestContext.WriteLine($"Cleaning up Test Subscription {subscriptionId}"); await RunDarcAsync("delete-subscriptions", "--id", subscriptionId, "--quiet").ConfigureAwait(false); })); } throw new MaestroTestException("Unable to create subscription."); }
public async Task CheckAzDoPullRequest(string expectedPRTitle, string targetRepoName, string targetBranch, List <Microsoft.DotNet.DarcLib.DependencyDetail> expectedDependencies, string repoDirectory, bool isCompleted, bool isUpdated, string[] expectedFeeds, string[] notExpectedFeeds) { string targetRepoUri = GetAzDoApiRepoUrl(targetRepoName); TestContext.WriteLine($"Checking Opened PR in {targetBranch} {targetRepoUri} ..."); int pullRequestId = await GetAzDoPullRequestIdAsync(targetRepoName, targetBranch); await using AsyncDisposableValue <Microsoft.DotNet.DarcLib.PullRequest> pullRequest = await GetAzDoPullRequestAsync(pullRequestId, targetRepoName, targetBranch, isUpdated, expectedPRTitle); string trimmedTitle = Regex.Replace(pullRequest.Value.Title, @"\s+", " "); StringAssert.AreEqualIgnoringCase(expectedPRTitle, trimmedTitle); Microsoft.DotNet.DarcLib.PrStatus expectedPRState = isCompleted ? Microsoft.DotNet.DarcLib.PrStatus.Closed : Microsoft.DotNet.DarcLib.PrStatus.Open; var prStatus = await AzDoClient.GetPullRequestStatusAsync(GetAzDoApiRepoUrl(targetRepoName) + $"/pullRequests/{pullRequestId}"); Assert.AreEqual(expectedPRState, prStatus); using (ChangeDirectory(repoDirectory)) { await ValidatePullRequestDependencies(targetRepoName, pullRequest.Value.HeadBranch, expectedDependencies); if (expectedFeeds != null && notExpectedFeeds != null) { TestContext.WriteLine("Validating Nuget feeds in PR branch"); ISettings settings = Settings.LoadSpecificSettings(@"./", "nuget.config"); PackageSourceProvider packageSourceProvider = new PackageSourceProvider(settings); IEnumerable <string> sources = packageSourceProvider.LoadPackageSources().Select(p => p.Source); sources.Should().Contain(expectedFeeds); sources.Should().NotContain(notExpectedFeeds); } } }
public async Task ArcadeSdkUpdate() { string testChannelName = "Test Channel " + _random.Next(int.MaxValue); var sourceRepo = "arcade"; var sourceRepoUri = "https://github.com/dotnet/arcade"; var sourceBranch = "dependencyflow-tests"; var sourceCommit = "0b36b99e29b1751403e23cfad0a7dff585818051"; var sourceBuildNumber = _random.Next(int.MaxValue).ToString(); ImmutableList <AssetData> sourceAssets = ImmutableList.Create <AssetData>() .Add(new AssetData(true) { Name = "Microsoft.DotNet.Arcade.Sdk", Version = "2.1.0", }); var targetRepo = "maestro-test2"; var targetBranch = _random.Next(int.MaxValue).ToString(); await using AsyncDisposableValue <string> channel = await CreateTestChannelAsync(testChannelName).ConfigureAwait(false); await using AsyncDisposableValue <string> sub = await CreateSubscriptionAsync(testChannelName, sourceRepo, targetRepo, targetBranch, "none"); Build build = await CreateBuildAsync(GetRepoUrl("dotnet", sourceRepo), sourceBranch, sourceCommit, sourceBuildNumber, sourceAssets); await using IAsyncDisposable _ = await AddBuildToChannelAsync(build.Id, testChannelName); using TemporaryDirectory repo = await CloneRepositoryAsync(targetRepo); using (ChangeDirectory(repo.Directory)) { await RunGitAsync("checkout", "-b", targetBranch).ConfigureAwait(false); await RunDarcAsync("add-dependency", "--name", "Microsoft.DotNet.Arcade.Sdk", "--type", "toolset", "--repo", sourceRepoUri); await RunGitAsync("commit", "-am", "Add dependencies."); await using IAsyncDisposable ___ = await PushGitBranchAsync("origin", targetBranch); await TriggerSubscriptionAsync(sub.Value); PullRequest pr = await WaitForPullRequestAsync(targetRepo, targetBranch); StringAssert.AreEqualIgnoringCase($"[{targetBranch}] Update dependencies from dotnet/arcade", pr.Title); await CheckoutRemoteRefAsync(pr.MergeCommitSha); string dependencies = await RunDarcAsync("get-dependencies"); string[] dependencyLines = dependencies.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); Assert.AreEqual(new[] { "Name: Microsoft.DotNet.Arcade.Sdk", "Version: 2.1.0", $"Repo: {sourceRepoUri}", $"Commit: {sourceCommit}", "Type: Toolset", "Pinned: False", }, dependencyLines); using TemporaryDirectory arcadeRepo = await CloneRepositoryAsync("dotnet", sourceRepo); using (ChangeDirectory(arcadeRepo.Directory)) { await CheckoutRemoteRefAsync(sourceCommit); } var arcadeFiles = Directory.EnumerateFileSystemEntries(Path.Join(arcadeRepo.Directory, "eng", "common"), "*", SearchOption.AllDirectories) .Select(s => s.Substring(arcadeRepo.Directory.Length)) .ToHashSet(); var repoFiles = Directory.EnumerateFileSystemEntries(Path.Join(repo.Directory, "eng", "common"), "*", SearchOption.AllDirectories) .Select(s => s.Substring(repo.Directory.Length)) .ToHashSet(); Assert.IsEmpty(arcadeFiles.Except(repoFiles)); Assert.IsEmpty(repoFiles.Except(arcadeFiles)); } }
public async Task NonBatchedUpdatingAzDoFlowTestBase(string targetBranch, string channelName, IImmutableList <AssetData> sourceAssets, IImmutableList <AssetData> updatedSourceAssets, List <DependencyDetail> expectedDependencies, List <DependencyDetail> expectedUpdatedDependencies) { string targetRepoName = TestRepository.TestRepo2Name; string sourceRepoName = TestRepository.TestRepo1Name; string sourceBranch = TestRepository.SourceBranch; string testChannelName = channelName; string sourceRepoUri = GetAzDoRepoUrl(sourceRepoName); string targetRepoUri = GetAzDoRepoUrl(targetRepoName); TestContext.WriteLine($"Creating test channel {testChannelName}"); await using AsyncDisposableValue <string> testChannel = await CreateTestChannelAsync(testChannelName).ConfigureAwait(false); await using AsyncDisposableValue <string> subscription1Id = await CreateSubscriptionForEndToEndTests( testChannelName, sourceRepoName, targetRepoName, targetBranch, false, true); TestContext.WriteLine("Set up build for intake into target repository"); Build build = await CreateBuildAsync(sourceRepoUri, TestRepository.SourceBranch, TestRepository.CoherencyTestRepo1Commit, sourceBuildNumber, sourceAssets); await AddBuildToChannelAsync(build.Id, testChannelName); TestContext.WriteLine("Cloning target repo to prepare the target branch"); TemporaryDirectory reposFolder = await CloneAzDoRepositoryAsync(targetRepoName, targetBranch); using (ChangeDirectory(reposFolder.Directory)) { await using (await CheckoutBranchAsync(targetBranch)) { TestContext.WriteLine("Adding dependencies to target repo"); await AddDependenciesToLocalRepo(reposFolder.Directory, sourceAssets.ToList(), sourceRepoUri); TestContext.WriteLine("Pushing branch to remote"); await GitCommitAsync("Add dependencies"); await using (await PushGitBranchAsync("origin", targetBranch)) { TestContext.WriteLine("Trigger the dependency update"); await TriggerSubscriptionAsync(subscription1Id.Value); TestContext.WriteLine($"Waiting on PR to be opened in {targetRepoUri}"); await CheckNonBatchedAzDoPullRequest(sourceRepoName, targetRepoName, targetBranch, expectedDependencies, reposFolder.Directory, isCompleted : false, isUpdated : false); TestContext.WriteLine("Set up another build for intake into target repository"); Build build2 = await CreateBuildAsync(sourceRepoUri, sourceBranch, TestRepository.CoherencyTestRepo2Commit, source2BuildNumber, updatedSourceAssets); TestContext.WriteLine("Trigger the dependency update"); await TriggerSubscriptionAsync(subscription1Id.Value); TestContext.WriteLine($"Waiting for PR to be updated in {targetRepoUri}"); await CheckNonBatchedAzDoPullRequest(sourceRepoName, targetRepoName, targetBranch, expectedUpdatedDependencies, reposFolder.Directory, isCompleted : false, isUpdated : true); // Then remove the second build from the channel, trigger the sub again, and it should revert back to the original dependency set TestContext.Write("Remove the build from the channel and verify that the original dependencies are restored"); await DeleteBuildFromChannelAsync(build2.Id.ToString(), testChannelName); TestContext.WriteLine("Trigger the dependency update"); await TriggerSubscriptionAsync(subscription1Id.Value); TestContext.WriteLine($"Waiting for PR to be updated in {targetRepoUri}"); await CheckNonBatchedAzDoPullRequest(sourceRepoName, targetRepoName, targetBranch, expectedDependencies, reposFolder.Directory, isCompleted : false, isUpdated : true); } } } }
public async Task DarcBatchedFlowTestBase(string targetBranch, string channelName, IImmutableList <AssetData> source1Assets, IImmutableList <AssetData> source2Assets, List <DependencyDetail> expectedDependencies, bool isAzDoTest) { string source1RepoName = TestRepository.TestRepo1Name; string source2RepoName = TestRepository.TestRepo3Name; string targetRepoName = TestRepository.TestRepo2Name; string testChannelName = channelName; string source1RepoUri = isAzDoTest ? GetAzDoRepoUrl(source1RepoName) : GetRepoUrl(source1RepoName); string source2RepoUri = isAzDoTest ? GetAzDoRepoUrl(source2RepoName) : GetRepoUrl(source2RepoName); string targetRepoUri = isAzDoTest ? GetAzDoRepoUrl(targetRepoName) : GetRepoUrl(targetRepoName); TestContext.WriteLine($"Creating test channel {testChannelName}"); await using AsyncDisposableValue <string> testChannel = await CreateTestChannelAsync(testChannelName).ConfigureAwait(false); TestContext.WriteLine($"Adding a subscription from {source1RepoName} to {targetRepoName}"); await using AsyncDisposableValue <string> subscription1Id = await CreateSubscriptionAsync(testChannelName, source1RepoName, targetRepoName, targetBranch, UpdateFrequency.None.ToString(), "maestro-auth-test", additionalOptions : new List <string> { "--batchable" }, sourceIsAzDo : isAzDoTest, targetIsAzDo : isAzDoTest); TestContext.WriteLine($"Adding a subscription from {source2RepoName} to {targetRepoName}"); await using AsyncDisposableValue <string> subscription2Id = await CreateSubscriptionAsync(testChannelName, source2RepoName, targetRepoName, targetBranch, UpdateFrequency.None.ToString(), "maestro-auth-test", additionalOptions : new List <string> { "--batchable" }, sourceIsAzDo : isAzDoTest, targetIsAzDo : isAzDoTest); TestContext.WriteLine("Set up build1 for intake into target repository"); Build build1 = await CreateBuildAsync(source1RepoUri, TestRepository.SourceBranch, TestRepository.CoherencyTestRepo1Commit, sourceBuildNumber, source1Assets); await AddBuildToChannelAsync(build1.Id, testChannelName); TestContext.WriteLine("Set up build2 for intake into target repository"); Build build2 = await CreateBuildAsync(source2RepoUri, TestRepository.SourceBranch, TestRepository.CoherencyTestRepo1Commit, sourceBuildNumber, source2Assets); await AddBuildToChannelAsync(build2.Id, testChannelName); TestContext.WriteLine("Cloning target repo to prepare the target branch"); TemporaryDirectory reposFolder = isAzDoTest ? await CloneAzDoRepositoryAsync(targetRepoName, targetBranch) : await CloneRepositoryAsync(targetRepoName); using (ChangeDirectory(reposFolder.Directory)) { await using (await CheckoutBranchAsync(targetBranch)) { TestContext.WriteLine("Adding dependencies to target repo"); await AddDependenciesToLocalRepo(reposFolder.Directory, source1Assets.ToList(), targetRepoUri); await AddDependenciesToLocalRepo(reposFolder.Directory, source2Assets.ToList(), targetRepoUri); TestContext.WriteLine("Pushing branch to remote"); await GitCommitAsync("Add dependencies"); await using (await PushGitBranchAsync("origin", targetBranch)) { TestContext.WriteLine("Trigger the dependency update"); await TriggerSubscriptionAsync(subscription1Id.Value); await TriggerSubscriptionAsync(subscription2Id.Value); TestContext.WriteLine($"Waiting on PR to be opened in {targetRepoUri}"); if (isAzDoTest) { await CheckBatchedAzDoPullRequest(source1RepoName, source2RepoName, targetRepoName, targetBranch, expectedDependencies, reposFolder.Directory); } else { await CheckBatchedGitHubPullRequest(targetBranch, source1RepoName, source2RepoName, targetRepoName, expectedDependencies, reposFolder.Directory); } } } } }
public async Task Subscriptions_EndToEnd() { TestContext.WriteLine("Subscription management tests..."); string repo1Name = TestRepository.TestRepo1Name; string repo2Name = TestRepository.TestRepo2Name; string channel1Name = $"SubscriptionEndToEnd_TestChannel1_{Environment.MachineName}"; string channel2Name = $"SubscriptionEndToEnd_TestChannel2_{Environment.MachineName}"; _parameters = await TestParameters.GetAsync(); SetTestParameters(_parameters); string repo1Uri = GetRepoUrl(repo1Name); string repo2Uri = GetRepoUrl(repo2Name); string repo1AzDoUri = GetAzDoRepoUrl(repo1Name); string targetBranch = $"SubscriptionEndToEnd_TargetBranch_{Environment.MachineName}"; TestContext.WriteLine($"Creating channels {channel1Name} and {channel2Name}"); await using (AsyncDisposableValue <string> channel1 = await CreateTestChannelAsync(channel1Name).ConfigureAwait(false)) { await using (AsyncDisposableValue <string> channel2 = await CreateTestChannelAsync(channel2Name).ConfigureAwait(false)) { TestContext.WriteLine("Testing various command line parameters of add-subscription"); await using AsyncDisposableValue <string> subscription1Id = await CreateSubscriptionAsync( channel1Name, repo1Name, repo2Name, targetBranch, "everyWeek", "maestro-auth-test"); Subscription expectedSubscription1 = SubscriptionBuilder.BuildSubscription( repo1Uri, repo2Uri, targetBranch, channel1Name, subscription1Id.Value, UpdateFrequency.EveryWeek, false); string expectedSubscription1Info = UxHelpers.GetTextSubscriptionDescription(expectedSubscription1, null); await ValidateSubscriptionInfo(subscription1Id.Value, expectedSubscription1Info); await using AsyncDisposableValue <string> subscription2Id = await CreateSubscriptionAsync( channel1Name, repo1Name, repo1Name, targetBranch, "none", "maestro-auth-test", new List <string> { "--all-checks-passed", "--no-extra-commits", "--no-requested-changes", "--ignore-checks", "WIP,license/cla" }, targetIsAzDo : true); Subscription expectedSubscription2 = SubscriptionBuilder.BuildSubscription( repo1Uri, repo1AzDoUri, targetBranch, channel1Name, subscription2Id.Value, UpdateFrequency.None, false, new List <string> { MergePolicyConstants.NoExtraCommitsMergePolicyName, MergePolicyConstants.AllCheckSuccessfulMergePolicyName, MergePolicyConstants.NoRequestedChangesMergePolicyName }, new List <string> { "WIP", "license/cla" }); string expectedSubscription2Info = UxHelpers.GetTextSubscriptionDescription(expectedSubscription2, null); await ValidateSubscriptionInfo(subscription2Id.Value, expectedSubscription2Info); await using AsyncDisposableValue <string> subscription3Id = await CreateSubscriptionAsync( channel2Name, repo1Name, repo2Name, targetBranch, "none", "maestro-auth-test", new List <string> { "--all-checks-passed", "--no-extra-commits", "--no-requested-changes", "--ignore-checks", "WIP,license/cla" }); Subscription expectedSubscription3 = SubscriptionBuilder.BuildSubscription( repo1Uri, repo2Uri, targetBranch, channel2Name, subscription3Id.Value, UpdateFrequency.None, false, new List <string> { MergePolicyConstants.NoExtraCommitsMergePolicyName, MergePolicyConstants.AllCheckSuccessfulMergePolicyName, MergePolicyConstants.NoRequestedChangesMergePolicyName }, new List <string> { "WIP", "license/cla" }); string expectedSubscription3Info = UxHelpers.GetTextSubscriptionDescription(expectedSubscription3, null); await ValidateSubscriptionInfo(subscription3Id.Value, expectedSubscription3Info); // Disable the first two subscriptions, but not the third. TestContext.WriteLine("Disable the subscriptions for test channel 1"); await SetSubscriptionStatus(false, channelName : channel1Name); // Disable one by id (classic usage) to make sure that works TestContext.WriteLine("Disable the third subscription by id"); await SetSubscriptionStatus(false, subscriptionId : subscription3Id.Value); // Re-enable TestContext.WriteLine("Enable the third subscription by id"); await SetSubscriptionStatus(true, subscriptionId : subscription3Id.Value); StringAssert.Contains("Enabled: True", await GetSubscriptionInfo(subscription3Id.Value), $"Expected subscription {subscription3Id} to be enabled"); // Mass delete the subscriptions. Delete the first two but not the third. TestContext.WriteLine("Delete the subscriptions for test channel 1"); string message = await DeleteSubscriptionsForChannel(channel1Name); // Check that there are no subscriptions against channel1 now TestContext.WriteLine("Verify that there are no subscriptions in test channel 1"); Assert.ThrowsAsync <MaestroTestException>(async() => await GetSubscriptions(channel1Name), "Subscriptions for channel 1 were not deleted."); // Validate the third subscription, which should still exist TestContext.WriteLine("Verify that the third subscription still exists, then delete it"); await ValidateSubscriptionInfo(subscription3Id.Value, expectedSubscription3Info); string message2 = await DeleteSubscriptionById(subscription3Id.Value); // Attempt to create a batchable subscription with merge policies. // Should fail, merge policies are set separately for batched subs TestContext.WriteLine("Attempt to create a batchable subscription with merge policies"); Assert.ThrowsAsync <MaestroTestException>(async() => await CreateSubscriptionAsync(channel1Name, repo1Name, repo2Name, targetBranch, "none", additionalOptions: new List <string> { "--standard-automerge", "--batchable" }), "Attempt to create a batchable subscription with merge policies"); // Create a batchable subscription TestContext.WriteLine("Create a batchable subscription"); await using AsyncDisposableValue <string> batchSubscriptionId = await CreateSubscriptionAsync( channel1Name, repo1Name, repo2Name, targetBranch, "everyWeek", "maestro-auth-test", additionalOptions : new List <string> { "--batchable" }); Subscription expectedBatchedSubscription = SubscriptionBuilder.BuildSubscription( repo1Uri, repo2Uri, targetBranch, channel1Name, batchSubscriptionId.Value, UpdateFrequency.EveryWeek, true); string expectedBatchedSubscriptionInfo = UxHelpers.GetTextSubscriptionDescription(expectedBatchedSubscription, null); await ValidateSubscriptionInfo(batchSubscriptionId.Value, expectedBatchedSubscriptionInfo); await DeleteSubscriptionById(batchSubscriptionId.Value); TestContext.WriteLine("Testing YAML for darc add-subscription"); string yamlDefinition = $@" Channel: {channel1Name} Source Repository URL: {repo1Uri} Target Repository URL: {repo2Uri} Target Branch: {targetBranch} Update Frequency: everyWeek Batchable: False Merge Policies: - Name: Standard "; await using AsyncDisposableValue <string> yamlSubscriptionId = await CreateSubscriptionAsync(yamlDefinition); Subscription expectedYamlSubscription = SubscriptionBuilder.BuildSubscription( repo1Uri, repo2Uri, targetBranch, channel1Name, yamlSubscriptionId.Value, UpdateFrequency.EveryWeek, false, new List <string> { MergePolicyConstants.StandardMergePolicyName }); string expectedYamlSubscriptionInfo = UxHelpers.GetTextSubscriptionDescription(expectedYamlSubscription, null); await ValidateSubscriptionInfo(yamlSubscriptionId.Value, expectedYamlSubscriptionInfo); await DeleteSubscriptionById(yamlSubscriptionId.Value); TestContext.WriteLine("Change casing of the various properties. Expecting no changes."); string yamlDefinition2 = $@" Channel: {channel1Name} Source Repository URL: {repo1Uri} Target Repository URL: {repo2Uri} Target Branch: {targetBranch} Update Frequency: everyweek Batchable: False Merge Policies: - Name: standard "; await using AsyncDisposableValue <string> yamlSubscription2Id = await CreateSubscriptionAsync(yamlDefinition2); Subscription expectedYamlSubscription2 = SubscriptionBuilder.BuildSubscription( repo1Uri, repo2Uri, targetBranch, channel1Name, yamlSubscription2Id.Value, UpdateFrequency.EveryWeek, false, new List <string> { MergePolicyConstants.StandardMergePolicyName }); string expectedYamlSubscriptionInfo2 = UxHelpers.GetTextSubscriptionDescription(expectedYamlSubscription2, null); await ValidateSubscriptionInfo(yamlSubscription2Id.Value, expectedYamlSubscriptionInfo2); await DeleteSubscriptionById(yamlSubscription2Id.Value); TestContext.WriteLine("Attempt to add multiple of the same merge policy checks. Should fail."); string yamlDefinition3 = $@" Channel: {channel1Name} Source Repository URL: {repo1Uri} Target Repository URL: {repo2Uri} Target Branch: {targetBranch} Update Frequency: everyweek Batchable: False Merge Policies: - Name: AllChecksSuccessful Properties: ignoreChecks: - WIP - license/cla - Name: AllChecksSuccessful Properties: ignoreChecks: - WIP - MySpecialCheck"; Assert.ThrowsAsync <MaestroTestException>(async() => await CreateSubscriptionAsync(yamlDefinition3), "Attempt to create a subscription with multiples of the same merge policy."); TestContext.WriteLine("Testing duplicate subscription handling..."); AsyncDisposableValue <string> yamlSubscription3Id = await CreateSubscriptionAsync(channel1Name, repo1Name, repo2Name, targetBranch, "everyWeek", "maestro-auth-test"); Assert.ThrowsAsync <MaestroTestException>(async() => await CreateSubscriptionAsync(channel1Name, repo1Name, repo2Name, targetBranch, "everyWeek", "maestro-auth-test"), "Attempt to create a subscription with the same values as an existing subscription."); Assert.ThrowsAsync <MaestroTestException>(async() => await CreateSubscriptionAsync(channel1Name, repo1Name, repo2Name, targetBranch, "everyweek", "maestro-auth-test"), "Attempt to create a subscription with the same values as an existing subscription (except for the casing of one parameter."); await DeleteSubscriptionById(yamlSubscription3Id.Value); TestContext.WriteLine("End of test case. Starting clean up."); } } }