diff --git a/src/main/java/io/pakland/mdas/githubstats/application/GetRepositoriesByTeam.java b/src/main/java/io/pakland/mdas/githubstats/application/GetRepositoriesByTeam.java index 55ea5fbe..918e203f 100644 --- a/src/main/java/io/pakland/mdas/githubstats/application/GetRepositoriesByTeam.java +++ b/src/main/java/io/pakland/mdas/githubstats/application/GetRepositoriesByTeam.java @@ -14,7 +14,7 @@ public GetRepositoriesByTeam() {} @Transactional public List execute(Team team) { - return team.getRepositories(); + return team.getRepositories().stream().toList(); } } diff --git a/src/main/java/io/pakland/mdas/githubstats/application/GetTeamsFromOrganization.java b/src/main/java/io/pakland/mdas/githubstats/application/GetTeamsFromOrganization.java index 4f30d2bc..ba9d2a87 100644 --- a/src/main/java/io/pakland/mdas/githubstats/application/GetTeamsFromOrganization.java +++ b/src/main/java/io/pakland/mdas/githubstats/application/GetTeamsFromOrganization.java @@ -14,6 +14,6 @@ public GetTeamsFromOrganization() { } @Transactional public List execute(Organization org) { - return org.getTeams(); + return org.getTeams().stream().toList(); } } diff --git a/src/main/java/io/pakland/mdas/githubstats/domain/Organization.java b/src/main/java/io/pakland/mdas/githubstats/domain/Organization.java index 93e7fa2b..ab97921e 100644 --- a/src/main/java/io/pakland/mdas/githubstats/domain/Organization.java +++ b/src/main/java/io/pakland/mdas/githubstats/domain/Organization.java @@ -1,35 +1,67 @@ package io.pakland.mdas.githubstats.domain; -import javax.persistence.*; - import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.ToString; - -import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import lombok.*; @Data @NoArgsConstructor @AllArgsConstructor @Entity +@Builder @Table(name = "organization") public class Organization { - @Id - @Column(updatable = false, nullable = false) - @JsonProperty("id") - private Integer id; - - @Column - @JsonProperty("login") - private String login; - - @OneToMany( - mappedBy = "organization", - cascade = CascadeType.ALL, - orphanRemoval = true - ) - private List teams = new ArrayList<>(); + + @Id + @Column(updatable = false, nullable = false) + @JsonProperty("id") + @NotNull + private Integer id; + + @Column + @JsonProperty("login") + private String login; + + @OneToMany( + mappedBy = "organization", + cascade = CascadeType.ALL, + orphanRemoval = true + ) + private Set teams = new HashSet<>(); + + public void addTeam(Team team) { + if (teams == null) { + teams = new HashSet<>(); + } + + teams.add(team); + team.setOrganization(this); + } + + public List getTeams() { + return teams.stream().toList(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + Organization that = (Organization) o; + + return id.equals(that.id); + } + + @Override + public int hashCode() { + return id.hashCode(); + } } diff --git a/src/main/java/io/pakland/mdas/githubstats/domain/Repository.java b/src/main/java/io/pakland/mdas/githubstats/domain/Repository.java index 864fe7b8..df62c450 100644 --- a/src/main/java/io/pakland/mdas/githubstats/domain/Repository.java +++ b/src/main/java/io/pakland/mdas/githubstats/domain/Repository.java @@ -17,6 +17,7 @@ @NoArgsConstructor @AllArgsConstructor @Entity +@Builder @Table(name = "repository") public class Repository { @@ -47,4 +48,23 @@ public class Repository { private void unpackNameFromNestedObject(Map owner) { this.ownerLogin = owner.get("login"); } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + Repository that = (Repository) o; + + return id.equals(that.id); + } + + @Override + public int hashCode() { + return id.hashCode(); + } } diff --git a/src/main/java/io/pakland/mdas/githubstats/domain/Team.java b/src/main/java/io/pakland/mdas/githubstats/domain/Team.java index 704abbf2..aa3fae29 100644 --- a/src/main/java/io/pakland/mdas/githubstats/domain/Team.java +++ b/src/main/java/io/pakland/mdas/githubstats/domain/Team.java @@ -1,44 +1,73 @@ package io.pakland.mdas.githubstats.domain; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - +import java.util.*; import javax.persistence.*; -import java.util.ArrayList; -import java.util.List; +import lombok.*; @Data @NoArgsConstructor @AllArgsConstructor @Entity +@Builder @Table(name = "team") public class Team { - @Id - @Column(updatable = false, nullable = false) - @JsonProperty("id") - private Integer id; - - @Column(name = "slug") - @JsonProperty("slug") - private String slug; - - @ManyToOne(fetch = FetchType.LAZY) - private Organization organization; - - @OneToMany( - mappedBy = "team", - cascade = CascadeType.ALL, - orphanRemoval = true - ) - private List users = new ArrayList<>(); - - @OneToMany( - mappedBy = "team", - cascade = CascadeType.ALL, - orphanRemoval = true - ) - private List repositories = new ArrayList<>(); + @Id + @Column(updatable = false, nullable = false) + @JsonProperty("id") + private Integer id; + + @Column(name = "slug") + @JsonProperty("slug") + private String slug; + + @ManyToOne(fetch = FetchType.LAZY) + private Organization organization; + + @OneToMany( + mappedBy = "team", + cascade = CascadeType.ALL, + orphanRemoval = true + ) + private List users = new ArrayList<>(); + + @OneToMany( + mappedBy = "team", + cascade = CascadeType.ALL, + orphanRemoval = true + ) + private Set repositories = new HashSet<>(); + + public void addRepository(Repository repository) { + if (repositories == null) { + repositories = new HashSet<>(); + } + + repositories.add(repository); + repository.setTeam(this); + } + + public List getRepositories() { + return repositories.stream().toList(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + Team team = (Team) o; + + return id.equals(team.id); + } + + @Override + public int hashCode() { + return id.hashCode(); + } } diff --git a/src/main/java/io/pakland/mdas/githubstats/infrastructure/shell/controller/UserOptionController.java b/src/main/java/io/pakland/mdas/githubstats/infrastructure/shell/controller/UserOptionController.java index 126e0879..7213d2a7 100644 --- a/src/main/java/io/pakland/mdas/githubstats/infrastructure/shell/controller/UserOptionController.java +++ b/src/main/java/io/pakland/mdas/githubstats/infrastructure/shell/controller/UserOptionController.java @@ -52,8 +52,8 @@ public void execute() { .execute(organization.getLogin()); for (Team team : teamList) { + organization.addTeam(team); // Fetch the members of each team. - logger.info(organization.getLogin()); List userList = new FetchUsersFromTeam(userExternalRepository) .execute(organization.getLogin(), team.getSlug()); // Fetch the repositories for each team. @@ -64,6 +64,7 @@ public void execute() { repositoryList.forEach(r -> r.setTeam(team)); for (Repository repository : repositoryList) { + team.addRepository(repository); // Fetch pull requests from each team. List pullRequestList = new FetchPullRequestsFromRepository( pullRequestExternalRepository) @@ -83,10 +84,7 @@ public void execute() { } team.setUsers(userList); - team.setRepositories(repositoryList); } - - organization.setTeams(teamList); } } catch (HttpException e) { throw new RuntimeException(e); diff --git a/src/test/java/io/pakland/mdas/githubstats/domain/OrganizationTest.java b/src/test/java/io/pakland/mdas/githubstats/domain/OrganizationTest.java new file mode 100644 index 00000000..a4b0c118 --- /dev/null +++ b/src/test/java/io/pakland/mdas/githubstats/domain/OrganizationTest.java @@ -0,0 +1,49 @@ +package io.pakland.mdas.githubstats.domain; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.util.Collections; +import java.util.HashSet; +import org.junit.jupiter.api.Test; + +public class OrganizationTest { + + @Test + public void shouldAddTheTeamToTheOrganization_andSetTheTeamOrganization() { + Organization organization = Organization.builder().id(1).login("github-stats").build(); + Team team = Team.builder().id(1).slug("gs-developers").build(); + + assertNull(team.getOrganization()); + organization.addTeam(team); + + assertEquals(organization.getTeams().size(), 1); + assertEquals(team.getOrganization(), organization); + } + + @Test + public void shouldNotAddTheTeam_whenTheTeamIsAlreadyContained() { + Organization organization = Organization.builder().id(1).login("github-stats").build(); + Team team = Team.builder().id(1).slug("gs-developers").build(); + organization.setTeams(new HashSet<>(Collections.singletonList(team))); + + assertNull(team.getOrganization()); + assertEquals(organization.getTeams().size(), 1); + organization.addTeam(team); + + assertEquals(organization.getTeams().size(), 1); + assertEquals(team.getOrganization(), organization); + } + + @Test + public void shouldCheckForEqualOrganizations() { + Organization original = Organization.builder().id(1).build(); + Organization equal = Organization.builder().id(1).build(); + Organization notEqual = Organization.builder().id(2).build(); + + assertEquals(original, equal); + assertNotEquals(original, notEqual); + } + +} diff --git a/src/test/java/io/pakland/mdas/githubstats/domain/TeamTest.java b/src/test/java/io/pakland/mdas/githubstats/domain/TeamTest.java new file mode 100644 index 00000000..f96221d5 --- /dev/null +++ b/src/test/java/io/pakland/mdas/githubstats/domain/TeamTest.java @@ -0,0 +1,49 @@ +package io.pakland.mdas.githubstats.domain; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.util.Collections; +import java.util.HashSet; +import org.junit.jupiter.api.Test; + +public class TeamTest { + + @Test + public void shouldAddTheRepository_andAssignTheTeamToTheRepository() { + Team team = Team.builder().id(1).slug("gs-developers").build(); + Repository repository = Repository.builder().id(1).name("github-stats").build(); + + assertNull(repository.getTeam()); + team.addRepository(repository); + + assertEquals(repository.getTeam(), team); + assertEquals(1, team.getRepositories().size()); + } + + @Test + public void shouldNotAddTheRepository_whenTheRepositoryIsAlreadyContained() { + Team team = Team.builder().id(1).slug("gs-developers").build(); + Repository repository = Repository.builder().id(1).name("github-stats").build(); + team.setRepositories(new HashSet<>(Collections.singletonList(repository))); + + assertNull(repository.getTeam()); + assertEquals(1, team.getRepositories().size()); + team.addRepository(repository); + + assertEquals(repository.getTeam(), team); + assertEquals(1, team.getRepositories().size()); + } + + @Test + public void shouldCheckForEqualTeams() { + Team original = Team.builder().id(1).build(); + Team equal = Team.builder().id(1).build(); + Team notEqual = Team.builder().id(2).build(); + + assertEquals(original, equal); + assertNotEquals(original, notEqual); + } + +} diff --git a/src/test/java/io/pakland/mdas/githubstats/infrastructure/github/repository/OrganizationGitHubRepositoryTest.java b/src/test/java/io/pakland/mdas/githubstats/infrastructure/github/repository/OrganizationGitHubRepositoryTest.java index d3f31794..c21f3ae8 100644 --- a/src/test/java/io/pakland/mdas/githubstats/infrastructure/github/repository/OrganizationGitHubRepositoryTest.java +++ b/src/test/java/io/pakland/mdas/githubstats/infrastructure/github/repository/OrganizationGitHubRepositoryTest.java @@ -1,44 +1,41 @@ package io.pakland.mdas.githubstats.infrastructure.github.repository; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + import io.pakland.mdas.githubstats.application.exceptions.HttpException; import io.pakland.mdas.githubstats.domain.Organization; -import io.pakland.mdas.githubstats.domain.Team; -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; -import okhttp3.mockwebserver.RecordedRequest; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; - import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import okhttp3.mockwebserver.RecordedRequest; +import org.junit.jupiter.api.*; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; @TestInstance(TestInstance.Lifecycle.PER_CLASS) class OrganizationGitHubRepositoryTest { + private final Integer organizationId = 119930124; private MockWebServer mockWebServer; private OrganizationGitHubRepository organizationGithubRepository; private String availableOrganizationsListResponse; - private final Integer organizationId = 119930124; - private final Integer teamId = 7098104; - @BeforeAll void setup() throws IOException { this.mockWebServer = new MockWebServer(); this.mockWebServer.start(); - WebClientConfiguration webClientConfiguration = new WebClientConfiguration(mockWebServer.url("/").toString(), "test-api-key"); - this.organizationGithubRepository = new OrganizationGitHubRepository(webClientConfiguration); - this.availableOrganizationsListResponse = new String(Files.readAllBytes(Paths.get("src/test/java/io/pakland/mdas/githubstats/infrastructure/github/repository/responses/AvailableOrganizations.json"))); + WebClientConfiguration webClientConfiguration = new WebClientConfiguration( + mockWebServer.url("/").toString(), "test-api-key"); + this.organizationGithubRepository = new OrganizationGitHubRepository( + webClientConfiguration); + this.availableOrganizationsListResponse = new String(Files.readAllBytes(Paths.get( + "src/test/java/io/pakland/mdas/githubstats/infrastructure/github/repository/responses/AvailableOrganizations.json"))); } @AfterAll @@ -47,10 +44,11 @@ void shutDown() throws IOException { } @Test - void givenValidUserOrganizationsRequest_shouldCallUserOrganizationsEndpoint() throws InterruptedException, HttpException { + void givenValidUserOrganizationsRequest_shouldCallUserOrganizationsEndpoint() + throws InterruptedException, HttpException { MockResponse mockResponse = new MockResponse() - .setBody(this.availableOrganizationsListResponse) - .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); + .setBody(this.availableOrganizationsListResponse) + .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); mockWebServer.enqueue(mockResponse); organizationGithubRepository.fetchAvailableOrganizations(); @@ -63,13 +61,13 @@ void givenValidUserOrganizationsRequest_shouldCallUserOrganizationsEndpoint() th void givenValidGithubAPIKey_shouldReturnAPIKeyUserOrganizations() throws HttpException { MockResponse mockResponse = new MockResponse() - .setBody(this.availableOrganizationsListResponse) - .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); + .setBody(this.availableOrganizationsListResponse) + .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); mockWebServer.enqueue(mockResponse); List response = organizationGithubRepository.fetchAvailableOrganizations(); List expected = new ArrayList<>(); - expected.add(new Organization(this.organizationId, "github-stats-22", new ArrayList())); + expected.add(new Organization(this.organizationId, "github-stats-22", new HashSet<>())); assertArrayEquals(response.toArray(), expected.toArray()); } diff --git a/src/test/java/io/pakland/mdas/githubstats/infrastructure/github/repository/TeamGitHubRepositoryTest.java b/src/test/java/io/pakland/mdas/githubstats/infrastructure/github/repository/TeamGitHubRepositoryTest.java index 2ede345f..983bb39b 100644 --- a/src/test/java/io/pakland/mdas/githubstats/infrastructure/github/repository/TeamGitHubRepositoryTest.java +++ b/src/test/java/io/pakland/mdas/githubstats/infrastructure/github/repository/TeamGitHubRepositoryTest.java @@ -1,44 +1,41 @@ package io.pakland.mdas.githubstats.infrastructure.github.repository; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + import io.pakland.mdas.githubstats.application.exceptions.HttpException; -import io.pakland.mdas.githubstats.domain.Repository; import io.pakland.mdas.githubstats.domain.Team; -import io.pakland.mdas.githubstats.domain.User; -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; -import okhttp3.mockwebserver.RecordedRequest; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; - import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import okhttp3.mockwebserver.RecordedRequest; +import org.junit.jupiter.api.*; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; @TestInstance(TestInstance.Lifecycle.PER_CLASS) class TeamGitHubRepositoryTest { - private MockWebServer mockWebServer; - private TeamGitHubRepository teamGitHubRepository; - private String organizationTeamsListResponse; private final String organizationName = "github-stats-22"; private final String teamName = "gs-developers"; + private MockWebServer mockWebServer; + private TeamGitHubRepository teamGitHubRepository; + private String organizationTeamsListResponse; @BeforeAll void setup() throws IOException { this.mockWebServer = new MockWebServer(); this.mockWebServer.start(); - WebClientConfiguration webClientConfiguration = new WebClientConfiguration(mockWebServer.url("/").toString(), "test-api-key"); + WebClientConfiguration webClientConfiguration = new WebClientConfiguration( + mockWebServer.url("/").toString(), "test-api-key"); this.teamGitHubRepository = new TeamGitHubRepository(webClientConfiguration); - this.organizationTeamsListResponse = new String(Files.readAllBytes(Paths.get("src/test/java/io/pakland/mdas/githubstats/infrastructure/github/repository/responses/OrganizationTeams.json"))); + this.organizationTeamsListResponse = new String(Files.readAllBytes(Paths.get( + "src/test/java/io/pakland/mdas/githubstats/infrastructure/github/repository/responses/OrganizationTeams.json"))); } @AfterAll @@ -47,10 +44,11 @@ void shutDown() throws IOException { } @Test - void givenValidTeamMembersRequest_shouldCallTeamMembersEndpoint() throws InterruptedException, HttpException { + void givenValidTeamMembersRequest_shouldCallTeamMembersEndpoint() + throws InterruptedException, HttpException { MockResponse mockResponse = new MockResponse() - .setBody(this.organizationTeamsListResponse) - .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); + .setBody(this.organizationTeamsListResponse) + .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); mockWebServer.enqueue(mockResponse); teamGitHubRepository.fetchTeamsFromOrganization(this.organizationName); @@ -62,13 +60,15 @@ void givenValidTeamMembersRequest_shouldCallTeamMembersEndpoint() throws Interru @Test void givenValidTeamName_shouldReturnTeamMembers() throws HttpException { MockResponse mockResponse = new MockResponse() - .setBody(this.organizationTeamsListResponse) - .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); + .setBody(this.organizationTeamsListResponse) + .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); mockWebServer.enqueue(mockResponse); - List response = teamGitHubRepository.fetchTeamsFromOrganization(this.organizationName); + List response = teamGitHubRepository.fetchTeamsFromOrganization( + this.organizationName); List expected = new ArrayList<>(); - expected.add(0, new Team(7098104, "gs-developers", null, new ArrayList(), new ArrayList())); + expected.add(0, + new Team(7098104, teamName, null, new ArrayList<>(), new HashSet<>())); assertEquals(1, response.size()); assertArrayEquals(response.toArray(), expected.toArray());