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