Skip to content

Commit 0e47134

Browse files
begedinjoshsmith
authored andcommitted
Switched other handlers to using ResultAggregator
Added tests to improve coverage
1 parent ed60a50 commit 0e47134

File tree

5 files changed

+108
-38
lines changed

5 files changed

+108
-38
lines changed
Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
defmodule CodeCorps.GitHub.Event.IssueComment.CommentSyncer do
22
alias CodeCorps.{
33
Comment,
4+
GitHub.Event.Common.ResultAggregator,
45
GitHub.Event.IssueComment.ChangesetBuilder,
56
Task,
67
User,
@@ -9,17 +10,19 @@ defmodule CodeCorps.GitHub.Event.IssueComment.CommentSyncer do
910

1011
alias Ecto.Changeset
1112

13+
@type outcome :: {:ok, list(Comment.t)} |
14+
{:error, {list(Comment.t), list(Changeset.t)}}
15+
1216
@doc """
1317
When provided a list of `Task`s, a `User` and a GitHub API payload, for each
1418
`Comment` associated to those `Task`s it creates or updates a `Comment`
1519
associated to the specified `User`.
1620
"""
17-
@spec sync_all(list(Task.t), User.t, map) :: {:ok, list(Comment.t)}
21+
@spec sync_all(list(Task.t), User.t, map) :: outcome
1822
def sync_all(tasks, %User{} = user, %{} = payload) do
1923
tasks
2024
|> Enum.map(&sync(&1, user, payload))
21-
|> collect()
22-
|> summarize()
25+
|> ResultAggregator.aggregate
2326
end
2427

2528
@spec sync(Task.t, User.t, map) :: {:ok, Comment.t} | {:error, Changeset.t}
@@ -41,18 +44,4 @@ defmodule CodeCorps.GitHub.Event.IssueComment.CommentSyncer do
4144
@spec commit(Changeset.t) :: {:ok, Comment.t} | {:error, Changeset.t}
4245
defp commit(%Changeset{data: %Comment{id: nil}} = changeset), do: changeset |> Repo.insert
4346
defp commit(%Changeset{} = changeset), do: changeset |> Repo.update
44-
45-
@spec collect(list, list, list) :: tuple
46-
defp collect(results, comments \\ [], errors \\ [])
47-
defp collect([{:ok, %Comment{} = comment} | tail], comments, errors) do
48-
collect(tail, comments ++ [comment], errors)
49-
end
50-
defp collect([{:error, %Changeset{} = changeset} | tail], comments, errors) do
51-
collect(tail, comments, errors ++ [changeset])
52-
end
53-
defp collect([], comments, errors), do: {comments, errors}
54-
55-
@spec summarize(tuple) :: tuple
56-
defp summarize({comments, []}), do: {:ok, comments}
57-
defp summarize({comments, errors}), do: {:error, {comments, errors}}
5847
end

lib/code_corps/github/event/issues/task_syncer.ex

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
defmodule CodeCorps.GitHub.Event.Issues.TaskSyncer do
22
alias CodeCorps.{
33
GithubRepo,
4+
GitHub.Event.Common.ResultAggregator,
45
GitHub.Event.Issues.ChangesetBuilder,
56
ProjectGithubRepo,
67
Task,
@@ -10,6 +11,9 @@ defmodule CodeCorps.GitHub.Event.Issues.TaskSyncer do
1011

1112
alias Ecto.Changeset
1213

14+
@type outcome :: {:ok, list(Task.t)} |
15+
{:error, {list(Task.t), list(Changeset.t)}}
16+
1317
@doc """
1418
When provided a `GithubRepo`, a `User` and a GitHub API payload, for each
1519
`Project` associated to that `GithubRepo` via a `ProjectGithubRepo`, it
@@ -19,8 +23,7 @@ defmodule CodeCorps.GitHub.Event.Issues.TaskSyncer do
1923
def sync_all(%GithubRepo{project_github_repos: project_github_repos}, %User{} = user, %{} = payload) do
2024
project_github_repos
2125
|> Enum.map(&sync(&1, user, payload))
22-
|> collect()
23-
|> summarize()
26+
|> ResultAggregator.aggregate
2427
end
2528

2629
@spec sync(ProjectGithubRepo.t, User.t, map) :: {:ok, ProjectGithubRepo.t} | {:error, Changeset.t}
@@ -51,18 +54,4 @@ defmodule CodeCorps.GitHub.Event.Issues.TaskSyncer do
5154
@spec commit(Changeset.t) :: {:ok, Task.t} | {:error, Changeset.t}
5255
defp commit(%Changeset{data: %Task{id: nil}} = changeset), do: changeset |> Repo.insert
5356
defp commit(%Changeset{} = changeset), do: changeset |> Repo.update
54-
55-
@spec collect(list, list, list) :: tuple
56-
defp collect(results, tasks \\ [], errors \\ [])
57-
defp collect([{:ok, %Task{} = task} | tail], tasks, errors) do
58-
collect(tail, tasks ++ [task], errors)
59-
end
60-
defp collect([{:error, %Changeset{} = changeset} | tail], tasks, errors) do
61-
collect(tail, tasks, errors ++ [changeset])
62-
end
63-
defp collect([], tasks, errors), do: {tasks, errors}
64-
65-
@spec summarize(tuple) :: tuple
66-
defp summarize({tasks, []}), do: {:ok, tasks}
67-
defp summarize({tasks, errors}), do: {:error, {tasks, errors}}
6857
end
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
defmodule CodeCorps.GitHub.Event.Common.ResultAggregatorTest do
2+
use CodeCorps.DbAccessCase
3+
4+
alias CodeCorps.{
5+
Comment,
6+
Task,
7+
GithubRepo,
8+
GitHub.Event.Common.ResultAggregator
9+
}
10+
11+
alias Ecto.Changeset
12+
13+
14+
describe "aggregate/1" do
15+
test "aggregates Task results correctly" do
16+
record = %Task{}
17+
good = {:ok, record}
18+
changeset = %Changeset{}
19+
bad = {:error, changeset}
20+
21+
assert [] |> ResultAggregator.aggregate == {:ok, []}
22+
assert [good] |> ResultAggregator.aggregate == {:ok, [record]}
23+
assert [good, good] |> ResultAggregator.aggregate == {:ok, [record, record]}
24+
assert [good, bad] |> ResultAggregator.aggregate == {:error, {[record], [changeset]}}
25+
assert [bad] |> ResultAggregator.aggregate == {:error, {[], [changeset]}}
26+
assert [bad, bad] |> ResultAggregator.aggregate == {:error, {[], [changeset, changeset]}}
27+
end
28+
29+
test "aggregates Comment results correctly" do
30+
record = %Comment{}
31+
good = {:ok, record}
32+
changeset = %Changeset{}
33+
bad = {:error, changeset}
34+
35+
assert [] |> ResultAggregator.aggregate == {:ok, []}
36+
assert [good] |> ResultAggregator.aggregate == {:ok, [record]}
37+
assert [good, good] |> ResultAggregator.aggregate == {:ok, [record, record]}
38+
assert [good, bad] |> ResultAggregator.aggregate == {:error, {[record], [changeset]}}
39+
assert [bad] |> ResultAggregator.aggregate == {:error, {[], [changeset]}}
40+
assert [bad, bad] |> ResultAggregator.aggregate == {:error, {[], [changeset, changeset]}}
41+
end
42+
43+
test "aggregates GithubRepo results correctly" do
44+
record = %GithubRepo{}
45+
good = {:ok, record}
46+
changeset = %Changeset{}
47+
bad = {:error, changeset}
48+
49+
assert [] |> ResultAggregator.aggregate == {:ok, []}
50+
assert [good] |> ResultAggregator.aggregate == {:ok, [record]}
51+
assert [good, good] |> ResultAggregator.aggregate == {:ok, [record, record]}
52+
assert [good, bad] |> ResultAggregator.aggregate == {:error, {[record], [changeset]}}
53+
assert [bad] |> ResultAggregator.aggregate == {:error, {[], [changeset]}}
54+
assert [bad, bad] |> ResultAggregator.aggregate == {:error, {[], [changeset, changeset]}}
55+
end
56+
end
57+
end

test/lib/code_corps/github/event/installation/repos_test.exs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,23 @@ defmodule CodeCorps.GitHub.Event.Installation.ReposTest do
1818
@installation_repositories load_endpoint_fixture("installation_repositories")
1919
@app_github_id 2
2020

21+
defmodule InvalidRepoRequest do
22+
def request(:get, "https://api.github.com/installation/repositories", _, _, _) do
23+
good_payload = "installation_repositories" |> load_endpoint_fixture
24+
%{"repositories" => [repo_1, repo_2]} = good_payload
25+
26+
bad_repo_1 = repo_1 |> Map.put("name", nil)
27+
28+
bad_payload =
29+
good_payload |> Map.put("repositories", [bad_repo_1, repo_2])
30+
31+
{:ok, bad_payload}
32+
end
33+
def request(method, endpoint, headers, body, options) do
34+
CodeCorps.GitHub.SuccessAPI.request(method, endpoint, headers, body, options)
35+
end
36+
end
37+
2138
describe "process/1" do
2239
test "syncs repos by performing a diff using payload as master list" do
2340
installation = insert(:github_app_installation, github_id: @app_github_id, state: "initiated_on_code_corps")
@@ -48,5 +65,19 @@ defmodule CodeCorps.GitHub.Event.Installation.ReposTest do
4865
# ensure no other repos have been created
4966
assert GithubRepo |> Repo.aggregate(:count, :id) == 2
5067
end
68+
69+
test "returned multi fails if there are repo validation erorrs" do
70+
installation = insert(:github_app_installation, github_id: @app_github_id, state: "initiated_on_code_corps")
71+
with_mock_api(InvalidRepoRequest) do
72+
{:error, :synced_repos, {repos, changesets}, _steps} =
73+
installation
74+
|> Repo.preload(:github_repos)
75+
|> Repos.process()
76+
|> Repo.transaction
77+
78+
assert repos |> Enum.count == 1
79+
assert changesets |> Enum.count == 1
80+
end
81+
end
5182
end
5283
end

test/lib/code_corps/github/event/installation_test.exs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,15 @@ defmodule CodeCorps.GitHub.Event.InstallationTest do
2424

2525
defmodule InvalidRepoRequest do
2626
def request(:get, "https://api.github.com/installation/repositories", _, _, _) do
27-
payload =
28-
"installation_repositories"
29-
|> load_endpoint_fixture
30-
|> Map.put("repositories", [%{}])
31-
{:ok, payload}
27+
good_payload = "installation_repositories" |> load_endpoint_fixture
28+
%{"repositories" => [repo_1, repo_2]} = good_payload
29+
30+
bad_repo_1 = repo_1 |> Map.put("name", nil)
31+
32+
bad_payload =
33+
good_payload |> Map.put("repositories", [bad_repo_1, repo_2])
34+
35+
{:ok, bad_payload}
3236
end
3337
def request(method, endpoint, headers, body, options) do
3438
CodeCorps.GitHub.SuccessAPI.request(method, endpoint, headers, body, options)

0 commit comments

Comments
 (0)