public async Task RepoHookWithErrorIsSkipped() { using (var context = new ShipHubContext()) { var user = TestUtil.MakeTestUser(context); var repo = TestUtil.MakeTestRepo(context, user.Id); var hook = context.Hooks.Add(new Hook() { Id = 1001, Events = "event1,event2", GitHubId = null, // Empty GitHubId RepositoryId = repo.Id, Secret = Guid.NewGuid(), LastError = DateTimeOffset.UtcNow, }); await context.SaveChangesAsync(); var repoActor = CreateRepoActor(repo.Id, repo.FullName); var changes = await repoActor.AddOrUpdateWebhooks(null); var beforeError = hook.LastError; await context.Entry(hook).ReloadAsync(); Assert.IsTrue(hook.LastError == beforeError, "Recent LastError should be skipped."); Assert.IsEmpty(changes.Repositories, "skipped hook should not send changes."); } }
public async Task OrgHookWithErrorIsSkipped() { using (var context = new ShipHubContext()) { var user = TestUtil.MakeTestUser(context); var org = TestUtil.MakeTestOrg(context); context.OrganizationAccounts.Add(new OrganizationAccount() { UserId = user.Id, OrganizationId = org.Id, }); var hook = context.Hooks.Add(new Hook() { Id = 1001, Events = "event1,event2", GitHubId = null, // Empty GitHub Id OrganizationId = org.Id, Secret = Guid.NewGuid(), LastError = DateTimeOffset.UtcNow, }); await context.SaveChangesAsync(); var orgActor = CreateOrgActor(org.Id, org.Login); var changes = await orgActor.AddOrUpdateOrganizationWebhooks(context, null); var beforeError = hook.LastError; await context.Entry(hook).ReloadAsync(); Assert.IsTrue(hook.LastError == beforeError, "Recent LastError should be skipped."); Assert.IsEmpty(changes.Repositories, "skipped hook should not send changes."); } }
public async Task OrgHookSetLastErrorIfGitHubAddRequestFails() { using (var context = new ShipHubContext()) { var user = TestUtil.MakeTestUser(context); var org = TestUtil.MakeTestOrg(context); context.OrganizationAccounts.Add(new OrganizationAccount() { UserId = user.Id, OrganizationId = org.Id, }); await context.SaveChangesAsync(); var mock = new Mock <IGitHubActor>(); mock .Setup(x => x.OrganizationWebhooks(org.Login, null, It.IsAny <RequestPriority>())) .ReturnsAsync(new GitHubResponse <IEnumerable <Webhook> >(null) { Result = new List <Webhook>(), Status = HttpStatusCode.OK, }); mock .Setup(x => x.AddOrganizationWebhook(org.Login, It.IsAny <Webhook>(), It.IsAny <RequestPriority>())) .ThrowsAsync(new Exception("some exception!")); var orgActor = CreateOrgActor(org.Id, org.Login); var changes = await orgActor.AddOrUpdateOrganizationWebhooks(context, mock.Object); Assert.IsEmpty(changes.Repositories, "Failed hook creation should not send notifications."); var hook = context.Hooks.SingleOrDefault(x => x.OrganizationId == org.Id); Assert.IsNotNull(hook.LastError, "hook should have been marked as errored when we noticed the AddRepoHook failed"); } }
public async Task RepoHookSetLastErrorIfGitHubAddRequestFails() { using (var context = new ShipHubContext()) { var user = TestUtil.MakeTestUser(context); var repo = TestUtil.MakeTestRepo(context, user.Id); await context.SaveChangesAsync(); var mock = new Mock <IGitHubActor>(); mock .Setup(x => x.RepositoryWebhooks(repo.FullName, null, It.IsAny <RequestPriority>())) .ReturnsAsync(new GitHubResponse <IEnumerable <Webhook> >(null) { Result = new List <Webhook>(), Status = HttpStatusCode.OK, }); mock .Setup(x => x.AddRepositoryWebhook(repo.FullName, It.IsAny <Webhook>(), It.IsAny <RequestPriority>())) .ThrowsAsync(new Exception("some exception!")); var repoActor = CreateRepoActor(repo.Id, repo.FullName); var changes = await repoActor.AddOrUpdateWebhooks(mock.Object); Assert.IsEmpty(changes.Repositories, "Failed hook creation should not send notifications."); var hook = context.Hooks.SingleOrDefault(x => x.RepositoryId == repo.Id); Assert.IsNotNull(hook.LastError, "hook should have been marked as errored when we noticed the AddRepoHook failed"); } }
private async Task <bool> RepoShipNeedsWebhookHelpHelper(bool hasHook, bool isAdmin) { using (var context = new ShipHubContext()) { var userAccount = TestUtil.MakeTestUser(context); var orgAccount = new AccountTableType() { Id = 4001, Login = "******", Type = "org", }; var repo = new RepositoryTableType() { Id = 5001, AccountId = 4001, Name = "unicorns", FullName = "pureimaginary/unicorns", Private = true, HasIssues = true, }; await context.BulkUpdateAccounts(DateTimeOffset.UtcNow, new[] { orgAccount }); var user = context.Users.Single(x => x.Id == userAccount.Id); await context.SaveChangesAsync(); await context.BulkUpdateRepositories(DateTimeOffset.UtcNow, new[] { repo }); await context.SetUserOrganizations(user.Id, new[] { orgAccount.Id }); await context.SetAccountLinkedRepositories( userAccount.Id, new[] { (repo.Id, isAdmin) });
private static async Task <Environment> MakeEnvironment(ShipHubContext context) { var env = new Environment() { user1 = TestUtil.MakeTestUser(context, 3001, "alok"), user2 = TestUtil.MakeTestUser(context, 3002, "aroon"), org = TestUtil.MakeTestOrg(context, 6001, "pureimaginary") }; await context.SetUserOrganizations(env.user1.Id, new[] { env.org.Id }); await context.SaveChangesAsync(); return(env); }
public async Task OrgHookWithOldErrorIsRetried() { using (var context = new ShipHubContext()) { var user = TestUtil.MakeTestUser(context); var org = TestUtil.MakeTestOrg(context); var hook = context.Hooks.Add(new Hook() { Id = 1001, Events = "event1,event2", GitHubId = null, // Empty GitHub Id OrganizationId = org.Id, Secret = Guid.NewGuid(), LastError = DateTimeOffset.UtcNow.Subtract(OrganizationActor.HookErrorDelay), }); await context.SaveChangesAsync(); await context.SetUserOrganizations(user.Id, new[] { org.Id }); var mock = new Mock <IGitHubActor>(); mock .Setup(x => x.OrganizationWebhooks(org.Login, null, It.IsAny <RequestPriority>())) .ReturnsAsync(new GitHubResponse <IEnumerable <Webhook> >(null) { Result = new List <Webhook>() { }, Status = HttpStatusCode.OK, }); mock .Setup(x => x.AddOrganizationWebhook(org.Login, It.IsAny <Webhook>(), It.IsAny <RequestPriority>())) .ReturnsAsync(new GitHubResponse <Webhook>(null) { Result = new Webhook() { Id = 9999, }, Status = HttpStatusCode.OK, }); var orgActor = CreateOrgActor(org.Id, org.Login); var changes = await orgActor.AddOrUpdateOrganizationWebhooks(context, mock.Object); await context.Entry(hook).ReloadAsync(); Assert.AreEqual(9999, hook.GitHubId); Assert.IsNull(hook.LastError); Assert.IsTrue(changes.Organizations?.First() == org.Id, "New hook should send notifications."); } }
public async Task UsersCanBecomeOrgs() { using (var context = new ShipHubContext()) { var user1 = TestUtil.MakeTestUser(context, 3001, "user1"); var user2 = TestUtil.MakeTestUser(context, 3002, "user2"); var user3 = TestUtil.MakeTestUser(context, 3003, "user3"); var repo1 = TestUtil.MakeTestRepo(context, user1.Id, 2001, "unicorns1"); var repo2 = TestUtil.MakeTestRepo(context, user1.Id, 2002, "unicorns2"); var repo3 = TestUtil.MakeTestRepo(context, user2.Id, 2003, "unicorns3"); var repo4 = TestUtil.MakeTestRepo(context, user3.Id, 2004, "unicorns4"); var org1 = TestUtil.MakeTestOrg(context, 6001, "org1"); var org2 = TestUtil.MakeTestOrg(context, 6002, "org2"); await context.SaveChangesAsync(); await context.SetAccountLinkedRepositories(user1.Id, new[] {
public async Task RepoHookWithOldErrorIsRetried() { using (var context = new ShipHubContext()) { var user = TestUtil.MakeTestUser(context); var repo = TestUtil.MakeTestRepo(context, user.Id); var hook = context.Hooks.Add(new Hook() { Id = 1001, Events = "event1,event2", GitHubId = null, // Empty GitHubId RepositoryId = repo.Id, Secret = Guid.NewGuid(), LastError = DateTimeOffset.UtcNow.Subtract(RepositoryActor.HookErrorDelay), }); await context.SaveChangesAsync(); var mock = new Mock <IGitHubActor>(); mock .Setup(x => x.RepositoryWebhooks(repo.FullName, It.IsAny <GitHubCacheDetails>(), It.IsAny <RequestPriority>())) .ReturnsAsync(new GitHubResponse <IEnumerable <Webhook> >(null) { Result = new List <Webhook>(), Status = HttpStatusCode.OK, }); mock .Setup(x => x.AddRepositoryWebhook(repo.FullName, It.IsAny <Webhook>(), It.IsAny <RequestPriority>())) .ReturnsAsync(new GitHubResponse <Webhook>(null) { Result = new Webhook() { Id = 9999, }, Status = HttpStatusCode.OK, }); var repoActor = CreateRepoActor(repo.Id, repo.FullName); var changes = await repoActor.AddOrUpdateWebhooks(mock.Object); await context.Entry(hook).ReloadAsync(); Assert.AreEqual(9999, hook.GitHubId); Assert.IsNull(hook.LastError); Assert.IsTrue(changes.Repositories.First() == repo.Id, "New hook should send notifications."); } }
public async Task ModeIsPaidWithPersonalSubscription() { using (var context = new ShipHubContext()) { var env = await MakeEnvironment(context); context.Subscriptions.Add(new Subscription() { AccountId = env.user1.Id, State = SubscriptionState.Subscribed, }); await context.SaveChangesAsync(); var entry = await GetSubscriptionResponse(env.user1); Assert.AreEqual(SubscriptionMode.Paid, entry.Mode, "Mode is paid with a personal subscription."); } }
public async Task ModeIsPaidWithOrgSubscriptionEvenIfUserHasTrial() { using (var context = new ShipHubContext()) { var env = await MakeEnvironment(context); context.Subscriptions.Add(new Subscription() { AccountId = env.user1.Id, State = SubscriptionState.InTrial, }); context.Subscriptions.Add(new Subscription() { AccountId = env.org.Id, State = SubscriptionState.Subscribed, }); await context.SaveChangesAsync(); var entry = await GetSubscriptionResponse(env.user1); Assert.AreEqual(SubscriptionMode.Paid, entry.Mode, "A paid organization overrides a user's trial"); Assert.IsNull(entry.TrialEndDate, "should not be set if we're in paid mode"); } }
public async Task WillEditHookWhenEventListIsExcessiveForOrg() { using (var context = new ShipHubContext()) { var user = TestUtil.MakeTestUser(context); var org = TestUtil.MakeTestOrg(context); context.OrganizationAccounts.Add(new OrganizationAccount() { UserId = user.Id, OrganizationId = org.Id, }); var extraEvents = OrganizationActor.RequiredEvents.Add("extra"); var extraEventsString = string.Join(",", extraEvents); var hook = context.Hooks.Add(new Hook() { Id = 1001, Events = extraEventsString, GitHubId = 8001, OrganizationId = org.Id, Secret = Guid.NewGuid(), }); await context.SaveChangesAsync(); var mock = new Mock <IGitHubActor>(); mock .Setup(x => x.OrganizationWebhooks(org.Login, null, It.IsAny <RequestPriority>())) .ReturnsAsync(new GitHubResponse <IEnumerable <Webhook> >(null) { Result = new List <Webhook>() { new Webhook() { Id = 8001, Active = true, Config = new WebhookConfiguration() { ContentType = "json", InsecureSsl = false, Secret = "*******", Url = $"https://{Configuration.ApiHostName}/webhook/repo/1234", }, Events = extraEvents, Name = "web", }, }, Status = HttpStatusCode.OK, }); mock .Setup(x => x.EditOrganizationWebhookEvents(org.Login, (long)hook.GitHubId, It.IsAny <IEnumerable <string> >(), It.IsAny <RequestPriority>())) .Returns((string repoName, long hookId, IEnumerable <string> eventList, RequestPriority priority) => { var result = new GitHubResponse <Webhook>(null) { Result = new Webhook() { Id = 8001, Active = true, Config = new WebhookConfiguration() { ContentType = "json", InsecureSsl = false, Secret = "*******", Url = $"https://{Configuration.ApiHostName}/webhook/org/1234", }, Events = eventList, Name = "web", }, Status = HttpStatusCode.OK, }; return(Task.FromResult(result)); }); var orgActor = CreateOrgActor(org.Id, org.Login); await orgActor.AddOrUpdateOrganizationWebhooks(context, mock.Object); mock.Verify(x => x.EditOrganizationWebhookEvents(org.Login, (long)hook.GitHubId, OrganizationActor.RequiredEvents, It.IsAny <RequestPriority>())); context.Entry(hook).Reload(); Assert.AreEqual(OrganizationActor.RequiredEvents.ToArray(), hook.Events.Split(',')); } }
public async Task WillRemoveExistingHooksBeforeAddingOneForOrg() { using (var context = new ShipHubContext()) { var user = TestUtil.MakeTestUser(context); var org = TestUtil.MakeTestOrg(context); await context.SaveChangesAsync(); var mock = new Mock <IGitHubActor>(); mock .Setup(x => x.OrganizationWebhooks(org.Login, null, It.IsAny <RequestPriority>())) .ReturnsAsync(new GitHubResponse <IEnumerable <Webhook> >(null) { Status = HttpStatusCode.OK, Result = new List <Webhook>() { new Webhook() { Id = 8001, Active = true, Config = new WebhookConfiguration() { ContentType = "json", InsecureSsl = false, Secret = "*******", Url = $"https://{Configuration.ApiHostName}/webhook/org/1", }, Events = new string[] { }, Name = "web", }, new Webhook() { Id = 8002, Active = true, Config = new WebhookConfiguration() { ContentType = "json", InsecureSsl = false, Secret = "*******", Url = $"https://{Configuration.ApiHostName}/webhook/repo/2", }, Events = new string[] { }, Name = "web", }, }, }); var deletedHookIds = new List <long>(); mock .Setup(x => x.DeleteOrganizationWebhook(org.Login, It.IsAny <long>(), It.IsAny <RequestPriority>())) .ReturnsAsync(new GitHubResponse <bool>(null) { Result = true, Status = HttpStatusCode.OK, }) .Callback((string fullName, long hookId, RequestPriority priority) => { deletedHookIds.Add(hookId); }); mock .Setup(x => x.AddOrganizationWebhook(org.Login, It.IsAny <Webhook>(), It.IsAny <RequestPriority>())) .ReturnsAsync(new GitHubResponse <Webhook>(null) { Result = new Webhook() { Id = 9999, }, Status = HttpStatusCode.OK, }); var orgActor = CreateOrgActor(org.Id, org.Login); await orgActor.AddOrUpdateOrganizationWebhooks(context, mock.Object); var hook = context.Hooks.Single(x => x.OrganizationId == org.Id); Assert.AreEqual(new long[] { 8001, 8002 }, deletedHookIds.ToArray()); Assert.NotNull(hook); } }
public async Task WillAddHookWhenNoneExistsForOrg() { using (var context = new ShipHubContext()) { var user = TestUtil.MakeTestUser(context); var org = TestUtil.MakeTestOrg(context); await context.SaveChangesAsync(); await context.SetUserOrganizations(user.Id, new[] { org.Id }); var orgLogItem = context.SyncLogs.Single(x => x.OwnerType == "org" && x.OwnerId == org.Id && x.ItemType == "account" && x.ItemId == org.Id); var orgLogItemRowVersion = orgLogItem.RowVersion; var mock = new Mock <IGitHubActor>(); mock .Setup(x => x.OrganizationWebhooks(org.Login, null, It.IsAny <RequestPriority>())) .ReturnsAsync(new GitHubResponse <IEnumerable <Webhook> >(null) { Result = new List <Webhook>(), Status = HttpStatusCode.OK, }); Webhook installWebhook = null; mock .Setup(x => x.AddOrganizationWebhook(org.Login, It.IsAny <Webhook>(), It.IsAny <RequestPriority>())) .ReturnsAsync(new GitHubResponse <Webhook>(null) { Result = new Webhook() { Id = 9999, }, Status = HttpStatusCode.OK, }) .Callback((string login, Webhook webhook, RequestPriority priority) => { installWebhook = webhook; }); var orgActor = CreateOrgActor(org.Id, org.Login); var changes = await orgActor.AddOrUpdateOrganizationWebhooks(context, mock.Object); var hook = context.Hooks.Single(x => x.OrganizationId == org.Id); Assert.AreEqual(OrganizationActor.RequiredEvents, new HashSet <string>(hook.Events.Split(','))); Assert.AreEqual(org.Id, hook.OrganizationId); Assert.AreEqual(9999, hook.GitHubId); Assert.Null(hook.RepositoryId); Assert.Null(hook.LastSeen); Assert.NotNull(hook.Secret); Assert.AreEqual("web", installWebhook.Name); Assert.AreEqual(true, installWebhook.Active); Assert.AreEqual(OrganizationActor.RequiredEvents, new HashSet <string>(installWebhook.Events)); Assert.AreEqual("json", installWebhook.Config.ContentType); Assert.AreEqual(false, installWebhook.Config.InsecureSsl); Assert.AreEqual(hook.Secret.ToString(), installWebhook.Config.Secret); orgLogItem = context.SyncLogs.Single(x => x.OwnerType == "org" && x.OwnerId == org.Id && x.ItemType == "account" && x.ItemId == org.Id); Assert.Greater(orgLogItem.RowVersion, orgLogItemRowVersion, "row version should get bumped so the org gets synced"); Assert.AreEqual(new long[] { org.Id }, changes.Organizations.ToArray()); } }
public async Task WillEditHookWhenEventListIsNotCompleteForRepo() { using (var context = new ShipHubContext()) { var user = TestUtil.MakeTestUser(context); var repo = TestUtil.MakeTestRepo(context, user.Id); var hook = context.Hooks.Add(new Hook() { Id = 1001, Events = "event1,event2", GitHubId = 8001, RepositoryId = repo.Id, Secret = Guid.NewGuid(), }); await context.SaveChangesAsync(); var mock = new Mock <IGitHubActor>(); mock .Setup(x => x.RepositoryWebhooks(repo.FullName, null, It.IsAny <RequestPriority>())) .ReturnsAsync(new GitHubResponse <IEnumerable <Webhook> >(null) { Result = new List <Webhook>() { new Webhook() { Id = 8001, Active = true, Config = new WebhookConfiguration() { ContentType = "json", InsecureSsl = false, Secret = "*******", Url = $"https://{Configuration.ApiHostName}/webhook/repo/1234", }, Events = new string[] { "event1", "event2", }, Name = "web", }, }, }); mock .Setup(x => x.EditRepositoryWebhookEvents(repo.FullName, (long)hook.GitHubId, It.IsAny <IEnumerable <string> >(), It.IsAny <RequestPriority>())) .Returns((string repoName, long hookId, IEnumerable <string> eventList, RequestPriority priority) => { var result = new GitHubResponse <Webhook>(null) { Result = new Webhook() { Id = 8001, Active = true, Config = new WebhookConfiguration() { ContentType = "json", InsecureSsl = false, Secret = "*******", Url = $"https://{Configuration.ApiHostName}/webhook/repo/1234", }, Events = eventList, Name = "web", }, Status = HttpStatusCode.OK, }; return(Task.FromResult(result)); }); var repoActor = CreateRepoActor(repo.Id, repo.FullName); var changes = await repoActor.AddOrUpdateWebhooks(mock.Object); mock.Verify(x => x.EditRepositoryWebhookEvents(repo.FullName, (long)hook.GitHubId, RepositoryActor.RequiredEvents, It.IsAny <RequestPriority>())); context.Entry(hook).Reload(); Assert.IsTrue(RepositoryActor.RequiredEvents.SetEquals(hook.Events.Split(','))); Assert.IsFalse(changes.Repositories.Any()); } }
public async Task WillAddHookWhenNoneExistsForRepo() { using (var context = new ShipHubContext()) { var user = TestUtil.MakeTestUser(context); var repo = TestUtil.MakeTestRepo(context, user.Id); await context.SaveChangesAsync(); var repoLogItem = context.SyncLogs.Single(x => x.OwnerType == "repo" && x.OwnerId == repo.Id && x.ItemType == "repository" && x.ItemId == repo.Id); var repoLogItemRowVersion = repoLogItem.RowVersion; var mock = new Mock <IGitHubActor>(); mock .Setup(x => x.RepositoryWebhooks(repo.FullName, null, It.IsAny <RequestPriority>())) .ReturnsAsync(new GitHubResponse <IEnumerable <Webhook> >(null) { Result = new List <Webhook>(), Status = HttpStatusCode.OK, }); string installRepoName = null; Webhook installWebhook = null; mock .Setup(x => x.AddRepositoryWebhook(repo.FullName, It.IsAny <Webhook>(), It.IsAny <RequestPriority>())) .ReturnsAsync(new GitHubResponse <Webhook>(null) { Result = new Webhook() { Id = 9999, }, Status = HttpStatusCode.OK, }) .Callback((string fullName, Webhook webhook, RequestPriority priority) => { installRepoName = fullName; installWebhook = webhook; }); var repoActor = CreateRepoActor(repo.Id, repo.FullName); var changes = await repoActor.AddOrUpdateWebhooks(mock.Object); var hook = context.Hooks.Single(x => x.RepositoryId == repo.Id); Assert.IsTrue(RepositoryActor.RequiredEvents.SetEquals(hook.Events.Split(','))); Assert.AreEqual(repo.Id, hook.RepositoryId); Assert.AreEqual(9999, hook.GitHubId); Assert.Null(hook.OrganizationId); Assert.Null(hook.LastSeen); Assert.NotNull(hook.Secret); Assert.AreEqual(repo.FullName, installRepoName); Assert.AreEqual("web", installWebhook.Name); Assert.AreEqual(true, installWebhook.Active); Assert.IsTrue(RepositoryActor.RequiredEvents.SetEquals(installWebhook.Events)); Assert.AreEqual("json", installWebhook.Config.ContentType); Assert.AreEqual(false, installWebhook.Config.InsecureSsl); Assert.AreEqual(hook.Secret.ToString(), installWebhook.Config.Secret); repoLogItem = context.SyncLogs.Single(x => x.OwnerType == "repo" && x.OwnerId == repo.Id && x.ItemType == "repository" && x.ItemId == repo.Id); Assert.Greater(repoLogItem.RowVersion, repoLogItemRowVersion, "row version should get bumped so the repo gets synced"); Assert.AreEqual(new long[] { repo.Id }, changes.Repositories.ToArray()); } }