From fe229befba232b12fd62522fffb50ebab41114ac Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Wed, 7 Feb 2024 15:46:45 +0300 Subject: [PATCH 01/29] Resolved #11 --- .../db/changelog/2024/002-tickets.sql | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/main/resources/db/changelog/2024/002-tickets.sql diff --git a/src/main/resources/db/changelog/2024/002-tickets.sql b/src/main/resources/db/changelog/2024/002-tickets.sql new file mode 100644 index 0000000..022fff9 --- /dev/null +++ b/src/main/resources/db/changelog/2024/002-tickets.sql @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +--liquibase formatted sql + +--changeset hizmailovich:1 +CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; + +--changeset hizmailovich:2 +CREATE SCHEMA IF NOT EXISTS projects; + +--changeset hizmailovich:3 +CREATE TABLE IF NOT EXISTS projects.tickets +( + id uuid DEFAULT uuid_generate_v4() PRIMARY KEY, + project uuid NOT NULL REFERENCES projects.projects, + number BIGINT NOT NULL, + repo CHARACTER VARYING(64) NOT NULL, + job CHARACTER VARYING(64) NOT NULL, + status CHARACTER VARYING(16) NOT NULL +); \ No newline at end of file From c2aeb9d1ff37e497d6c282ce615981de8c4a1fd2 Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Wed, 7 Feb 2024 17:40:46 +0300 Subject: [PATCH 02/29] Tickets implemented --- .../tracehub/pmo/ticket/DefaultTickets.java | 103 ++++++++++++++++++ .../java/git/tracehub/pmo/ticket/Ticket.java | 82 ++++++++++++++ .../git/tracehub/pmo/ticket/TicketOf.java | 52 +++++++++ .../java/git/tracehub/pmo/ticket/Tickets.java | 53 +++++++++ .../git/tracehub/pmo/ticket/package-info.java | 23 ++++ src/main/resources/sql/insert-ticket.sql | 29 +++++ .../sql/select-ticket-by-job-and-repo.sql | 25 +++++ .../sql/select-ticket-by-number-and-repo.sql | 25 +++++ 8 files changed, 392 insertions(+) create mode 100644 src/main/java/git/tracehub/pmo/ticket/DefaultTickets.java create mode 100644 src/main/java/git/tracehub/pmo/ticket/Ticket.java create mode 100644 src/main/java/git/tracehub/pmo/ticket/TicketOf.java create mode 100644 src/main/java/git/tracehub/pmo/ticket/Tickets.java create mode 100644 src/main/java/git/tracehub/pmo/ticket/package-info.java create mode 100644 src/main/resources/sql/insert-ticket.sql create mode 100644 src/main/resources/sql/select-ticket-by-job-and-repo.sql create mode 100644 src/main/resources/sql/select-ticket-by-number-and-repo.sql diff --git a/src/main/java/git/tracehub/pmo/ticket/DefaultTickets.java b/src/main/java/git/tracehub/pmo/ticket/DefaultTickets.java new file mode 100644 index 0000000..7629785 --- /dev/null +++ b/src/main/java/git/tracehub/pmo/ticket/DefaultTickets.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package git.tracehub.pmo.ticket; + +import com.jcabi.jdbc.JdbcSession; +import git.tracehub.pmo.exception.ResourceNotFoundException; +import git.tracehub.pmo.project.SqlStatement; +import javax.sql.DataSource; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import org.springframework.stereotype.Component; + +/** + * Default tickets. + * + * @since 0.0.0 + */ +@Component +@RequiredArgsConstructor +public class DefaultTickets implements Tickets { + + /** + * Datasource. + */ + private final DataSource source; + + @Override + @SneakyThrows + public Ticket byJob(final String job, final String repo) { + return new JdbcSession(this.source) + .sql( + new SqlStatement("select-ticket-by-job-and-repo.sql").asString() + ).set(job) + .set(repo) + .select( + (rs, stmt) -> { + if (!rs.next()) { + throw new ResourceNotFoundException( + "Ticket with job = %s and repo = %s not found" + .formatted(job, repo) + ); + } + return new TicketOf(rs).value(); + } + ); + } + + @Override + @SneakyThrows + public Ticket byNumber(final Long number, final String repo) { + return new JdbcSession(this.source) + .sql( + new SqlStatement("select-ticket-by-job-and-repo.sql").asString() + ).set(number) + .set(repo) + .select( + (rs, stmt) -> { + if (!rs.next()) { + throw new ResourceNotFoundException( + "Ticket with issue = %s and repo = %s not found" + .formatted(number, repo) + ); + } + return new TicketOf(rs).value(); + } + ); + } + + @Override + @SneakyThrows + public Ticket create(final Ticket ticket) { + return new JdbcSession(this.source) + .sql( + new SqlStatement("insert-ticket.sql").asString() + ).set(ticket.getProject()) + .set(ticket.getNumber()) + .set(ticket.getRepo()) + .set(ticket.getJob()) + .set(ticket.getStatus().name()) + .update( + (rs, stmt) -> { + rs.next(); + return new TicketOf(rs).value(); + } + ); + } + +} diff --git a/src/main/java/git/tracehub/pmo/ticket/Ticket.java b/src/main/java/git/tracehub/pmo/ticket/Ticket.java new file mode 100644 index 0000000..44b1a58 --- /dev/null +++ b/src/main/java/git/tracehub/pmo/ticket/Ticket.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package git.tracehub.pmo.ticket; + +import java.util.UUID; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Ticket. + * + * @since 0.0.0 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Ticket { + + /** + * Id. + */ + private UUID id; + + /** + * Project id. + */ + private UUID project; + + /** + * Issue number. + */ + private Long number; + + /** + * Repository. + */ + private String repo; + + /** + * Job. + */ + private String job; + + /** + * Status. + */ + private Status status; + + /** + * Status of the ticket. + */ + public enum Status { + + /** + * Opened. + */ + OPENED, + + /** + * Closed. + */ + CLOSED + + } + +} diff --git a/src/main/java/git/tracehub/pmo/ticket/TicketOf.java b/src/main/java/git/tracehub/pmo/ticket/TicketOf.java new file mode 100644 index 0000000..647bd1b --- /dev/null +++ b/src/main/java/git/tracehub/pmo/ticket/TicketOf.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package git.tracehub.pmo.ticket; + +import java.sql.ResultSet; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import org.cactoos.Scalar; + +/** + * Ticket from result set. + * + * @since 0.0.0 + */ +@RequiredArgsConstructor +public final class TicketOf implements Scalar { + + /** + * Result set. + */ + private final ResultSet set; + + @Override + @SneakyThrows + public Ticket value() { + return new Ticket( + UUID.fromString(this.set.getString("id")), + UUID.fromString(this.set.getString("project")), + this.set.getLong("number"), + this.set.getString("repo"), + this.set.getString("job"), + Ticket.Status.valueOf(this.set.getString("status")) + ); + } + +} diff --git a/src/main/java/git/tracehub/pmo/ticket/Tickets.java b/src/main/java/git/tracehub/pmo/ticket/Tickets.java new file mode 100644 index 0000000..a1a59de --- /dev/null +++ b/src/main/java/git/tracehub/pmo/ticket/Tickets.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package git.tracehub.pmo.ticket; + +/** + * Tickets. + * + * @since 0.0.0 + */ +public interface Tickets { + + /** + * Ticket by job and repository. + * + * @param job Job path + * @param repo Repository name + * @return Ticket + */ + Ticket byJob(String job, String repo); + + /** + * Ticket by number and repository. + * + * @param number Issue number + * @param repo Repository name + * @return Ticket + */ + Ticket byNumber(Long number, String repo); + + /** + * Create ticket. + * + * @param ticket Ticket + * @return Ticket + */ + Ticket create(Ticket ticket); + +} diff --git a/src/main/java/git/tracehub/pmo/ticket/package-info.java b/src/main/java/git/tracehub/pmo/ticket/package-info.java new file mode 100644 index 0000000..0b24f88 --- /dev/null +++ b/src/main/java/git/tracehub/pmo/ticket/package-info.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * Tickets. + * + * @since 0.0.0 + */ +package git.tracehub.pmo.ticket; diff --git a/src/main/resources/sql/insert-ticket.sql b/src/main/resources/sql/insert-ticket.sql new file mode 100644 index 0000000..186a9ab --- /dev/null +++ b/src/main/resources/sql/insert-ticket.sql @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +INSERT INTO projects.tickets (project, + number, + repo, + job, + status) +VALUES (?, ?, ?, ?, ?) +RETURNING id, + project, + number, + repo, + job, + status; \ No newline at end of file diff --git a/src/main/resources/sql/select-ticket-by-job-and-repo.sql b/src/main/resources/sql/select-ticket-by-job-and-repo.sql new file mode 100644 index 0000000..6b0502c --- /dev/null +++ b/src/main/resources/sql/select-ticket-by-job-and-repo.sql @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +SELECT id, + project, + number, + repo, + job, + status +FROM projects.tickets +WHERE job = ? AND repo = ?''; diff --git a/src/main/resources/sql/select-ticket-by-number-and-repo.sql b/src/main/resources/sql/select-ticket-by-number-and-repo.sql new file mode 100644 index 0000000..47afe50 --- /dev/null +++ b/src/main/resources/sql/select-ticket-by-number-and-repo.sql @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +SELECT id, + project, + number, + repo, + job, + status +FROM projects.tickets +WHERE number = ? AND repo = ?''; From b05dc414f95f654087b7ea7ee6cde67fb1a2b385 Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Wed, 7 Feb 2024 19:18:31 +0300 Subject: [PATCH 03/29] Fixed script --- src/main/resources/db/changelog/2024/002-tickets.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/db/changelog/2024/002-tickets.sql b/src/main/resources/db/changelog/2024/002-tickets.sql index 022fff9..6a115a5 100644 --- a/src/main/resources/db/changelog/2024/002-tickets.sql +++ b/src/main/resources/db/changelog/2024/002-tickets.sql @@ -28,7 +28,7 @@ CREATE TABLE IF NOT EXISTS projects.tickets ( id uuid DEFAULT uuid_generate_v4() PRIMARY KEY, project uuid NOT NULL REFERENCES projects.projects, - number BIGINT NOT NULL, + number int NOT NULL, repo CHARACTER VARYING(64) NOT NULL, job CHARACTER VARYING(64) NOT NULL, status CHARACTER VARYING(16) NOT NULL From e8799c6c0c548d9f3257ffc0322b89400cb3fb2b Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Wed, 7 Feb 2024 19:20:08 +0300 Subject: [PATCH 04/29] Tickets fixed --- src/main/java/git/tracehub/pmo/ticket/DefaultTickets.java | 2 +- src/main/java/git/tracehub/pmo/ticket/Ticket.java | 2 +- src/main/java/git/tracehub/pmo/ticket/TicketOf.java | 2 +- src/main/java/git/tracehub/pmo/ticket/Tickets.java | 2 +- src/main/resources/sql/select-ticket-by-job-and-repo.sql | 2 +- src/main/resources/sql/select-ticket-by-number-and-repo.sql | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/git/tracehub/pmo/ticket/DefaultTickets.java b/src/main/java/git/tracehub/pmo/ticket/DefaultTickets.java index 7629785..416c509 100644 --- a/src/main/java/git/tracehub/pmo/ticket/DefaultTickets.java +++ b/src/main/java/git/tracehub/pmo/ticket/DefaultTickets.java @@ -62,7 +62,7 @@ public Ticket byJob(final String job, final String repo) { @Override @SneakyThrows - public Ticket byNumber(final Long number, final String repo) { + public Ticket byNumber(final int number, final String repo) { return new JdbcSession(this.source) .sql( new SqlStatement("select-ticket-by-job-and-repo.sql").asString() diff --git a/src/main/java/git/tracehub/pmo/ticket/Ticket.java b/src/main/java/git/tracehub/pmo/ticket/Ticket.java index 44b1a58..7f61753 100644 --- a/src/main/java/git/tracehub/pmo/ticket/Ticket.java +++ b/src/main/java/git/tracehub/pmo/ticket/Ticket.java @@ -45,7 +45,7 @@ public class Ticket { /** * Issue number. */ - private Long number; + private int number; /** * Repository. diff --git a/src/main/java/git/tracehub/pmo/ticket/TicketOf.java b/src/main/java/git/tracehub/pmo/ticket/TicketOf.java index 647bd1b..79d20cd 100644 --- a/src/main/java/git/tracehub/pmo/ticket/TicketOf.java +++ b/src/main/java/git/tracehub/pmo/ticket/TicketOf.java @@ -42,7 +42,7 @@ public Ticket value() { return new Ticket( UUID.fromString(this.set.getString("id")), UUID.fromString(this.set.getString("project")), - this.set.getLong("number"), + this.set.getInt("number"), this.set.getString("repo"), this.set.getString("job"), Ticket.Status.valueOf(this.set.getString("status")) diff --git a/src/main/java/git/tracehub/pmo/ticket/Tickets.java b/src/main/java/git/tracehub/pmo/ticket/Tickets.java index a1a59de..15a13bc 100644 --- a/src/main/java/git/tracehub/pmo/ticket/Tickets.java +++ b/src/main/java/git/tracehub/pmo/ticket/Tickets.java @@ -40,7 +40,7 @@ public interface Tickets { * @param repo Repository name * @return Ticket */ - Ticket byNumber(Long number, String repo); + Ticket byNumber(int number, String repo); /** * Create ticket. diff --git a/src/main/resources/sql/select-ticket-by-job-and-repo.sql b/src/main/resources/sql/select-ticket-by-job-and-repo.sql index 6b0502c..f567fcd 100644 --- a/src/main/resources/sql/select-ticket-by-job-and-repo.sql +++ b/src/main/resources/sql/select-ticket-by-job-and-repo.sql @@ -22,4 +22,4 @@ SELECT id, job, status FROM projects.tickets -WHERE job = ? AND repo = ?''; +WHERE job = ? AND repo = ?; diff --git a/src/main/resources/sql/select-ticket-by-number-and-repo.sql b/src/main/resources/sql/select-ticket-by-number-and-repo.sql index 47afe50..7fc93fa 100644 --- a/src/main/resources/sql/select-ticket-by-number-and-repo.sql +++ b/src/main/resources/sql/select-ticket-by-number-and-repo.sql @@ -22,4 +22,4 @@ SELECT id, job, status FROM projects.tickets -WHERE number = ? AND repo = ?''; +WHERE number = ? AND repo = ?; From dd429b70c3ebe4507bbbc008bd16c58bdbff04fa Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Thu, 8 Feb 2024 13:30:51 +0300 Subject: [PATCH 05/29] Unit tests added --- .../git/tracehub/pmo/database/JdbcTest.java | 104 +++++++++++ .../tracehub/pmo/database/package-info.java | 23 +++ .../pmo/project/DefaultProjectsTest.java | 138 +++++++++++++++ .../pmo/ticket/DefaultTicketsTest.java | 162 ++++++++++++++++++ .../git/tracehub/pmo/ticket/TicketOfTest.java | 81 +++++++++ .../git/tracehub/pmo/ticket/package-info.java | 23 +++ src/test/java/it/database/package-info.java | 23 +++ 7 files changed, 554 insertions(+) create mode 100644 src/test/java/git/tracehub/pmo/database/JdbcTest.java create mode 100644 src/test/java/git/tracehub/pmo/database/package-info.java create mode 100644 src/test/java/git/tracehub/pmo/project/DefaultProjectsTest.java create mode 100644 src/test/java/git/tracehub/pmo/ticket/DefaultTicketsTest.java create mode 100644 src/test/java/git/tracehub/pmo/ticket/TicketOfTest.java create mode 100644 src/test/java/git/tracehub/pmo/ticket/package-info.java create mode 100644 src/test/java/it/database/package-info.java diff --git a/src/test/java/git/tracehub/pmo/database/JdbcTest.java b/src/test/java/git/tracehub/pmo/database/JdbcTest.java new file mode 100644 index 0000000..07aa014 --- /dev/null +++ b/src/test/java/git/tracehub/pmo/database/JdbcTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package git.tracehub.pmo.database; + +import git.tracehub.pmo.project.Project; +import git.tracehub.pmo.ticket.Ticket; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import javax.sql.DataSource; +import org.junit.jupiter.api.BeforeEach; +import org.mockito.Mock; +import org.mockito.Mockito; + +/** + * Jdbc test. + * + * @since 0.0.0 + */ +public class JdbcTest { + + /** + * Datasource. + */ + @Mock + private DataSource source; + + /** + * Connection. + */ + @Mock + private Connection connection; + + /** + * Statement. + */ + @Mock + private PreparedStatement statement; + + /** + * Result set. + */ + @Mock + protected ResultSet set; + + @BeforeEach + void setConnection() throws SQLException { + Mockito.when(this.source.getConnection()).thenReturn(this.connection); + Mockito.doNothing().when(this.connection).setAutoCommit(true); + Mockito.lenient().when(this.connection.prepareStatement(Mockito.anyString())) + .thenReturn(this.statement); + Mockito.lenient().when(this.connection.prepareStatement(Mockito.anyString(), Mockito.anyInt())) + .thenReturn(this.statement); + Mockito.doNothing().when(this.statement).close(); + Mockito.lenient().when(this.statement.executeQuery()).thenReturn(this.set); + Mockito.lenient().when(this.statement.getGeneratedKeys()).thenReturn(this.set); + } + + protected void setTicket(Ticket ticket) throws SQLException { + Mockito.when(this.set.next()).thenReturn(true); + Mockito.when(this.set.getString("id")) + .thenReturn(ticket.getId().toString()); + Mockito.when(this.set.getString("project")) + .thenReturn(ticket.getProject().toString()); + Mockito.when(this.set.getInt("number")) + .thenReturn(ticket.getNumber()); + Mockito.when(this.set.getString("repo")) + .thenReturn(ticket.getRepo()); + Mockito.when(this.set.getString("job")) + .thenReturn(ticket.getJob()); + Mockito.when(this.set.getString("status")) + .thenReturn(ticket.getStatus().name()); + } + + protected void setProject(Project project) throws SQLException { + Mockito.when(this.set.getString("id")) + .thenReturn(project.getId().toString()); + Mockito.when(this.set.getString("name")) + .thenReturn(project.getName()); + Mockito.when(this.set.getString("location")) + .thenReturn(project.getLocation()); + Mockito.when(this.set.getString("description")) + .thenReturn(project.getDescription()); + Mockito.when(this.set.getBoolean("active")) + .thenReturn(project.isActive()); + } + +} diff --git a/src/test/java/git/tracehub/pmo/database/package-info.java b/src/test/java/git/tracehub/pmo/database/package-info.java new file mode 100644 index 0000000..3f0be36 --- /dev/null +++ b/src/test/java/git/tracehub/pmo/database/package-info.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * Database Tests. + * + * @since 0.0.0 + */ +package git.tracehub.pmo.database; diff --git a/src/test/java/git/tracehub/pmo/project/DefaultProjectsTest.java b/src/test/java/git/tracehub/pmo/project/DefaultProjectsTest.java new file mode 100644 index 0000000..2b33abf --- /dev/null +++ b/src/test/java/git/tracehub/pmo/project/DefaultProjectsTest.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package git.tracehub.pmo.project; + +import git.tracehub.pmo.database.JdbcTest; +import git.tracehub.pmo.exception.ResourceNotFoundException; +import java.sql.SQLException; +import java.util.List; +import java.util.UUID; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.hamcrest.core.IsEqual; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.llorllale.cactoos.matchers.Assertion; +import org.llorllale.cactoos.matchers.Throws; +import org.mockito.InjectMocks; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +/** + * Test suite for {@link DefaultProjects}. + * + * @since 0.0.0 + */ +@ExtendWith(MockitoExtension.class) +final class DefaultProjectsTest extends JdbcTest { + + /** + * Default tickets. + */ + @InjectMocks + private DefaultProjects projects; + + @Test + void returnsProjectById() throws SQLException { + final Project expected = new Project( + UUID.randomUUID(), + "Test Project", + "Location", + "Description", + true + ); + super.setProject(expected); + Mockito.when(super.set.next()).thenReturn(true); + final Project project = this.projects.byId(expected.getId()); + MatcherAssert.assertThat( + "Project %s is null".formatted(project), + true, + Matchers.notNullValue() + ); + MatcherAssert.assertThat( + "Project %s isn't correct".formatted(project), + project, + new IsEqual<>(expected) + ); + } + + @Test + void returnsProjectsByUser() throws SQLException { + final String email = "email"; + final Project expected = new Project( + UUID.randomUUID(), + "Test Project", + "Location", + "Description", + true + ); + super.setProject(expected); + Mockito.when(super.set.next()).thenReturn(true, false); + final List actual = this.projects.byUser(email); + MatcherAssert.assertThat( + "List of projects %s is null".formatted(actual), + true, + Matchers.notNullValue() + ); + MatcherAssert.assertThat( + "List of projects %s isn't correct".formatted(actual), + actual, + Matchers.contains(expected) + ); + } + + @Test + void employsProject() throws SQLException { + final Project expected = new Project( + UUID.randomUUID(), + "Test Project", + "Location", + "Description", + true + ); + super.setProject(expected); + Mockito.when(super.set.next()).thenReturn(true); + final Project project = this.projects.employ(expected); + MatcherAssert.assertThat( + "Project %s is null".formatted(project), + true, + Matchers.notNullValue() + ); + MatcherAssert.assertThat( + "Project %s isn't correct".formatted(project), + project, + new IsEqual<>(expected) + ); + } + + @Test + @SuppressWarnings("JTCOP.RuleAssertionMessage") + void throwsOnInvalidProjectId() throws SQLException { + final UUID id = UUID.randomUUID(); + Mockito.when(super.set.next()).thenReturn(false); + new Assertion<>( + "Exception is not thrown or valid", + () -> this.projects.byId(id), + new Throws<>( + "Project %s not found".formatted(id), + ResourceNotFoundException.class + ) + ).affirm(); + } + +} diff --git a/src/test/java/git/tracehub/pmo/ticket/DefaultTicketsTest.java b/src/test/java/git/tracehub/pmo/ticket/DefaultTicketsTest.java new file mode 100644 index 0000000..a83d032 --- /dev/null +++ b/src/test/java/git/tracehub/pmo/ticket/DefaultTicketsTest.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package git.tracehub.pmo.ticket; + +import git.tracehub.pmo.database.JdbcTest; +import git.tracehub.pmo.exception.ResourceNotFoundException; +import java.sql.SQLException; +import java.util.UUID; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.hamcrest.core.IsEqual; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.llorllale.cactoos.matchers.Assertion; +import org.llorllale.cactoos.matchers.Throws; +import org.mockito.InjectMocks; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +/** + * Test suite for {@link DefaultTickets}. + * + * @since 0.0.0 + */ +@ExtendWith(MockitoExtension.class) +final class DefaultTicketsTest extends JdbcTest { + + /** + * Default tickets. + */ + @InjectMocks + private DefaultTickets tickets; + + @Test + void returnsTicketByJob() throws SQLException { + final Ticket expected = new Ticket( + UUID.randomUUID(), + UUID.randomUUID(), + 35, + "user/repo", + "path/to/job", + Ticket.Status.OPENED + ); + super.setTicket(expected); + Mockito.when(super.set.next()).thenReturn(true); + final Ticket ticket = this.tickets.byJob( + expected.getJob(), + expected.getRepo() + ); + MatcherAssert.assertThat( + "Ticket %s is null".formatted(ticket), + true, + Matchers.notNullValue() + ); + MatcherAssert.assertThat( + "Ticket %s isn't correct".formatted(ticket), + ticket, + new IsEqual<>(expected) + ); + } + + @Test + void returnsTicketByIssueNumber() throws SQLException { + final Ticket expected = new Ticket( + UUID.randomUUID(), + UUID.randomUUID(), + 35, + "user/repo", + "path/to/job", + Ticket.Status.OPENED + ); + super.setTicket(expected); + Mockito.when(super.set.next()).thenReturn(true); + final Ticket ticket = this.tickets.byNumber( + expected.getNumber(), + expected.getRepo() + ); + MatcherAssert.assertThat( + "Ticket %s is null".formatted(ticket), + true, + Matchers.notNullValue() + ); + MatcherAssert.assertThat( + "Ticket %s isn't correct".formatted(ticket), + ticket, + new IsEqual<>(expected) + ); + } + + @Test + void createsTicket() throws SQLException { + final Ticket expected = new Ticket( + UUID.randomUUID(), + UUID.randomUUID(), + 35, + "user/repo", + "path/to/job", + Ticket.Status.OPENED + ); + super.setTicket(expected); + Mockito.when(super.set.next()).thenReturn(true); + final Ticket ticket = this.tickets.create(expected); + MatcherAssert.assertThat( + "Ticket %s isn't created".formatted(ticket), + true, + Matchers.notNullValue() + ); + MatcherAssert.assertThat( + "Ticket %s isn't correct".formatted(ticket), + ticket, + new IsEqual<>(expected) + ); + } + + @Test + @SuppressWarnings("JTCOP.RuleAssertionMessage") + void throwsOnInvalidJob() throws SQLException { + final String job = "path/to/job"; + final String repo = "user/repo"; + Mockito.when(super.set.next()).thenReturn(false); + new Assertion<>( + "Exception is not thrown or valid", + () -> this.tickets.byJob(job, repo), + new Throws<>( + "Ticket with job = %s and repo = %s not found".formatted(job, repo), + ResourceNotFoundException.class + ) + ).affirm(); + } + + @Test + @SuppressWarnings("JTCOP.RuleAssertionMessage") + void throwsOnInvalidIssueNumber() throws SQLException { + final int number = 35; + final String repo = "user/repo"; + Mockito.when(super.set.next()).thenReturn(false); + new Assertion<>( + "Exception is not thrown or valid", + () -> this.tickets.byNumber(number, repo), + new Throws<>( + "Ticket with issue = %s and repo = %s not found".formatted(number, repo), + ResourceNotFoundException.class + ) + ).affirm(); + } + +} diff --git a/src/test/java/git/tracehub/pmo/ticket/TicketOfTest.java b/src/test/java/git/tracehub/pmo/ticket/TicketOfTest.java new file mode 100644 index 0000000..36e8265 --- /dev/null +++ b/src/test/java/git/tracehub/pmo/ticket/TicketOfTest.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package git.tracehub.pmo.ticket; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.UUID; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.hamcrest.core.IsEqual; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +/** + * Test suite for {@link TicketOf}. + * + * @since 0.0.0 + */ +@ExtendWith(MockitoExtension.class) +final class TicketOfTest { + + /** + * Result set. + */ + @Mock + private ResultSet set; + + @Test + void returnsTicketWithAllFields() throws SQLException { + final Ticket expected = new Ticket( + UUID.randomUUID(), + UUID.randomUUID(), + 35, + "user/repo", + "path/to/job", + Ticket.Status.OPENED + ); + Mockito.when(this.set.getString("id")) + .thenReturn(expected.getId().toString()); + Mockito.when(this.set.getString("project")) + .thenReturn(expected.getProject().toString()); + Mockito.when(this.set.getInt("number")) + .thenReturn(expected.getNumber()); + Mockito.when(this.set.getString("repo")) + .thenReturn(expected.getRepo()); + Mockito.when(this.set.getString("job")) + .thenReturn(expected.getJob()); + Mockito.when(this.set.getString("status")) + .thenReturn(expected.getStatus().name()); + final Ticket ticket = new TicketOf(this.set).value(); + MatcherAssert.assertThat( + "Ticket %s is null".formatted(ticket), + true, + Matchers.notNullValue() + ); + MatcherAssert.assertThat( + "Ticket %s isn't correct".formatted(ticket), + ticket, + new IsEqual<>(expected) + ); + } + +} diff --git a/src/test/java/git/tracehub/pmo/ticket/package-info.java b/src/test/java/git/tracehub/pmo/ticket/package-info.java new file mode 100644 index 0000000..04fe3cc --- /dev/null +++ b/src/test/java/git/tracehub/pmo/ticket/package-info.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * Ticket Tests. + * + * @since 0.0.0 + */ +package git.tracehub.pmo.ticket; diff --git a/src/test/java/it/database/package-info.java b/src/test/java/it/database/package-info.java new file mode 100644 index 0000000..8609cdd --- /dev/null +++ b/src/test/java/it/database/package-info.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * Database Integration Tests. + * + * @since 0.0.0 + */ +package it.database; From ee70e9a4b8cdbce23f31ac315b6ef77e6454d828 Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Thu, 8 Feb 2024 14:24:36 +0300 Subject: [PATCH 06/29] Unit tests fixed --- .../tracehub/pmo/ticket/DefaultTickets.java | 3 +- .../git/tracehub/pmo/database/JdbcTest.java | 58 +++++++++++++------ .../pmo/project/DefaultProjectsTest.java | 6 +- .../pmo/ticket/DefaultTicketsTest.java | 10 ++-- 4 files changed, 49 insertions(+), 28 deletions(-) diff --git a/src/main/java/git/tracehub/pmo/ticket/DefaultTickets.java b/src/main/java/git/tracehub/pmo/ticket/DefaultTickets.java index 416c509..e6ac16b 100644 --- a/src/main/java/git/tracehub/pmo/ticket/DefaultTickets.java +++ b/src/main/java/git/tracehub/pmo/ticket/DefaultTickets.java @@ -28,6 +28,7 @@ /** * Default tickets. * + * @checkstyle DesignForExtensionCheck (70 lines) * @since 0.0.0 */ @Component @@ -65,7 +66,7 @@ public Ticket byJob(final String job, final String repo) { public Ticket byNumber(final int number, final String repo) { return new JdbcSession(this.source) .sql( - new SqlStatement("select-ticket-by-job-and-repo.sql").asString() + new SqlStatement("select-ticket-by-number-and-repo.sql").asString() ).set(number) .set(repo) .select( diff --git a/src/test/java/git/tracehub/pmo/database/JdbcTest.java b/src/test/java/git/tracehub/pmo/database/JdbcTest.java index 07aa014..7b49739 100644 --- a/src/test/java/git/tracehub/pmo/database/JdbcTest.java +++ b/src/test/java/git/tracehub/pmo/database/JdbcTest.java @@ -35,6 +35,14 @@ */ public class JdbcTest { + /** + * Result set. + * + * @checkstyle VisibilityModifierCheck (3 lines) + */ + @Mock + protected ResultSet set; + /** * Datasource. */ @@ -54,25 +62,12 @@ public class JdbcTest { private PreparedStatement statement; /** - * Result set. + * Mock result set. + * + * @param ticket Ticket + * @throws SQLException If something goes wrong */ - @Mock - protected ResultSet set; - - @BeforeEach - void setConnection() throws SQLException { - Mockito.when(this.source.getConnection()).thenReturn(this.connection); - Mockito.doNothing().when(this.connection).setAutoCommit(true); - Mockito.lenient().when(this.connection.prepareStatement(Mockito.anyString())) - .thenReturn(this.statement); - Mockito.lenient().when(this.connection.prepareStatement(Mockito.anyString(), Mockito.anyInt())) - .thenReturn(this.statement); - Mockito.doNothing().when(this.statement).close(); - Mockito.lenient().when(this.statement.executeQuery()).thenReturn(this.set); - Mockito.lenient().when(this.statement.getGeneratedKeys()).thenReturn(this.set); - } - - protected void setTicket(Ticket ticket) throws SQLException { + protected void mockResultSet(final Ticket ticket) throws SQLException { Mockito.when(this.set.next()).thenReturn(true); Mockito.when(this.set.getString("id")) .thenReturn(ticket.getId().toString()); @@ -88,7 +83,13 @@ protected void setTicket(Ticket ticket) throws SQLException { .thenReturn(ticket.getStatus().name()); } - protected void setProject(Project project) throws SQLException { + /** + * Mock result set. + * + * @param project Project + * @throws SQLException If something goes wrong + */ + protected void mockResultSet(final Project project) throws SQLException { Mockito.when(this.set.getString("id")) .thenReturn(project.getId().toString()); Mockito.when(this.set.getString("name")) @@ -101,4 +102,23 @@ protected void setProject(Project project) throws SQLException { .thenReturn(project.isActive()); } + /** + * Set datasource and connection. + * + * @throws SQLException If something goes wrong + */ + @BeforeEach + void setConnection() throws SQLException { + Mockito.when(this.source.getConnection()).thenReturn(this.connection); + Mockito.doNothing().when(this.connection).setAutoCommit(true); + Mockito.lenient().when(this.connection.prepareStatement(Mockito.anyString())) + .thenReturn(this.statement); + Mockito.lenient() + .when(this.connection.prepareStatement(Mockito.anyString(), Mockito.anyInt())) + .thenReturn(this.statement); + Mockito.doNothing().when(this.statement).close(); + Mockito.lenient().when(this.statement.executeQuery()).thenReturn(this.set); + Mockito.lenient().when(this.statement.getGeneratedKeys()).thenReturn(this.set); + } + } diff --git a/src/test/java/git/tracehub/pmo/project/DefaultProjectsTest.java b/src/test/java/git/tracehub/pmo/project/DefaultProjectsTest.java index 2b33abf..632ea80 100644 --- a/src/test/java/git/tracehub/pmo/project/DefaultProjectsTest.java +++ b/src/test/java/git/tracehub/pmo/project/DefaultProjectsTest.java @@ -56,7 +56,7 @@ void returnsProjectById() throws SQLException { "Description", true ); - super.setProject(expected); + super.mockResultSet(expected); Mockito.when(super.set.next()).thenReturn(true); final Project project = this.projects.byId(expected.getId()); MatcherAssert.assertThat( @@ -81,7 +81,7 @@ void returnsProjectsByUser() throws SQLException { "Description", true ); - super.setProject(expected); + super.mockResultSet(expected); Mockito.when(super.set.next()).thenReturn(true, false); final List actual = this.projects.byUser(email); MatcherAssert.assertThat( @@ -105,7 +105,7 @@ void employsProject() throws SQLException { "Description", true ); - super.setProject(expected); + super.mockResultSet(expected); Mockito.when(super.set.next()).thenReturn(true); final Project project = this.projects.employ(expected); MatcherAssert.assertThat( diff --git a/src/test/java/git/tracehub/pmo/ticket/DefaultTicketsTest.java b/src/test/java/git/tracehub/pmo/ticket/DefaultTicketsTest.java index a83d032..73feca7 100644 --- a/src/test/java/git/tracehub/pmo/ticket/DefaultTicketsTest.java +++ b/src/test/java/git/tracehub/pmo/ticket/DefaultTicketsTest.java @@ -56,7 +56,7 @@ void returnsTicketByJob() throws SQLException { "path/to/job", Ticket.Status.OPENED ); - super.setTicket(expected); + super.mockResultSet(expected); Mockito.when(super.set.next()).thenReturn(true); final Ticket ticket = this.tickets.byJob( expected.getJob(), @@ -84,7 +84,7 @@ void returnsTicketByIssueNumber() throws SQLException { "path/to/job", Ticket.Status.OPENED ); - super.setTicket(expected); + super.mockResultSet(expected); Mockito.when(super.set.next()).thenReturn(true); final Ticket ticket = this.tickets.byNumber( expected.getNumber(), @@ -112,7 +112,7 @@ void createsTicket() throws SQLException { "path/to/job", Ticket.Status.OPENED ); - super.setTicket(expected); + super.mockResultSet(expected); Mockito.when(super.set.next()).thenReturn(true); final Ticket ticket = this.tickets.create(expected); MatcherAssert.assertThat( @@ -131,7 +131,7 @@ void createsTicket() throws SQLException { @SuppressWarnings("JTCOP.RuleAssertionMessage") void throwsOnInvalidJob() throws SQLException { final String job = "path/to/job"; - final String repo = "user/repo"; + final String repo = "repo"; Mockito.when(super.set.next()).thenReturn(false); new Assertion<>( "Exception is not thrown or valid", @@ -147,7 +147,7 @@ void throwsOnInvalidJob() throws SQLException { @SuppressWarnings("JTCOP.RuleAssertionMessage") void throwsOnInvalidIssueNumber() throws SQLException { final int number = 35; - final String repo = "user/repo"; + final String repo = "repo"; Mockito.when(super.set.next()).thenReturn(false); new Assertion<>( "Exception is not thrown or valid", From e979c80a05530fadcf50d395785bbf7a4dca9ee1 Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Thu, 8 Feb 2024 14:24:50 +0300 Subject: [PATCH 07/29] String format refactored --- src/main/java/git/tracehub/pmo/project/DefaultProjects.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/java/git/tracehub/pmo/project/DefaultProjects.java b/src/main/java/git/tracehub/pmo/project/DefaultProjects.java index 8a6000c..e149850 100644 --- a/src/main/java/git/tracehub/pmo/project/DefaultProjects.java +++ b/src/main/java/git/tracehub/pmo/project/DefaultProjects.java @@ -53,10 +53,7 @@ public Project byId(final UUID id) { (rs, stmt) -> { if (!rs.next()) { throw new ResourceNotFoundException( - String.format( - "Project %s not found", - id - ) + "Project %s not found".formatted(id) ); } return new ProjectOf(rs).value(); From ef95fc1c46a940b2f0c4cf3756bce478133cef15 Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Thu, 8 Feb 2024 14:25:01 +0300 Subject: [PATCH 08/29] It tests implemented --- .../java/it/database/DefaultProjectsIT.java | 116 ++++++++++++++++ .../java/it/database/DefaultTicketsIT.java | 124 ++++++++++++++++++ src/test/resources/application-pgit.yaml | 5 + src/test/resources/pre/sql/projects.sql | 20 ++- 4 files changed, 263 insertions(+), 2 deletions(-) create mode 100644 src/test/java/it/database/DefaultProjectsIT.java create mode 100644 src/test/java/it/database/DefaultTicketsIT.java diff --git a/src/test/java/it/database/DefaultProjectsIT.java b/src/test/java/it/database/DefaultProjectsIT.java new file mode 100644 index 0000000..755b238 --- /dev/null +++ b/src/test/java/it/database/DefaultProjectsIT.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package it.database; + +import git.tracehub.pmo.PmoApplication; +import git.tracehub.pmo.project.DefaultProjects; +import git.tracehub.pmo.project.Project; +import git.tracehub.pmo.project.Projects; +import it.PostgresIntegration; +import java.util.List; +import java.util.UUID; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.hamcrest.core.IsEqual; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.jdbc.Sql; + +/** + * Integration tests for {@link DefaultProjects}. + * + * @since 0.0.0 + */ +@ActiveProfiles("pgit") +@SpringBootTest(classes = PmoApplication.class) +@SuppressWarnings("JTCOP.RuleAllTestsHaveProductionClass") +final class DefaultProjectsIT implements PostgresIntegration { + + /** + * Projects. + */ + @Autowired + private Projects projects; + + @Test + @Sql("classpath:pre/sql/projects.sql") + void returnsProjectById() { + final Project expected = new Project( + UUID.fromString("74bb5ec8-0e6b-4618-bfa4-a0b76b7b312d"), + "Test", + "github@user/test:master", + "Description", + true + ); + final Project project = this.projects.byId(expected.getId()); + MatcherAssert.assertThat( + "Project %s is null".formatted(project), + true, + Matchers.notNullValue() + ); + MatcherAssert.assertThat( + "Project %s isn't correct".formatted(project), + project, + new IsEqual<>(expected) + ); + } + + @Test + @Sql("classpath:pre/sql/projects.sql") + void returnsProjectsByUser() { + final String email = "user"; + final Project expected = new Project( + UUID.fromString("74bb5ec8-0e6b-4618-bfa4-a0b76b7b312d"), + "Test", + "github@user/test:master", + "Description", + true + ); + final List actual = this.projects.byUser(email); + MatcherAssert.assertThat( + "List of projects %s is null".formatted(actual), + true, + Matchers.notNullValue() + ); + MatcherAssert.assertThat( + "List of projects %s isn't correct".formatted(actual), + actual, + Matchers.contains(expected) + ); + } + + @Test + void employsProject() { + final Project expected = new Project( + UUID.fromString("74bb5ec8-0e6b-4618-bfa4-a0b76b7b312d"), + "New project", + "Location", + "Description", + true + ); + final Project project = this.projects.employ(expected); + MatcherAssert.assertThat( + "Project %s is null".formatted(project), + true, + Matchers.notNullValue() + ); + } + +} diff --git a/src/test/java/it/database/DefaultTicketsIT.java b/src/test/java/it/database/DefaultTicketsIT.java new file mode 100644 index 0000000..df7343c --- /dev/null +++ b/src/test/java/it/database/DefaultTicketsIT.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package it.database; + +import git.tracehub.pmo.PmoApplication; +import git.tracehub.pmo.ticket.DefaultTickets; +import git.tracehub.pmo.ticket.Ticket; +import git.tracehub.pmo.ticket.Tickets; +import it.PostgresIntegration; +import java.util.UUID; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.hamcrest.core.IsEqual; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.jdbc.Sql; + +/** + * Integration tests for {@link DefaultTickets}. + * + * @since 0.0.0 + */ +@ActiveProfiles("pgit") +@SpringBootTest(classes = PmoApplication.class) +@SuppressWarnings("JTCOP.RuleAllTestsHaveProductionClass") +final class DefaultTicketsIT implements PostgresIntegration { + + /** + * Tickets. + */ + @Autowired + private Tickets tickets; + + @Test + @Sql("classpath:pre/sql/projects.sql") + void returnsTicketByJob() { + final Ticket expected = new Ticket( + UUID.fromString("04986038-6e38-4928-b12e-644c99f9cadc"), + UUID.fromString("74bb5ec8-0e6b-4618-bfa4-a0b76b7b312d"), + 1, + "user/test", + "path/to/job", + Ticket.Status.OPENED + ); + final Ticket ticket = this.tickets.byJob( + expected.getJob(), + expected.getRepo() + ); + MatcherAssert.assertThat( + "Ticket %s is null".formatted(ticket), + true, + Matchers.notNullValue() + ); + MatcherAssert.assertThat( + "Ticket %s isn't correct".formatted(ticket), + ticket, + new IsEqual<>(expected) + ); + } + + @Test + @Sql("classpath:pre/sql/projects.sql") + void returnsTicketByIssueNumber() { + final Ticket expected = new Ticket( + UUID.fromString("04986038-6e38-4928-b12e-644c99f9cadc"), + UUID.fromString("74bb5ec8-0e6b-4618-bfa4-a0b76b7b312d"), + 1, + "user/test", + "path/to/job", + Ticket.Status.OPENED + ); + final Ticket ticket = this.tickets.byNumber( + expected.getNumber(), + expected.getRepo() + ); + MatcherAssert.assertThat( + "Ticket %s is null".formatted(ticket), + true, + Matchers.notNullValue() + ); + MatcherAssert.assertThat( + "Ticket %s isn't correct".formatted(ticket), + ticket, + new IsEqual<>(expected) + ); + } + + @Test + @Sql("classpath:pre/sql/projects.sql") + void createsTicket() { + final Ticket expected = new Ticket( + UUID.fromString("04986038-6e38-4928-b12e-644c99f9cadc"), + UUID.fromString("74bb5ec8-0e6b-4618-bfa4-a0b76b7b312d"), + 1, + "user/test", + "path/to/job", + Ticket.Status.OPENED + ); + final Ticket ticket = this.tickets.create(expected); + MatcherAssert.assertThat( + "Ticket %s is null".formatted(ticket), + true, + Matchers.notNullValue() + ); + } + +} diff --git a/src/test/resources/application-pgit.yaml b/src/test/resources/application-pgit.yaml index fec3db8..f6ce8a5 100644 --- a/src/test/resources/application-pgit.yaml +++ b/src/test/resources/application-pgit.yaml @@ -8,5 +8,10 @@ spring: liquibase: user: test password: test + security: + oauth2: + resourceserver: + jwt: + issuer-uri: url platforms: github: host diff --git a/src/test/resources/pre/sql/projects.sql b/src/test/resources/pre/sql/projects.sql index de1d8fb..0108505 100644 --- a/src/test/resources/pre/sql/projects.sql +++ b/src/test/resources/pre/sql/projects.sql @@ -7,10 +7,26 @@ VALUES ('74bb5ec8-0e6b-4618-bfa4-a0b76b7b312d', 'Test', 'github@user/test:master', 'Description', - true); + true) +ON CONFLICT (id) DO NOTHING; + INSERT INTO projects.performers (email, project, permission) VALUES ('user', '74bb5ec8-0e6b-4618-bfa4-a0b76b7b312d', - 'READ'); \ No newline at end of file + 'READ'); + +INSERT INTO projects.tickets(id, + project, + number, + repo, + job, + status) +VALUES ('04986038-6e38-4928-b12e-644c99f9cadc', + '74bb5ec8-0e6b-4618-bfa4-a0b76b7b312d', + 1, + 'user/test', + 'path/to/job', + 'OPENED') +ON CONFLICT (id) DO NOTHING; From 52a1404a74997c3a40a7cceed910bac810ebd7f1 Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Thu, 8 Feb 2024 18:51:37 +0300 Subject: [PATCH 09/29] Controller advice added --- .../pmo/controller/AdviceController.java | 110 ++++++++++++++++++ .../controller/request/ProjectFromReq.java | 47 ++++++++ .../pmo/controller/request/RqProject.java | 41 +++++++ .../pmo/controller/request/RqTicket.java | 48 ++++++++ .../pmo/controller/request/TicketFromReq.java | 48 ++++++++ .../pmo/controller/request/package-info.java | 23 ++++ .../pmo/request/TicketFromReqTest.java | 66 +++++++++++ 7 files changed, 383 insertions(+) create mode 100644 src/main/java/git/tracehub/pmo/controller/AdviceController.java create mode 100644 src/main/java/git/tracehub/pmo/controller/request/ProjectFromReq.java create mode 100644 src/main/java/git/tracehub/pmo/controller/request/RqProject.java create mode 100644 src/main/java/git/tracehub/pmo/controller/request/RqTicket.java create mode 100644 src/main/java/git/tracehub/pmo/controller/request/TicketFromReq.java create mode 100644 src/main/java/git/tracehub/pmo/controller/request/package-info.java create mode 100644 src/test/java/git/tracehub/pmo/request/TicketFromReqTest.java diff --git a/src/main/java/git/tracehub/pmo/controller/AdviceController.java b/src/main/java/git/tracehub/pmo/controller/AdviceController.java new file mode 100644 index 0000000..2501cd4 --- /dev/null +++ b/src/main/java/git/tracehub/pmo/controller/AdviceController.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package git.tracehub.pmo.controller; + +import git.tracehub.pmo.exception.ResourceNotFoundException; +import io.github.eocqrs.eokson.Jocument; +import io.github.eocqrs.eokson.MutableJson; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.support.DefaultMessageSourceResolvable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +/** + * Exception handler. + * + * @since 0.0.0 + * @checkstyle NonStaticMethodCheck (70 lines) + */ +@Slf4j +@RestControllerAdvice +public class AdviceController { + + /** + * Handle MethodArgumentNotValidException. + * + * @param exception Exception + * @return ResponseEntity + */ + @ExceptionHandler(MethodArgumentNotValidException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ResponseEntity handle( + final MethodArgumentNotValidException exception + ) { + log.warn(exception.getMessage(), exception); + return new ResponseEntity<>( + new Jocument( + new MutableJson() + .with( + "message", + exception.getBindingResult().getFieldErrors() + .stream() + .map(DefaultMessageSourceResolvable::getDefaultMessage) + .collect(Collectors.joining(", ")) + ) + ).byteArray(), + HttpStatus.BAD_REQUEST + ); + } + + /** + * Handle ResourceNotFoundException. + * + * @param exception Exception + * @return ResponseEntity + */ + @ExceptionHandler(ResourceNotFoundException.class) + @ResponseStatus(HttpStatus.NOT_FOUND) + public ResponseEntity handle( + final ResourceNotFoundException exception + ) { + log.warn(exception.getMessage(), exception); + return new ResponseEntity<>( + new Jocument( + new MutableJson() + .with("message", exception.getMessage()) + ).byteArray(), + HttpStatus.NOT_FOUND + ); + } + + /** + * Handle Exception. + * + * @param exception Exception + * @return ResponseEntity + */ + @ExceptionHandler(Exception.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public ResponseEntity handle(final Exception exception) { + log.warn(exception.getMessage(), exception); + return new ResponseEntity<>( + new Jocument( + new MutableJson() + .with("message", exception.getMessage()) + ).byteArray(), + HttpStatus.INTERNAL_SERVER_ERROR + ); + } + +} diff --git a/src/main/java/git/tracehub/pmo/controller/request/ProjectFromReq.java b/src/main/java/git/tracehub/pmo/controller/request/ProjectFromReq.java new file mode 100644 index 0000000..5a2e016 --- /dev/null +++ b/src/main/java/git/tracehub/pmo/controller/request/ProjectFromReq.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package git.tracehub.pmo.controller.request; + +import git.tracehub.pmo.project.Project; +import lombok.RequiredArgsConstructor; +import org.cactoos.Scalar; + +/** + * Project from request. + * + * @since 0.0.0 + */ +@RequiredArgsConstructor +public final class ProjectFromReq implements Scalar { + + /** + * Request project. + */ + private final RqProject project; + + @Override + public Project value() { + return new Project( + this.project.name(), + this.project.location(), + this.project.description(), + this.project.active() + ); + } + +} diff --git a/src/main/java/git/tracehub/pmo/controller/request/RqProject.java b/src/main/java/git/tracehub/pmo/controller/request/RqProject.java new file mode 100644 index 0000000..ef1dd6d --- /dev/null +++ b/src/main/java/git/tracehub/pmo/controller/request/RqProject.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package git.tracehub.pmo.controller.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + +/** + * Request Project. + * + * @since 0.0.0 + */ +public record RqProject( + @NotBlank(message = "Name can't be blank") + String name, + + @NotBlank(message = "Location can't be blank") + String location, + + String description, + + @NotNull(message = "Active status can't be null") + boolean active +) { + +} diff --git a/src/main/java/git/tracehub/pmo/controller/request/RqTicket.java b/src/main/java/git/tracehub/pmo/controller/request/RqTicket.java new file mode 100644 index 0000000..afa27d3 --- /dev/null +++ b/src/main/java/git/tracehub/pmo/controller/request/RqTicket.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package git.tracehub.pmo.controller.request; + +import git.tracehub.pmo.ticket.Ticket; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import java.util.UUID; + +/** + * Request Ticket. + * + * @since 0.0.0 + */ +public record RqTicket( + + @NotNull(message = "Project id can't be null") + UUID project, + + @NotNull(message = "Issue number can't be null") + Integer number, + + @NotBlank(message = "Repository name can't be blank") + String repo, + + @NotBlank(message = "Path to job name can't be blank") + String job, + + @NotNull(message = "Status can't be null") + Ticket.Status status +) { + +} diff --git a/src/main/java/git/tracehub/pmo/controller/request/TicketFromReq.java b/src/main/java/git/tracehub/pmo/controller/request/TicketFromReq.java new file mode 100644 index 0000000..302919f --- /dev/null +++ b/src/main/java/git/tracehub/pmo/controller/request/TicketFromReq.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package git.tracehub.pmo.controller.request; + +import git.tracehub.pmo.ticket.Ticket; +import lombok.RequiredArgsConstructor; +import org.cactoos.Scalar; + +/** + * Ticket from request. + * + * @since 0.0.0 + */ +@RequiredArgsConstructor +public final class TicketFromReq implements Scalar { + + /** + * Request ticket. + */ + private final RqTicket ticket; + + @Override + public Ticket value() { + return new Ticket( + this.ticket.project(), + this.ticket.number(), + this.ticket.repo(), + this.ticket.job(), + this.ticket.status() + ); + } + +} diff --git a/src/main/java/git/tracehub/pmo/controller/request/package-info.java b/src/main/java/git/tracehub/pmo/controller/request/package-info.java new file mode 100644 index 0000000..85c64d6 --- /dev/null +++ b/src/main/java/git/tracehub/pmo/controller/request/package-info.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * Requests. + * + * @since 0.0.0 + */ +package git.tracehub.pmo.controller.request; diff --git a/src/test/java/git/tracehub/pmo/request/TicketFromReqTest.java b/src/test/java/git/tracehub/pmo/request/TicketFromReqTest.java new file mode 100644 index 0000000..cd7d2c1 --- /dev/null +++ b/src/test/java/git/tracehub/pmo/request/TicketFromReqTest.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package git.tracehub.pmo.request; + +import git.tracehub.pmo.controller.request.RqTicket; +import git.tracehub.pmo.controller.request.TicketFromReq; +import git.tracehub.pmo.ticket.Ticket; +import java.util.UUID; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Test; + +/** + * Test suite for {@link TicketFromReq}. + * + * @since 0.0.0 + */ +final class TicketFromReqTest { + + @Test + void createsTicketFromRequest() { + final Ticket expected = new Ticket( + UUID.randomUUID(), + UUID.randomUUID(), + 1, + "user/test", + "path/to/job", + Ticket.Status.OPENED + ); + final Ticket ticket = new TicketFromReq( + new RqTicket( + expected.getProject(), + expected.getNumber(), + expected.getRepo(), + expected.getJob(), + expected.getStatus() + ) + ).value(); + MatcherAssert.assertThat( + "Ticket %s is null".formatted(ticket), + true, + Matchers.notNullValue() + ); + MatcherAssert.assertThat( + "Ticket %s isn't correct".formatted(ticket), + ticket, + Matchers.samePropertyValuesAs(expected, "id") + ); + } + +} From d465c0660d28213a77f24cbee8306e9af8db8ca4 Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Thu, 8 Feb 2024 18:52:15 +0300 Subject: [PATCH 10/29] Resolved #34 --- .../pmo/controller/ProjectController.java | 13 ++- .../pmo/controller/TicketController.java | 94 +++++++++++++++++++ .../git/tracehub/pmo/project/Project.java | 58 ++++++++++-- .../java/git/tracehub/pmo/ticket/Ticket.java | 65 +++++++++++-- 4 files changed, 209 insertions(+), 21 deletions(-) create mode 100644 src/main/java/git/tracehub/pmo/controller/TicketController.java diff --git a/src/main/java/git/tracehub/pmo/controller/ProjectController.java b/src/main/java/git/tracehub/pmo/controller/ProjectController.java index 7de1782..955e0e7 100644 --- a/src/main/java/git/tracehub/pmo/controller/ProjectController.java +++ b/src/main/java/git/tracehub/pmo/controller/ProjectController.java @@ -20,6 +20,8 @@ import com.jcabi.github.Coordinates; import com.jcabi.github.Repo; import com.jcabi.github.RtGithub; +import git.tracehub.pmo.controller.request.ProjectFromReq; +import git.tracehub.pmo.controller.request.RqProject; import git.tracehub.pmo.platforms.Label; import git.tracehub.pmo.platforms.RepoPath; import git.tracehub.pmo.platforms.github.CreateLabels; @@ -30,6 +32,7 @@ import git.tracehub.pmo.security.ClaimOf; import git.tracehub.pmo.security.ExistsRole; import git.tracehub.pmo.security.IdpToken; +import jakarta.validation.Valid; import java.awt.Color; import java.util.List; import java.util.UUID; @@ -44,6 +47,7 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; @@ -54,6 +58,7 @@ */ @RestController @RequiredArgsConstructor +@RequestMapping("/projects") public class ProjectController { /** @@ -106,14 +111,16 @@ public Project byId(@PathVariable final UUID id) { * @return Project * @checkstyle MethodBodyCommentsCheck (20 lines) */ - @PostMapping() + @PostMapping @PreAuthorize("hasAuthority('user_github')") @ResponseStatus(HttpStatus.CREATED) public Project employ( - @RequestBody final Project project, + @RequestBody @Valid final RqProject project, @AuthenticationPrincipal final Jwt jwt ) { - final Project created = this.projects.employ(project); + final Project created = this.projects.employ( + new ProjectFromReq(project).value() + ); /* * @todo #1:45min/DEV define appropriate agent according to location * of the project. We need to define appropriate agent and call diff --git a/src/main/java/git/tracehub/pmo/controller/TicketController.java b/src/main/java/git/tracehub/pmo/controller/TicketController.java new file mode 100644 index 0000000..f5428a7 --- /dev/null +++ b/src/main/java/git/tracehub/pmo/controller/TicketController.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package git.tracehub.pmo.controller; + +import git.tracehub.pmo.controller.request.RqTicket; +import git.tracehub.pmo.controller.request.TicketFromReq; +import git.tracehub.pmo.ticket.Ticket; +import git.tracehub.pmo.ticket.Tickets; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +/** + * Ticket Controller. + * + * @since 0.0.0 + */ +@RestController +@RequiredArgsConstructor +@RequestMapping("/tickets") +public class TicketController { + + /** + * Tickets. + */ + private final Tickets tickets; + + /** + * Ticket by path to job and repository. + * + * @param job Path to job + * @param repo Repository name + * @return Ticket + */ + @GetMapping("/job") + public Ticket byJob( + @RequestParam final String job, + @RequestParam final String repo + ) { + return this.tickets.byJob(job, repo); + } + + /** + * Ticket by issue number and repository. + * + * @param number Issue number + * @param repo Repository name + * @return Ticket + */ + @GetMapping("/number") + public Ticket byNumber( + @RequestParam final Integer number, + @RequestParam final String repo + ) { + return this.tickets.byNumber(number, repo); + } + + /** + * Create ticket. + * + * @param ticket Ticket + * @return Ticket + */ + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public Ticket create(@RequestBody @Valid final RqTicket ticket) { + return this.tickets.create( + new TicketFromReq(ticket).value() + ); + } + +} diff --git a/src/main/java/git/tracehub/pmo/project/Project.java b/src/main/java/git/tracehub/pmo/project/Project.java index be25008..2830a8b 100644 --- a/src/main/java/git/tracehub/pmo/project/Project.java +++ b/src/main/java/git/tracehub/pmo/project/Project.java @@ -18,18 +18,16 @@ package git.tracehub.pmo.project; import java.util.UUID; -import lombok.AllArgsConstructor; import lombok.Data; -import lombok.NoArgsConstructor; /** * Project. * + * @checkstyle ParameterNumberCheck (70 lines) * @since 0.0.0 */ @Data -@AllArgsConstructor -@NoArgsConstructor +@SuppressWarnings("PMD.OnlyOneConstructorShouldDoInitialization") public class Project { /** @@ -40,21 +38,63 @@ public class Project { /** * Name. */ - private String name; + private final String name; /** * Location. */ - private String location; + private final String location; /** * Description. */ - private String description; + private final String description; /** - * Visibility. + * Is active. */ - private boolean active; + private final boolean active; + /** + * Constructor. + * + * @param id Id + * @param name Name + * @param location Location + * @param description Description + * @param active Is active + */ + public Project( + final UUID id, + final String name, + final String location, + final String description, + final boolean active + ) { + this.id = id; + this.name = name; + this.location = location; + this.description = description; + this.active = active; + } + + /** + * Constructor. + * + * @param name Name + * @param location Location + * @param description Description + * @param active Is active + */ + public Project( + final String name, + final String location, + final String description, + final boolean active + ) { + this.name = name; + this.location = location; + this.description = description; + this.active = active; + } } diff --git a/src/main/java/git/tracehub/pmo/ticket/Ticket.java b/src/main/java/git/tracehub/pmo/ticket/Ticket.java index 7f61753..a4f642e 100644 --- a/src/main/java/git/tracehub/pmo/ticket/Ticket.java +++ b/src/main/java/git/tracehub/pmo/ticket/Ticket.java @@ -18,18 +18,16 @@ package git.tracehub.pmo.ticket; import java.util.UUID; -import lombok.AllArgsConstructor; import lombok.Data; -import lombok.NoArgsConstructor; /** * Ticket. * + * @checkstyle ParameterNumberCheck (90 lines) * @since 0.0.0 */ @Data -@NoArgsConstructor -@AllArgsConstructor +@SuppressWarnings("PMD.OnlyOneConstructorShouldDoInitialization") public class Ticket { /** @@ -40,27 +38,27 @@ public class Ticket { /** * Project id. */ - private UUID project; + private final UUID project; /** * Issue number. */ - private int number; + private final int number; /** * Repository. */ - private String repo; + private final String repo; /** * Job. */ - private String job; + private final String job; /** * Status. */ - private Status status; + private final Status status; /** * Status of the ticket. @@ -79,4 +77,53 @@ public enum Status { } + /** + * Constructor. + * + * @param id Id + * @param project Project id + * @param number Issue number + * @param repo Repository + * @param job Job + * @param status Status + */ + public Ticket( + final UUID id, + final UUID project, + final int number, + final String repo, + final String job, + final Status status + ) { + this.id = id; + this.project = project; + this.number = number; + this.repo = repo; + this.job = job; + this.status = status; + } + + /** + * Constructor. + * + * @param project Project id + * @param number Issue number + * @param repo Repository + * @param job Job + * @param status Status + */ + public Ticket( + final UUID project, + final int number, + final String repo, + final String job, + final Status status + ) { + this.project = project; + this.number = number; + this.repo = repo; + this.job = job; + this.status = status; + } + } From e6fe1f757acaf917424c612cf8464f8613a16dab Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Thu, 8 Feb 2024 18:52:42 +0300 Subject: [PATCH 11/29] Unit tests for controllers added --- .../pmo/controller/ProjectControllerTest.java | 32 ++++- .../pmo/controller/TicketControllerTest.java | 130 ++++++++++++++++++ .../pmo/request/ProjectFromReqTest.java | 64 +++++++++ .../tracehub/pmo/request/package-info.java | 23 ++++ 4 files changed, 245 insertions(+), 4 deletions(-) create mode 100644 src/test/java/git/tracehub/pmo/controller/TicketControllerTest.java create mode 100644 src/test/java/git/tracehub/pmo/request/ProjectFromReqTest.java create mode 100644 src/test/java/git/tracehub/pmo/request/package-info.java diff --git a/src/test/java/git/tracehub/pmo/controller/ProjectControllerTest.java b/src/test/java/git/tracehub/pmo/controller/ProjectControllerTest.java index 7cdc406..5245649 100644 --- a/src/test/java/git/tracehub/pmo/controller/ProjectControllerTest.java +++ b/src/test/java/git/tracehub/pmo/controller/ProjectControllerTest.java @@ -20,6 +20,7 @@ import git.tracehub.pmo.project.Projects; import io.github.eocqrs.eokson.Jocument; import io.github.eocqrs.eokson.JsonOf; +import io.github.eocqrs.eokson.MutableJson; import org.cactoos.io.ResourceOf; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -60,7 +61,7 @@ final class ProjectControllerTest { @Test void returnsForbiddenOnUnauthorizedUser() throws Exception { this.mvc.perform( - MockMvcRequestBuilders.post("/") + MockMvcRequestBuilders.post("/projects") .contentType(MediaType.APPLICATION_JSON) ).andExpect(MockMvcResultMatchers.status().isForbidden()); } @@ -68,7 +69,7 @@ void returnsForbiddenOnUnauthorizedUser() throws Exception { @Test void returnsProjectByUser() throws Exception { this.mvc.perform( - MockMvcRequestBuilders.get("/") + MockMvcRequestBuilders.get("/projects") .with(SecurityMockMvcRequestPostProcessors.jwt()) .contentType(MediaType.APPLICATION_JSON) ).andExpect(MockMvcResultMatchers.status().isOk()); @@ -77,7 +78,7 @@ void returnsProjectByUser() throws Exception { @Test void returnsProjectById() throws Exception { this.mvc.perform( - MockMvcRequestBuilders.get("/74bb5ec8-0e6b-4618-bfa4-a0b76b7b312d") + MockMvcRequestBuilders.get("/projects/74bb5ec8-0e6b-4618-bfa4-a0b76b7b312d") .with(SecurityMockMvcRequestPostProcessors.jwt()) .contentType(MediaType.APPLICATION_JSON) ).andExpect(MockMvcResultMatchers.status().isOk()); @@ -86,7 +87,7 @@ void returnsProjectById() throws Exception { @Test void createsNewProject() throws Exception { this.mvc.perform( - MockMvcRequestBuilders.post("/") + MockMvcRequestBuilders.post("/projects") .with(SecurityMockMvcRequestPostProcessors.jwt()) .contentType(MediaType.APPLICATION_JSON) .content( @@ -99,4 +100,27 @@ void createsNewProject() throws Exception { ).andExpect(MockMvcResultMatchers.status().isCreated()); } + @Test + void throwsOnInvalidRequestBody() throws Exception { + this.mvc.perform( + MockMvcRequestBuilders.post("/projects") + .with(SecurityMockMvcRequestPostProcessors.jwt()) + .contentType(MediaType.APPLICATION_JSON) + .content( + new Jocument( + new JsonOf( + new ResourceOf("data/no-name-project.json").stream() + ) + ).toString() + ) + ).andExpect(MockMvcResultMatchers.status().isBadRequest()) + .andExpect( + MockMvcResultMatchers.content().string( + new MutableJson() + .with("message", "Name can't be blank") + .toString() + ) + ); + } + } diff --git a/src/test/java/git/tracehub/pmo/controller/TicketControllerTest.java b/src/test/java/git/tracehub/pmo/controller/TicketControllerTest.java new file mode 100644 index 0000000..236d713 --- /dev/null +++ b/src/test/java/git/tracehub/pmo/controller/TicketControllerTest.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package git.tracehub.pmo.controller; + +import git.tracehub.pmo.ticket.Tickets; +import io.github.eocqrs.eokson.Jocument; +import io.github.eocqrs.eokson.JsonOf; +import io.github.eocqrs.eokson.MutableJson; +import org.cactoos.io.ResourceOf; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +/** + * Test suite for {@link TicketController}. + * + * @since 0.0.0 + */ +@ActiveProfiles("web") +@ExtendWith(SpringExtension.class) +@WebMvcTest(controllers = TicketController.class) +final class TicketControllerTest { + + /** + * Mocked mvc. + */ + @Autowired + private MockMvc mvc; + + /** + * Tickets. + */ + @MockBean + @SuppressWarnings("PMD.UnusedPrivateField") + private Tickets tickets; + + @Test + void returnsForbiddenOnUnauthorizedUser() throws Exception { + this.mvc.perform( + MockMvcRequestBuilders.post("/tickets/job") + .contentType(MediaType.APPLICATION_JSON) + ).andExpect(MockMvcResultMatchers.status().isForbidden()); + } + + @Test + void returnsTicketByJob() throws Exception { + this.mvc.perform( + MockMvcRequestBuilders.get("/tickets/job") + .param("job", "path/to/job") + .param("repo", "user/repo") + .with(SecurityMockMvcRequestPostProcessors.jwt()) + .contentType(MediaType.APPLICATION_JSON) + ).andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void returnsTicketByIssueNumber() throws Exception { + this.mvc.perform( + MockMvcRequestBuilders.get("/tickets/number") + .param("number", "1") + .param("repo", "user/repo") + .with(SecurityMockMvcRequestPostProcessors.jwt()) + .contentType(MediaType.APPLICATION_JSON) + ).andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void createsNewTicket() throws Exception { + this.mvc.perform( + MockMvcRequestBuilders.post("/tickets") + .with(SecurityMockMvcRequestPostProcessors.jwt()) + .contentType(MediaType.APPLICATION_JSON) + .content( + new Jocument( + new JsonOf( + new ResourceOf("data/ticket.json").stream() + ) + ).toString() + ) + ).andExpect(MockMvcResultMatchers.status().isCreated()); + } + + @Test + void throwsOnInvalidRequestBody() throws Exception { + this.mvc.perform( + MockMvcRequestBuilders.post("/tickets") + .with(SecurityMockMvcRequestPostProcessors.jwt()) + .contentType(MediaType.APPLICATION_JSON) + .content( + new Jocument( + new JsonOf( + new ResourceOf("data/no-issue-ticket.json").stream() + ) + ).toString() + ) + ).andExpect(MockMvcResultMatchers.status().isBadRequest()) + .andExpect( + MockMvcResultMatchers.content().string( + new MutableJson() + .with("message", "Issue number can't be null") + .toString() + ) + ); + } + +} diff --git a/src/test/java/git/tracehub/pmo/request/ProjectFromReqTest.java b/src/test/java/git/tracehub/pmo/request/ProjectFromReqTest.java new file mode 100644 index 0000000..82745c6 --- /dev/null +++ b/src/test/java/git/tracehub/pmo/request/ProjectFromReqTest.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package git.tracehub.pmo.request; + +import git.tracehub.pmo.controller.request.ProjectFromReq; +import git.tracehub.pmo.controller.request.RqProject; +import git.tracehub.pmo.project.Project; +import java.util.UUID; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Test; + +/** + * Test suite for {@link ProjectFromReq}. + * + * @since 0.0.0 + */ +final class ProjectFromReqTest { + + @Test + void createsProjectFromRequest() { + final Project expected = new Project( + UUID.randomUUID(), + "Test Project", + "Location", + "Description", + true + ); + final Project project = new ProjectFromReq( + new RqProject( + expected.getName(), + expected.getLocation(), + expected.getDescription(), + expected.isActive() + ) + ).value(); + MatcherAssert.assertThat( + "Project %s is null".formatted(project), + true, + Matchers.notNullValue() + ); + MatcherAssert.assertThat( + "Project %s isn't correct".formatted(project), + project, + Matchers.samePropertyValuesAs(expected, "id") + ); + } + +} diff --git a/src/test/java/git/tracehub/pmo/request/package-info.java b/src/test/java/git/tracehub/pmo/request/package-info.java new file mode 100644 index 0000000..c031096 --- /dev/null +++ b/src/test/java/git/tracehub/pmo/request/package-info.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * Request Tests. + * + * @since 0.0.0 + */ +package git.tracehub.pmo.request; From 92cb531e101723c65f19709d16985056e9122dfd Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Thu, 8 Feb 2024 18:53:08 +0300 Subject: [PATCH 12/29] It tests for database --- src/test/java/it/database/DefaultProjectsIT.java | 5 +++++ src/test/java/it/database/DefaultTicketsIT.java | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/test/java/it/database/DefaultProjectsIT.java b/src/test/java/it/database/DefaultProjectsIT.java index 755b238..9e2c1b1 100644 --- a/src/test/java/it/database/DefaultProjectsIT.java +++ b/src/test/java/it/database/DefaultProjectsIT.java @@ -111,6 +111,11 @@ void employsProject() { true, Matchers.notNullValue() ); + MatcherAssert.assertThat( + "Project %s isn't correct".formatted(project), + project, + Matchers.samePropertyValuesAs(expected, "id") + ); } } diff --git a/src/test/java/it/database/DefaultTicketsIT.java b/src/test/java/it/database/DefaultTicketsIT.java index df7343c..5398800 100644 --- a/src/test/java/it/database/DefaultTicketsIT.java +++ b/src/test/java/it/database/DefaultTicketsIT.java @@ -119,6 +119,11 @@ void createsTicket() { true, Matchers.notNullValue() ); + MatcherAssert.assertThat( + "Ticket name %s isn't correct".formatted(ticket), + ticket, + Matchers.samePropertyValuesAs(expected, "id") + ); } } From dc6907d958ca4e8c1dd82c29ab68620251efd80a Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Thu, 8 Feb 2024 18:53:21 +0300 Subject: [PATCH 13/29] It tests for controllers --- src/test/java/it/web/CreateTicketITCase.java | 139 ++++++++++++++++++ .../it/web/RetrieveProjectByIdITCase.java | 6 +- .../it/web/RetrieveProjectsByUserITCase.java | 2 +- .../it/web/RetrieveTicketByJobITCase.java | 89 +++++++++++ .../it/web/RetrieveTicketByNumberITCase.java | 89 +++++++++++ src/test/resources/data/no-issue-ticket.json | 6 + src/test/resources/data/no-name-project.json | 4 + src/test/resources/data/ticket.json | 7 + 8 files changed, 339 insertions(+), 3 deletions(-) create mode 100644 src/test/java/it/web/CreateTicketITCase.java create mode 100644 src/test/java/it/web/RetrieveTicketByJobITCase.java create mode 100644 src/test/java/it/web/RetrieveTicketByNumberITCase.java create mode 100644 src/test/resources/data/no-issue-ticket.json create mode 100644 src/test/resources/data/no-name-project.json create mode 100644 src/test/resources/data/ticket.json diff --git a/src/test/java/it/web/CreateTicketITCase.java b/src/test/java/it/web/CreateTicketITCase.java new file mode 100644 index 0000000..c334b72 --- /dev/null +++ b/src/test/java/it/web/CreateTicketITCase.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package it.web; + +import com.jcabi.http.Request; +import com.jcabi.http.Response; +import com.jcabi.http.request.JdkRequest; +import git.tracehub.pmo.PmoApplication; +import git.tracehub.pmo.controller.TicketController; +import io.github.eocqrs.eokson.Jocument; +import io.github.eocqrs.eokson.JsonOf; +import io.github.eocqrs.eokson.MutableJson; +import it.KeycloakIntegration; +import it.PostgresIntegration; +import org.cactoos.io.ResourceOf; +import org.hamcrest.MatcherAssert; +import org.hamcrest.core.IsEqual; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.jdbc.Sql; + +/** + * Integration Test Case for Creating Ticket + * from {@link TicketController}. + * + * @since 0.0.0 + */ +@ActiveProfiles("pgit") +@SpringBootTest( + classes = PmoApplication.class, + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT +) +@SuppressWarnings("JTCOP.RuleAllTestsHaveProductionClass") +final class CreateTicketITCase + implements KeycloakIntegration, PostgresIntegration { + + /** + * Raw Endpoint. + */ + private static final String RAW = "http://localhost:%s/tickets"; + + /** + * Application Port. + */ + @LocalServerPort + private int port; + + @Test + @Sql("classpath:pre/sql/projects.sql") + void createsTicketSuccessfully() throws Exception { + final Response response = new JdkRequest( + CreateTicketITCase.RAW.formatted(this.port) + ).method(Request.POST) + .body() + .set( + new Jocument( + new JsonOf( + new ResourceOf("data/ticket.json").stream() + ) + ).toString() + ).back() + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .header( + HttpHeaders.AUTHORIZATION, + "Bearer %s".formatted( + new KeycloakToken( + KeycloakIntegration.KEYCLOAK.getAuthServerUrl() + ).value() + ) + ).fetch(); + MatcherAssert.assertThat( + "Response Status %s does not match to expected one".formatted( + response.status() + ), + response.status(), + new IsEqual<>(201) + ); + } + + @Test + void throwsOnInvalidRequestBody() throws Exception { + final Response response = new JdkRequest( + CreateTicketITCase.RAW.formatted(this.port) + ).method(Request.POST) + .body() + .set( + new Jocument( + new JsonOf( + new ResourceOf("data/no-issue-ticket.json").stream() + ) + ).toString() + ).back() + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .header( + HttpHeaders.AUTHORIZATION, + "Bearer %s".formatted( + new KeycloakToken( + KeycloakIntegration.KEYCLOAK.getAuthServerUrl() + ).value() + ) + ).fetch(); + MatcherAssert.assertThat( + "Response Status %s does not match to expected one".formatted( + response.status() + ), + response.status(), + new IsEqual<>(400) + ); + MatcherAssert.assertThat( + "Message %s isn't correct".formatted(response.body()), + response.body(), + new IsEqual<>( + new MutableJson() + .with("message", "Issue number can't be null") + .toString() + ) + ); + } + +} diff --git a/src/test/java/it/web/RetrieveProjectByIdITCase.java b/src/test/java/it/web/RetrieveProjectByIdITCase.java index 936e626..8ae5a39 100644 --- a/src/test/java/it/web/RetrieveProjectByIdITCase.java +++ b/src/test/java/it/web/RetrieveProjectByIdITCase.java @@ -21,6 +21,7 @@ import com.jcabi.http.Response; import com.jcabi.http.request.JdkRequest; import git.tracehub.pmo.PmoApplication; +import git.tracehub.pmo.controller.ProjectController; import it.KeycloakIntegration; import it.PostgresIntegration; import org.hamcrest.MatcherAssert; @@ -34,7 +35,7 @@ /** * Integration Test Case for Retrieving Project by Id - * from {@link git.tracehub.pmo.controller.ProjectController}. + * from {@link ProjectController}. * * @since 0.0.0 */ @@ -50,7 +51,8 @@ final class RetrieveProjectByIdITCase /** * Raw Endpoint. */ - private static final String RAW = "http://localhost:%s/74bb5ec8-0e6b-4618-bfa4-a0b76b7b312d"; + private static final String RAW = + "http://localhost:%s/projects/74bb5ec8-0e6b-4618-bfa4-a0b76b7b312d"; /** * Application Port. diff --git a/src/test/java/it/web/RetrieveProjectsByUserITCase.java b/src/test/java/it/web/RetrieveProjectsByUserITCase.java index f08dcbf..44db668 100644 --- a/src/test/java/it/web/RetrieveProjectsByUserITCase.java +++ b/src/test/java/it/web/RetrieveProjectsByUserITCase.java @@ -50,7 +50,7 @@ final class RetrieveProjectsByUserITCase /** * Raw Endpoint. */ - private static final String RAW = "http://localhost:%s"; + private static final String RAW = "http://localhost:%s/projects"; /** * Application Port. diff --git a/src/test/java/it/web/RetrieveTicketByJobITCase.java b/src/test/java/it/web/RetrieveTicketByJobITCase.java new file mode 100644 index 0000000..5068aa7 --- /dev/null +++ b/src/test/java/it/web/RetrieveTicketByJobITCase.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package it.web; + +import com.jcabi.http.Request; +import com.jcabi.http.Response; +import com.jcabi.http.request.JdkRequest; +import git.tracehub.pmo.PmoApplication; +import git.tracehub.pmo.controller.TicketController; +import it.KeycloakIntegration; +import it.PostgresIntegration; +import org.hamcrest.MatcherAssert; +import org.hamcrest.core.IsEqual; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.http.HttpHeaders; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.jdbc.Sql; + +/** + * Integration Test Case for Retrieving Ticket by Job and Repository + * from {@link TicketController}. + * + * @since 0.0.0 + */ +@ActiveProfiles("pgit") +@SpringBootTest( + classes = PmoApplication.class, + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT +) +@SuppressWarnings("JTCOP.RuleAllTestsHaveProductionClass") +final class RetrieveTicketByJobITCase + implements KeycloakIntegration, PostgresIntegration { + + /** + * Raw Endpoint. + */ + private static final String RAW = "http://localhost:%s/tickets/job"; + + /** + * Application Port. + */ + @LocalServerPort + private int port; + + @Test + @Sql("classpath:pre/sql/projects.sql") + void retrievesTicketByJobSuccessfully() throws Exception { + final Response response = new JdkRequest( + RetrieveTicketByJobITCase.RAW.formatted(this.port) + ).uri() + .queryParam("job", "path/to/job") + .queryParam("repo", "user/test") + .back() + .method(Request.GET) + .header( + HttpHeaders.AUTHORIZATION, + "Bearer %s".formatted( + new KeycloakToken( + KeycloakIntegration.KEYCLOAK.getAuthServerUrl() + ).value() + ) + ).fetch(); + MatcherAssert.assertThat( + "Response Status %s does not match to expected one".formatted( + response.status() + ), + response.status(), + new IsEqual<>(200) + ); + } + +} diff --git a/src/test/java/it/web/RetrieveTicketByNumberITCase.java b/src/test/java/it/web/RetrieveTicketByNumberITCase.java new file mode 100644 index 0000000..58b7bd3 --- /dev/null +++ b/src/test/java/it/web/RetrieveTicketByNumberITCase.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package it.web; + +import com.jcabi.http.Request; +import com.jcabi.http.Response; +import com.jcabi.http.request.JdkRequest; +import git.tracehub.pmo.PmoApplication; +import git.tracehub.pmo.controller.TicketController; +import it.KeycloakIntegration; +import it.PostgresIntegration; +import org.hamcrest.MatcherAssert; +import org.hamcrest.core.IsEqual; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.http.HttpHeaders; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.jdbc.Sql; + +/** + * Integration Test Case for Retrieving Ticket by Number and Repository + * from {@link TicketController}. + * + * @since 0.0.0 + */ +@ActiveProfiles("pgit") +@SpringBootTest( + classes = PmoApplication.class, + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT +) +@SuppressWarnings("JTCOP.RuleAllTestsHaveProductionClass") +final class RetrieveTicketByNumberITCase + implements KeycloakIntegration, PostgresIntegration { + + /** + * Raw Endpoint. + */ + private static final String RAW = "http://localhost:%s/tickets/number"; + + /** + * Application Port. + */ + @LocalServerPort + private int port; + + @Test + @Sql("classpath:pre/sql/projects.sql") + void retrievesTicketByJobSuccessfully() throws Exception { + final Response response = new JdkRequest( + RetrieveTicketByNumberITCase.RAW.formatted(this.port) + ).uri() + .queryParam("number", 1) + .queryParam("repo", "user/test") + .back() + .method(Request.GET) + .header( + HttpHeaders.AUTHORIZATION, + "Bearer %s".formatted( + new KeycloakToken( + KeycloakIntegration.KEYCLOAK.getAuthServerUrl() + ).value() + ) + ).fetch(); + MatcherAssert.assertThat( + "Response Status %s does not match to expected one".formatted( + response.status() + ), + response.status(), + new IsEqual<>(200) + ); + } + +} diff --git a/src/test/resources/data/no-issue-ticket.json b/src/test/resources/data/no-issue-ticket.json new file mode 100644 index 0000000..101cd90 --- /dev/null +++ b/src/test/resources/data/no-issue-ticket.json @@ -0,0 +1,6 @@ +{ + "project": "74bb5ec8-0e6b-4618-bfa4-a0b76b7b312d", + "repo": "user/repo", + "job": "path/to/job", + "status": "OPENED" +} \ No newline at end of file diff --git a/src/test/resources/data/no-name-project.json b/src/test/resources/data/no-name-project.json new file mode 100644 index 0000000..f53063c --- /dev/null +++ b/src/test/resources/data/no-name-project.json @@ -0,0 +1,4 @@ +{ + "active": true, + "location": "github@hizmailovich/draft:master" +} \ No newline at end of file diff --git a/src/test/resources/data/ticket.json b/src/test/resources/data/ticket.json new file mode 100644 index 0000000..60cedeb --- /dev/null +++ b/src/test/resources/data/ticket.json @@ -0,0 +1,7 @@ +{ + "project": "74bb5ec8-0e6b-4618-bfa4-a0b76b7b312d", + "number": 1, + "repo": "user/repo", + "job": "path/to/job", + "status": "OPENED" +} \ No newline at end of file From 0e52ba8fb74277cf899cba11fae410f6d9534f64 Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Fri, 9 Feb 2024 16:09:40 +0300 Subject: [PATCH 14/29] AccessDenied exception hanlked --- .../pmo/controller/AdviceController.java | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/main/java/git/tracehub/pmo/controller/AdviceController.java b/src/main/java/git/tracehub/pmo/controller/AdviceController.java index 2501cd4..b1675c9 100644 --- a/src/main/java/git/tracehub/pmo/controller/AdviceController.java +++ b/src/main/java/git/tracehub/pmo/controller/AdviceController.java @@ -25,6 +25,7 @@ import org.springframework.context.support.DefaultMessageSourceResolvable; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.AccessDeniedException; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; @@ -33,8 +34,8 @@ /** * Exception handler. * + * @checkstyle NonStaticMethodCheck (90 lines) * @since 0.0.0 - * @checkstyle NonStaticMethodCheck (70 lines) */ @Slf4j @RestControllerAdvice @@ -88,6 +89,27 @@ public ResponseEntity handle( ); } + /** + * Handle AccessDeniedException. + * + * @param exception Exception + * @return ResponseEntity + */ + @ExceptionHandler(AccessDeniedException.class) + @ResponseStatus(HttpStatus.FORBIDDEN) + public ResponseEntity handle( + final AccessDeniedException exception + ) { + log.warn(exception.getMessage(), exception); + return new ResponseEntity<>( + new Jocument( + new MutableJson() + .with("message", exception.getMessage()) + ).byteArray(), + HttpStatus.FORBIDDEN + ); + } + /** * Handle Exception. * From f5f4944c60ce12a86c8275d093ffce0daff214a7 Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Fri, 9 Feb 2024 16:09:48 +0300 Subject: [PATCH 15/29] Tests fixed --- .../git/tracehub/pmo/database/JdbcTest.java | 1 - .../pmo/project/DefaultProjectsTest.java | 18 ++++++++ .../tracehub/pmo/project/ProjectOfTest.java | 13 ++++++ .../pmo/ticket/DefaultTicketsTest.java | 21 ++++++++- .../git/tracehub/pmo/ticket/TicketOfTest.java | 13 ++++++ .../it/web/RetrieveProjectByIdITCase.java | 43 +++++++++++++++++-- .../it/web/RetrieveTicketByJobITCase.java | 41 ++++++++++++++++++ .../it/web/RetrieveTicketByNumberITCase.java | 41 ++++++++++++++++++ 8 files changed, 186 insertions(+), 5 deletions(-) diff --git a/src/test/java/git/tracehub/pmo/database/JdbcTest.java b/src/test/java/git/tracehub/pmo/database/JdbcTest.java index 7b49739..e3459bd 100644 --- a/src/test/java/git/tracehub/pmo/database/JdbcTest.java +++ b/src/test/java/git/tracehub/pmo/database/JdbcTest.java @@ -68,7 +68,6 @@ public class JdbcTest { * @throws SQLException If something goes wrong */ protected void mockResultSet(final Ticket ticket) throws SQLException { - Mockito.when(this.set.next()).thenReturn(true); Mockito.when(this.set.getString("id")) .thenReturn(ticket.getId().toString()); Mockito.when(this.set.getString("project")) diff --git a/src/test/java/git/tracehub/pmo/project/DefaultProjectsTest.java b/src/test/java/git/tracehub/pmo/project/DefaultProjectsTest.java index 632ea80..705a6f6 100644 --- a/src/test/java/git/tracehub/pmo/project/DefaultProjectsTest.java +++ b/src/test/java/git/tracehub/pmo/project/DefaultProjectsTest.java @@ -135,4 +135,22 @@ void throwsOnInvalidProjectId() throws SQLException { ).affirm(); } + @Test + @SuppressWarnings("JTCOP.RuleAssertionMessage") + void throwsOnCreatingInvalidProject() throws SQLException { + Mockito.when(super.set.next()).thenThrow(SQLException.class); + new Assertion<>( + "Exception is not thrown or valid", + () -> this.projects.employ( + new Project( + "Test Project", + "Location", + "Description", + true + ) + ), + new Throws<>(SQLException.class) + ).affirm(); + } + } diff --git a/src/test/java/git/tracehub/pmo/project/ProjectOfTest.java b/src/test/java/git/tracehub/pmo/project/ProjectOfTest.java index ba5612e..52f07b4 100644 --- a/src/test/java/git/tracehub/pmo/project/ProjectOfTest.java +++ b/src/test/java/git/tracehub/pmo/project/ProjectOfTest.java @@ -25,6 +25,8 @@ import org.hamcrest.core.IsEqual; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.llorllale.cactoos.matchers.Assertion; +import org.llorllale.cactoos.matchers.Throws; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; @@ -75,4 +77,15 @@ void returnsProjectWithAllFields() throws SQLException { ); } + @Test + void throwsOnInvalidResultSet() throws SQLException { + Mockito.when(this.set.getString("id")) + .thenThrow(SQLException.class); + new Assertion<>( + "Exception is not thrown or valid", + () -> new ProjectOf(this.set).value(), + new Throws<>(SQLException.class) + ).affirm(); + } + } diff --git a/src/test/java/git/tracehub/pmo/ticket/DefaultTicketsTest.java b/src/test/java/git/tracehub/pmo/ticket/DefaultTicketsTest.java index 73feca7..86e4d54 100644 --- a/src/test/java/git/tracehub/pmo/ticket/DefaultTicketsTest.java +++ b/src/test/java/git/tracehub/pmo/ticket/DefaultTicketsTest.java @@ -130,7 +130,7 @@ void createsTicket() throws SQLException { @Test @SuppressWarnings("JTCOP.RuleAssertionMessage") void throwsOnInvalidJob() throws SQLException { - final String job = "path/to/job"; + final String job = "invalid/path/to/job"; final String repo = "repo"; Mockito.when(super.set.next()).thenReturn(false); new Assertion<>( @@ -159,4 +159,23 @@ void throwsOnInvalidIssueNumber() throws SQLException { ).affirm(); } + @Test + @SuppressWarnings("JTCOP.RuleAssertionMessage") + void throwsOnCreatingInvalidTicket() throws SQLException { + Mockito.when(super.set.next()).thenThrow(SQLException.class); + new Assertion<>( + "Exception is not thrown or valid", + () -> this.tickets.create( + new Ticket( + UUID.randomUUID(), + 35, + "user/repo", + "invalid/path/to/job", + Ticket.Status.OPENED + ) + ), + new Throws<>(SQLException.class) + ).affirm(); + } + } diff --git a/src/test/java/git/tracehub/pmo/ticket/TicketOfTest.java b/src/test/java/git/tracehub/pmo/ticket/TicketOfTest.java index 36e8265..cadefa9 100644 --- a/src/test/java/git/tracehub/pmo/ticket/TicketOfTest.java +++ b/src/test/java/git/tracehub/pmo/ticket/TicketOfTest.java @@ -25,6 +25,8 @@ import org.hamcrest.core.IsEqual; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.llorllale.cactoos.matchers.Assertion; +import org.llorllale.cactoos.matchers.Throws; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; @@ -78,4 +80,15 @@ void returnsTicketWithAllFields() throws SQLException { ); } + @Test + void throwsOnInvalidResultSet() throws SQLException { + Mockito.when(this.set.getString("id")) + .thenThrow(SQLException.class); + new Assertion<>( + "Exception is not thrown or valid", + () -> new TicketOf(this.set).value(), + new Throws<>(SQLException.class) + ).affirm(); + } + } diff --git a/src/test/java/it/web/RetrieveProjectByIdITCase.java b/src/test/java/it/web/RetrieveProjectByIdITCase.java index 8ae5a39..fa34fd4 100644 --- a/src/test/java/it/web/RetrieveProjectByIdITCase.java +++ b/src/test/java/it/web/RetrieveProjectByIdITCase.java @@ -22,6 +22,7 @@ import com.jcabi.http.request.JdkRequest; import git.tracehub.pmo.PmoApplication; import git.tracehub.pmo.controller.ProjectController; +import io.github.eocqrs.eokson.MutableJson; import it.KeycloakIntegration; import it.PostgresIntegration; import org.hamcrest.MatcherAssert; @@ -51,8 +52,7 @@ final class RetrieveProjectByIdITCase /** * Raw Endpoint. */ - private static final String RAW = - "http://localhost:%s/projects/74bb5ec8-0e6b-4618-bfa4-a0b76b7b312d"; + private static final String RAW = "http://localhost:%s/projects/%s"; /** * Application Port. @@ -64,7 +64,10 @@ final class RetrieveProjectByIdITCase @Sql("classpath:pre/sql/projects.sql") void retrievesProjectByIdSuccessfully() throws Exception { final Response response = new JdkRequest( - RetrieveProjectByIdITCase.RAW.formatted(this.port) + RetrieveProjectByIdITCase.RAW.formatted( + this.port, + "74bb5ec8-0e6b-4618-bfa4-a0b76b7b312d" + ) ).method(Request.GET) .header( HttpHeaders.AUTHORIZATION, @@ -83,4 +86,38 @@ void retrievesProjectByIdSuccessfully() throws Exception { ); } + @Test + void throwsOnInvalidProjectId() throws Exception { + final Response response = new JdkRequest( + RetrieveProjectByIdITCase.RAW.formatted( + this.port, + "22bb5ec8-0e6b-4618-bfa4-a0b76b7b312d" + ) + ).method(Request.GET) + .header( + HttpHeaders.AUTHORIZATION, + "Bearer %s".formatted( + new KeycloakToken( + KeycloakIntegration.KEYCLOAK.getAuthServerUrl() + ).value() + ) + ).fetch(); + MatcherAssert.assertThat( + "Response Status %s does not match to expected one".formatted( + response.status() + ), + response.status(), + new IsEqual<>(403) + ); + MatcherAssert.assertThat( + "Message %s isn't correct".formatted(response.body()), + response.body(), + new IsEqual<>( + new MutableJson() + .with("message", "Access Denied") + .toString() + ) + ); + } + } diff --git a/src/test/java/it/web/RetrieveTicketByJobITCase.java b/src/test/java/it/web/RetrieveTicketByJobITCase.java index 5068aa7..68993dc 100644 --- a/src/test/java/it/web/RetrieveTicketByJobITCase.java +++ b/src/test/java/it/web/RetrieveTicketByJobITCase.java @@ -22,6 +22,7 @@ import com.jcabi.http.request.JdkRequest; import git.tracehub.pmo.PmoApplication; import git.tracehub.pmo.controller.TicketController; +import io.github.eocqrs.eokson.MutableJson; import it.KeycloakIntegration; import it.PostgresIntegration; import org.hamcrest.MatcherAssert; @@ -86,4 +87,44 @@ void retrievesTicketByJobSuccessfully() throws Exception { ); } + @Test + void throwsOnInvalidJob() throws Exception { + final String job = "invalid/path/to/job"; + final String repo = "user/test"; + final Response response = new JdkRequest( + RetrieveTicketByJobITCase.RAW.formatted(this.port) + ).uri() + .queryParam("job", job) + .queryParam("repo", repo) + .back() + .method(Request.GET) + .header( + HttpHeaders.AUTHORIZATION, + "Bearer %s".formatted( + new KeycloakToken( + KeycloakIntegration.KEYCLOAK.getAuthServerUrl() + ).value() + ) + ).fetch(); + MatcherAssert.assertThat( + "Response Status %s does not match to expected one".formatted( + response.status() + ), + response.status(), + new IsEqual<>(404) + ); + MatcherAssert.assertThat( + "Message %s isn't correct".formatted(response.body()), + response.body(), + new IsEqual<>( + new MutableJson() + .with( + "message", + "Ticket with job = %s and repo = %s not found" + .formatted(job, repo) + ).toString() + ) + ); + } + } diff --git a/src/test/java/it/web/RetrieveTicketByNumberITCase.java b/src/test/java/it/web/RetrieveTicketByNumberITCase.java index 58b7bd3..61a52c4 100644 --- a/src/test/java/it/web/RetrieveTicketByNumberITCase.java +++ b/src/test/java/it/web/RetrieveTicketByNumberITCase.java @@ -22,6 +22,7 @@ import com.jcabi.http.request.JdkRequest; import git.tracehub.pmo.PmoApplication; import git.tracehub.pmo.controller.TicketController; +import io.github.eocqrs.eokson.MutableJson; import it.KeycloakIntegration; import it.PostgresIntegration; import org.hamcrest.MatcherAssert; @@ -86,4 +87,44 @@ void retrievesTicketByJobSuccessfully() throws Exception { ); } + @Test + void throwsOnInvalidNumber() throws Exception { + final int number = 0; + final String repo = "user/test"; + final Response response = new JdkRequest( + RetrieveTicketByNumberITCase.RAW.formatted(this.port) + ).uri() + .queryParam("number", number) + .queryParam("repo", repo) + .back() + .method(Request.GET) + .header( + HttpHeaders.AUTHORIZATION, + "Bearer %s".formatted( + new KeycloakToken( + KeycloakIntegration.KEYCLOAK.getAuthServerUrl() + ).value() + ) + ).fetch(); + MatcherAssert.assertThat( + "Response Status %s does not match to expected one".formatted( + response.status() + ), + response.status(), + new IsEqual<>(404) + ); + MatcherAssert.assertThat( + "Message %s isn't correct".formatted(response.body()), + response.body(), + new IsEqual<>( + new MutableJson() + .with( + "message", + "Ticket with issue = %s and repo = %s not found" + .formatted(number, repo) + ).toString() + ) + ); + } + } From 4a191655a5ce46b1fa5125643335004175930c22 Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Tue, 13 Feb 2024 13:27:09 +0300 Subject: [PATCH 16/29] Inheritance removed --- .../git/tracehub/pmo/database/JdbcTest.java | 123 ------------------ .../tracehub/pmo/database/package-info.java | 23 ---- .../pmo/project/DefaultProjectsTest.java | 81 ++++++++++-- .../pmo/ticket/DefaultTicketsTest.java | 85 ++++++++++-- 4 files changed, 145 insertions(+), 167 deletions(-) delete mode 100644 src/test/java/git/tracehub/pmo/database/JdbcTest.java delete mode 100644 src/test/java/git/tracehub/pmo/database/package-info.java diff --git a/src/test/java/git/tracehub/pmo/database/JdbcTest.java b/src/test/java/git/tracehub/pmo/database/JdbcTest.java deleted file mode 100644 index e3459bd..0000000 --- a/src/test/java/git/tracehub/pmo/database/JdbcTest.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2023-2024 Tracehub.git - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to read - * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package git.tracehub.pmo.database; - -import git.tracehub.pmo.project.Project; -import git.tracehub.pmo.ticket.Ticket; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import javax.sql.DataSource; -import org.junit.jupiter.api.BeforeEach; -import org.mockito.Mock; -import org.mockito.Mockito; - -/** - * Jdbc test. - * - * @since 0.0.0 - */ -public class JdbcTest { - - /** - * Result set. - * - * @checkstyle VisibilityModifierCheck (3 lines) - */ - @Mock - protected ResultSet set; - - /** - * Datasource. - */ - @Mock - private DataSource source; - - /** - * Connection. - */ - @Mock - private Connection connection; - - /** - * Statement. - */ - @Mock - private PreparedStatement statement; - - /** - * Mock result set. - * - * @param ticket Ticket - * @throws SQLException If something goes wrong - */ - protected void mockResultSet(final Ticket ticket) throws SQLException { - Mockito.when(this.set.getString("id")) - .thenReturn(ticket.getId().toString()); - Mockito.when(this.set.getString("project")) - .thenReturn(ticket.getProject().toString()); - Mockito.when(this.set.getInt("number")) - .thenReturn(ticket.getNumber()); - Mockito.when(this.set.getString("repo")) - .thenReturn(ticket.getRepo()); - Mockito.when(this.set.getString("job")) - .thenReturn(ticket.getJob()); - Mockito.when(this.set.getString("status")) - .thenReturn(ticket.getStatus().name()); - } - - /** - * Mock result set. - * - * @param project Project - * @throws SQLException If something goes wrong - */ - protected void mockResultSet(final Project project) throws SQLException { - Mockito.when(this.set.getString("id")) - .thenReturn(project.getId().toString()); - Mockito.when(this.set.getString("name")) - .thenReturn(project.getName()); - Mockito.when(this.set.getString("location")) - .thenReturn(project.getLocation()); - Mockito.when(this.set.getString("description")) - .thenReturn(project.getDescription()); - Mockito.when(this.set.getBoolean("active")) - .thenReturn(project.isActive()); - } - - /** - * Set datasource and connection. - * - * @throws SQLException If something goes wrong - */ - @BeforeEach - void setConnection() throws SQLException { - Mockito.when(this.source.getConnection()).thenReturn(this.connection); - Mockito.doNothing().when(this.connection).setAutoCommit(true); - Mockito.lenient().when(this.connection.prepareStatement(Mockito.anyString())) - .thenReturn(this.statement); - Mockito.lenient() - .when(this.connection.prepareStatement(Mockito.anyString(), Mockito.anyInt())) - .thenReturn(this.statement); - Mockito.doNothing().when(this.statement).close(); - Mockito.lenient().when(this.statement.executeQuery()).thenReturn(this.set); - Mockito.lenient().when(this.statement.getGeneratedKeys()).thenReturn(this.set); - } - -} diff --git a/src/test/java/git/tracehub/pmo/database/package-info.java b/src/test/java/git/tracehub/pmo/database/package-info.java deleted file mode 100644 index 3f0be36..0000000 --- a/src/test/java/git/tracehub/pmo/database/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2023-2024 Tracehub.git - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to read - * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/** - * Database Tests. - * - * @since 0.0.0 - */ -package git.tracehub.pmo.database; diff --git a/src/test/java/git/tracehub/pmo/project/DefaultProjectsTest.java b/src/test/java/git/tracehub/pmo/project/DefaultProjectsTest.java index 705a6f6..902157b 100644 --- a/src/test/java/git/tracehub/pmo/project/DefaultProjectsTest.java +++ b/src/test/java/git/tracehub/pmo/project/DefaultProjectsTest.java @@ -17,19 +17,24 @@ package git.tracehub.pmo.project; -import git.tracehub.pmo.database.JdbcTest; import git.tracehub.pmo.exception.ResourceNotFoundException; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import java.util.UUID; +import javax.sql.DataSource; import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; import org.hamcrest.core.IsEqual; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.llorllale.cactoos.matchers.Assertion; import org.llorllale.cactoos.matchers.Throws; import org.mockito.InjectMocks; +import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; @@ -39,7 +44,31 @@ * @since 0.0.0 */ @ExtendWith(MockitoExtension.class) -final class DefaultProjectsTest extends JdbcTest { +final class DefaultProjectsTest { + + /** + * Result set. + */ + @Mock + private ResultSet set; + + /** + * Datasource. + */ + @Mock + private DataSource source; + + /** + * Connection. + */ + @Mock + private Connection connection; + + /** + * Statement. + */ + @Mock + private PreparedStatement statement; /** * Default tickets. @@ -47,6 +76,25 @@ final class DefaultProjectsTest extends JdbcTest { @InjectMocks private DefaultProjects projects; + /** + * Set datasource and connection. + * + * @throws SQLException If something goes wrong + */ + @BeforeEach + void setConnection() throws SQLException { + Mockito.when(this.source.getConnection()).thenReturn(this.connection); + Mockito.doNothing().when(this.connection).setAutoCommit(true); + Mockito.lenient().when(this.connection.prepareStatement(Mockito.anyString())) + .thenReturn(this.statement); + Mockito.lenient() + .when(this.connection.prepareStatement(Mockito.anyString(), Mockito.anyInt())) + .thenReturn(this.statement); + Mockito.doNothing().when(this.statement).close(); + Mockito.lenient().when(this.statement.executeQuery()).thenReturn(this.set); + Mockito.lenient().when(this.statement.getGeneratedKeys()).thenReturn(this.set); + } + @Test void returnsProjectById() throws SQLException { final Project expected = new Project( @@ -56,8 +104,8 @@ void returnsProjectById() throws SQLException { "Description", true ); - super.mockResultSet(expected); - Mockito.when(super.set.next()).thenReturn(true); + this.mock(expected); + Mockito.when(this.set.next()).thenReturn(true); final Project project = this.projects.byId(expected.getId()); MatcherAssert.assertThat( "Project %s is null".formatted(project), @@ -81,8 +129,8 @@ void returnsProjectsByUser() throws SQLException { "Description", true ); - super.mockResultSet(expected); - Mockito.when(super.set.next()).thenReturn(true, false); + this.mock(expected); + Mockito.when(this.set.next()).thenReturn(true, false); final List actual = this.projects.byUser(email); MatcherAssert.assertThat( "List of projects %s is null".formatted(actual), @@ -105,8 +153,8 @@ void employsProject() throws SQLException { "Description", true ); - super.mockResultSet(expected); - Mockito.when(super.set.next()).thenReturn(true); + this.mock(expected); + Mockito.when(this.set.next()).thenReturn(true); final Project project = this.projects.employ(expected); MatcherAssert.assertThat( "Project %s is null".formatted(project), @@ -124,7 +172,7 @@ void employsProject() throws SQLException { @SuppressWarnings("JTCOP.RuleAssertionMessage") void throwsOnInvalidProjectId() throws SQLException { final UUID id = UUID.randomUUID(); - Mockito.when(super.set.next()).thenReturn(false); + Mockito.when(this.set.next()).thenReturn(false); new Assertion<>( "Exception is not thrown or valid", () -> this.projects.byId(id), @@ -138,7 +186,7 @@ void throwsOnInvalidProjectId() throws SQLException { @Test @SuppressWarnings("JTCOP.RuleAssertionMessage") void throwsOnCreatingInvalidProject() throws SQLException { - Mockito.when(super.set.next()).thenThrow(SQLException.class); + Mockito.when(this.set.next()).thenThrow(SQLException.class); new Assertion<>( "Exception is not thrown or valid", () -> this.projects.employ( @@ -153,4 +201,17 @@ void throwsOnCreatingInvalidProject() throws SQLException { ).affirm(); } + private void mock(final Project project) throws SQLException { + Mockito.when(this.set.getString("id")) + .thenReturn(project.getId().toString()); + Mockito.when(this.set.getString("name")) + .thenReturn(project.getName()); + Mockito.when(this.set.getString("location")) + .thenReturn(project.getLocation()); + Mockito.when(this.set.getString("description")) + .thenReturn(project.getDescription()); + Mockito.when(this.set.getBoolean("active")) + .thenReturn(project.isActive()); + } + } diff --git a/src/test/java/git/tracehub/pmo/ticket/DefaultTicketsTest.java b/src/test/java/git/tracehub/pmo/ticket/DefaultTicketsTest.java index 86e4d54..b6882bc 100644 --- a/src/test/java/git/tracehub/pmo/ticket/DefaultTicketsTest.java +++ b/src/test/java/git/tracehub/pmo/ticket/DefaultTicketsTest.java @@ -17,18 +17,23 @@ package git.tracehub.pmo.ticket; -import git.tracehub.pmo.database.JdbcTest; import git.tracehub.pmo.exception.ResourceNotFoundException; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.sql.SQLException; import java.util.UUID; +import javax.sql.DataSource; import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; import org.hamcrest.core.IsEqual; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.llorllale.cactoos.matchers.Assertion; import org.llorllale.cactoos.matchers.Throws; import org.mockito.InjectMocks; +import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; @@ -38,7 +43,31 @@ * @since 0.0.0 */ @ExtendWith(MockitoExtension.class) -final class DefaultTicketsTest extends JdbcTest { +final class DefaultTicketsTest { + + /** + * Result set. + */ + @Mock + private ResultSet set; + + /** + * Datasource. + */ + @Mock + private DataSource source; + + /** + * Connection. + */ + @Mock + private Connection connection; + + /** + * Statement. + */ + @Mock + private PreparedStatement statement; /** * Default tickets. @@ -46,6 +75,25 @@ final class DefaultTicketsTest extends JdbcTest { @InjectMocks private DefaultTickets tickets; + /** + * Set datasource and connection. + * + * @throws SQLException If something goes wrong + */ + @BeforeEach + void setConnection() throws SQLException { + Mockito.when(this.source.getConnection()).thenReturn(this.connection); + Mockito.doNothing().when(this.connection).setAutoCommit(true); + Mockito.lenient().when(this.connection.prepareStatement(Mockito.anyString())) + .thenReturn(this.statement); + Mockito.lenient() + .when(this.connection.prepareStatement(Mockito.anyString(), Mockito.anyInt())) + .thenReturn(this.statement); + Mockito.doNothing().when(this.statement).close(); + Mockito.lenient().when(this.statement.executeQuery()).thenReturn(this.set); + Mockito.lenient().when(this.statement.getGeneratedKeys()).thenReturn(this.set); + } + @Test void returnsTicketByJob() throws SQLException { final Ticket expected = new Ticket( @@ -56,8 +104,8 @@ void returnsTicketByJob() throws SQLException { "path/to/job", Ticket.Status.OPENED ); - super.mockResultSet(expected); - Mockito.when(super.set.next()).thenReturn(true); + this.mock(expected); + Mockito.when(this.set.next()).thenReturn(true); final Ticket ticket = this.tickets.byJob( expected.getJob(), expected.getRepo() @@ -84,8 +132,8 @@ void returnsTicketByIssueNumber() throws SQLException { "path/to/job", Ticket.Status.OPENED ); - super.mockResultSet(expected); - Mockito.when(super.set.next()).thenReturn(true); + this.mock(expected); + Mockito.when(this.set.next()).thenReturn(true); final Ticket ticket = this.tickets.byNumber( expected.getNumber(), expected.getRepo() @@ -112,8 +160,8 @@ void createsTicket() throws SQLException { "path/to/job", Ticket.Status.OPENED ); - super.mockResultSet(expected); - Mockito.when(super.set.next()).thenReturn(true); + this.mock(expected); + Mockito.when(this.set.next()).thenReturn(true); final Ticket ticket = this.tickets.create(expected); MatcherAssert.assertThat( "Ticket %s isn't created".formatted(ticket), @@ -132,7 +180,7 @@ void createsTicket() throws SQLException { void throwsOnInvalidJob() throws SQLException { final String job = "invalid/path/to/job"; final String repo = "repo"; - Mockito.when(super.set.next()).thenReturn(false); + Mockito.when(this.set.next()).thenReturn(false); new Assertion<>( "Exception is not thrown or valid", () -> this.tickets.byJob(job, repo), @@ -148,7 +196,7 @@ void throwsOnInvalidJob() throws SQLException { void throwsOnInvalidIssueNumber() throws SQLException { final int number = 35; final String repo = "repo"; - Mockito.when(super.set.next()).thenReturn(false); + Mockito.when(this.set.next()).thenReturn(false); new Assertion<>( "Exception is not thrown or valid", () -> this.tickets.byNumber(number, repo), @@ -162,7 +210,7 @@ void throwsOnInvalidIssueNumber() throws SQLException { @Test @SuppressWarnings("JTCOP.RuleAssertionMessage") void throwsOnCreatingInvalidTicket() throws SQLException { - Mockito.when(super.set.next()).thenThrow(SQLException.class); + Mockito.when(this.set.next()).thenThrow(SQLException.class); new Assertion<>( "Exception is not thrown or valid", () -> this.tickets.create( @@ -178,4 +226,19 @@ void throwsOnCreatingInvalidTicket() throws SQLException { ).affirm(); } + private void mock(final Ticket ticket) throws SQLException { + Mockito.when(this.set.getString("id")) + .thenReturn(ticket.getId().toString()); + Mockito.when(this.set.getString("project")) + .thenReturn(ticket.getProject().toString()); + Mockito.when(this.set.getInt("number")) + .thenReturn(ticket.getNumber()); + Mockito.when(this.set.getString("repo")) + .thenReturn(ticket.getRepo()); + Mockito.when(this.set.getString("job")) + .thenReturn(ticket.getJob()); + Mockito.when(this.set.getString("status")) + .thenReturn(ticket.getStatus().name()); + } + } From c8a1dcd96eceb8833dcc9cc932ff7a764bc38ea2 Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Tue, 13 Feb 2024 13:27:20 +0300 Subject: [PATCH 17/29] Constructors fixed --- src/main/java/git/tracehub/pmo/project/Project.java | 6 +----- src/main/java/git/tracehub/pmo/ticket/Ticket.java | 7 +------ 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/src/main/java/git/tracehub/pmo/project/Project.java b/src/main/java/git/tracehub/pmo/project/Project.java index 2830a8b..33c9efc 100644 --- a/src/main/java/git/tracehub/pmo/project/Project.java +++ b/src/main/java/git/tracehub/pmo/project/Project.java @@ -27,7 +27,6 @@ * @since 0.0.0 */ @Data -@SuppressWarnings("PMD.OnlyOneConstructorShouldDoInitialization") public class Project { /** @@ -92,9 +91,6 @@ public Project( final String description, final boolean active ) { - this.name = name; - this.location = location; - this.description = description; - this.active = active; + this(null, name, location, description, active); } } diff --git a/src/main/java/git/tracehub/pmo/ticket/Ticket.java b/src/main/java/git/tracehub/pmo/ticket/Ticket.java index a4f642e..2620f79 100644 --- a/src/main/java/git/tracehub/pmo/ticket/Ticket.java +++ b/src/main/java/git/tracehub/pmo/ticket/Ticket.java @@ -27,7 +27,6 @@ * @since 0.0.0 */ @Data -@SuppressWarnings("PMD.OnlyOneConstructorShouldDoInitialization") public class Ticket { /** @@ -119,11 +118,7 @@ public Ticket( final String job, final Status status ) { - this.project = project; - this.number = number; - this.repo = repo; - this.job = job; - this.status = status; + this(null, project, number, repo, job, status); } } From e62950fada718c44d2ab43aae8e0713f55adafda Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Tue, 13 Feb 2024 13:47:13 +0300 Subject: [PATCH 18/29] Tables renamed --- .../db/changelog/2024/003-naming.sql | 23 +++++++++++++++ src/main/resources/sql/insert-project.sql | 8 +++--- src/main/resources/sql/insert-ticket.sql | 10 +++---- .../resources/sql/select-project-by-id.sql | 2 +- .../sql/select-projects-by-user-email.sql | 6 ++-- .../sql/select-ticket-by-job-and-repo.sql | 2 +- .../sql/select-ticket-by-number-and-repo.sql | 2 +- src/test/resources/pre/sql/projects.sql | 28 +++++++++---------- 8 files changed, 52 insertions(+), 29 deletions(-) create mode 100644 src/main/resources/db/changelog/2024/003-naming.sql diff --git a/src/main/resources/db/changelog/2024/003-naming.sql b/src/main/resources/db/changelog/2024/003-naming.sql new file mode 100644 index 0000000..2d54255 --- /dev/null +++ b/src/main/resources/db/changelog/2024/003-naming.sql @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +--liquibase formatted sql + +--changeset hizmailovich:1 +ALTER TABLE projects.projects RENAME TO project; +ALTER TABLE projects.performers RENAME TO performer; +ALTER TABLE projects.tickets RENAME TO ticket; \ No newline at end of file diff --git a/src/main/resources/sql/insert-project.sql b/src/main/resources/sql/insert-project.sql index 6b681eb..f801038 100644 --- a/src/main/resources/sql/insert-project.sql +++ b/src/main/resources/sql/insert-project.sql @@ -15,10 +15,10 @@ * SOFTWARE. */ -INSERT INTO projects.projects (name, - location, - description, - active) +INSERT INTO projects.project (name, + location, + description, + active) VALUES (?, ?, ?, ?) RETURNING id, name, diff --git a/src/main/resources/sql/insert-ticket.sql b/src/main/resources/sql/insert-ticket.sql index 186a9ab..9203751 100644 --- a/src/main/resources/sql/insert-ticket.sql +++ b/src/main/resources/sql/insert-ticket.sql @@ -15,11 +15,11 @@ * SOFTWARE. */ -INSERT INTO projects.tickets (project, - number, - repo, - job, - status) +INSERT INTO projects.ticket (project, + number, + repo, + job, + status) VALUES (?, ?, ?, ?, ?) RETURNING id, project, diff --git a/src/main/resources/sql/select-project-by-id.sql b/src/main/resources/sql/select-project-by-id.sql index fcd473c..caffdac 100644 --- a/src/main/resources/sql/select-project-by-id.sql +++ b/src/main/resources/sql/select-project-by-id.sql @@ -20,5 +20,5 @@ SELECT id, location, description, active -FROM projects.projects +FROM projects.project WHERE id = ?; diff --git a/src/main/resources/sql/select-projects-by-user-email.sql b/src/main/resources/sql/select-projects-by-user-email.sql index 1ac4636..8c29a6b 100644 --- a/src/main/resources/sql/select-projects-by-user-email.sql +++ b/src/main/resources/sql/select-projects-by-user-email.sql @@ -20,6 +20,6 @@ SELECT p.id, p.location, p.description, p.active -FROM projects.projects p - INNER JOIN projects.performers on p.id = performers.project -WHERE performers.email = ?; +FROM projects.project p + INNER JOIN projects.performer on p.id = performer.project +WHERE performer.email = ?; diff --git a/src/main/resources/sql/select-ticket-by-job-and-repo.sql b/src/main/resources/sql/select-ticket-by-job-and-repo.sql index f567fcd..08f6a1f 100644 --- a/src/main/resources/sql/select-ticket-by-job-and-repo.sql +++ b/src/main/resources/sql/select-ticket-by-job-and-repo.sql @@ -21,5 +21,5 @@ SELECT id, repo, job, status -FROM projects.tickets +FROM projects.ticket WHERE job = ? AND repo = ?; diff --git a/src/main/resources/sql/select-ticket-by-number-and-repo.sql b/src/main/resources/sql/select-ticket-by-number-and-repo.sql index 7fc93fa..493d196 100644 --- a/src/main/resources/sql/select-ticket-by-number-and-repo.sql +++ b/src/main/resources/sql/select-ticket-by-number-and-repo.sql @@ -21,5 +21,5 @@ SELECT id, repo, job, status -FROM projects.tickets +FROM projects.ticket WHERE number = ? AND repo = ?; diff --git a/src/test/resources/pre/sql/projects.sql b/src/test/resources/pre/sql/projects.sql index 0108505..4c5aa0b 100644 --- a/src/test/resources/pre/sql/projects.sql +++ b/src/test/resources/pre/sql/projects.sql @@ -1,8 +1,8 @@ -INSERT INTO projects.projects (id, - name, - location, - description, - active) +INSERT INTO projects.project (id, + name, + location, + description, + active) VALUES ('74bb5ec8-0e6b-4618-bfa4-a0b76b7b312d', 'Test', 'github@user/test:master', @@ -10,19 +10,19 @@ VALUES ('74bb5ec8-0e6b-4618-bfa4-a0b76b7b312d', true) ON CONFLICT (id) DO NOTHING; -INSERT INTO projects.performers (email, - project, - permission) +INSERT INTO projects.performer (email, + project, + permission) VALUES ('user', '74bb5ec8-0e6b-4618-bfa4-a0b76b7b312d', 'READ'); -INSERT INTO projects.tickets(id, - project, - number, - repo, - job, - status) +INSERT INTO projects.ticket(id, + project, + number, + repo, + job, + status) VALUES ('04986038-6e38-4928-b12e-644c99f9cadc', '74bb5ec8-0e6b-4618-bfa4-a0b76b7b312d', 1, From a853d93d20901eb9e8c8c193c852bb1b1af53d3c Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Tue, 13 Feb 2024 15:47:04 +0300 Subject: [PATCH 19/29] Token fixed --- src/test/java/it/platforms/github/webhook/CreateWebhookIT.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/it/platforms/github/webhook/CreateWebhookIT.java b/src/test/java/it/platforms/github/webhook/CreateWebhookIT.java index 3c9ee34..dda2c6a 100644 --- a/src/test/java/it/platforms/github/webhook/CreateWebhookIT.java +++ b/src/test/java/it/platforms/github/webhook/CreateWebhookIT.java @@ -36,7 +36,7 @@ void createsWebhookSuccessfully() { final String host = "https://api.github.com"; final String url = "http://it/webhook"; final String location = "hizmailovich/draft"; - final String token = "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"; + final String token = System.getProperty("GithubToken"); new CreateWebhook( "https://api.github.com", token, From 33f221347c22498302446b16173276d5f0b24108 Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Tue, 13 Feb 2024 17:20:05 +0300 Subject: [PATCH 20/29] Resolved #16 --- .../pmo/controller/ProjectController.java | 64 ++++--------- .../git/tracehub/pmo/platforms/Platform.java | 53 +++++++++++ .../pmo/platforms/github/GithubPlatform.java | 89 +++++++++++++++++++ .../{ExistsRole.java => IdProvider.java} | 22 ++--- 4 files changed, 171 insertions(+), 57 deletions(-) create mode 100644 src/main/java/git/tracehub/pmo/platforms/Platform.java create mode 100644 src/main/java/git/tracehub/pmo/platforms/github/GithubPlatform.java rename src/main/java/git/tracehub/pmo/security/{ExistsRole.java => IdProvider.java} (70%) diff --git a/src/main/java/git/tracehub/pmo/controller/ProjectController.java b/src/main/java/git/tracehub/pmo/controller/ProjectController.java index 955e0e7..def4e8e 100644 --- a/src/main/java/git/tracehub/pmo/controller/ProjectController.java +++ b/src/main/java/git/tracehub/pmo/controller/ProjectController.java @@ -17,27 +17,21 @@ package git.tracehub.pmo.controller; -import com.jcabi.github.Coordinates; -import com.jcabi.github.Repo; -import com.jcabi.github.RtGithub; import git.tracehub.pmo.controller.request.ProjectFromReq; import git.tracehub.pmo.controller.request.RqProject; -import git.tracehub.pmo.platforms.Label; +import git.tracehub.pmo.platforms.Platform; import git.tracehub.pmo.platforms.RepoPath; -import git.tracehub.pmo.platforms.github.CreateLabels; -import git.tracehub.pmo.platforms.github.InviteCollaborator; -import git.tracehub.pmo.platforms.github.webhook.CreateWebhook; import git.tracehub.pmo.project.Project; import git.tracehub.pmo.project.Projects; import git.tracehub.pmo.security.ClaimOf; -import git.tracehub.pmo.security.ExistsRole; +import git.tracehub.pmo.security.IdProvider; import git.tracehub.pmo.security.IdpToken; import jakarta.validation.Valid; -import java.awt.Color; import java.util.List; +import java.util.Map; import java.util.UUID; import lombok.RequiredArgsConstructor; -import org.cactoos.list.ListOf; +import org.cactoos.Scalar; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; @@ -67,16 +61,15 @@ public class ProjectController { private final Projects projects; /** - * Issuer url. + * Platforms. */ - @Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}") - private String url; + private final Map platforms; /** - * Github host. + * Issuer url. */ - @Value("${platforms.github}") - private String host; + @Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}") + private String url; /** * Projects by user. @@ -112,7 +105,7 @@ public Project byId(@PathVariable final UUID id) { * @checkstyle MethodBodyCommentsCheck (20 lines) */ @PostMapping - @PreAuthorize("hasAuthority('user_github')") + @PreAuthorize("hasAuthority('user_github') || hasAuthority('user_gitlab')") @ResponseStatus(HttpStatus.CREATED) public Project employ( @RequestBody @Valid final RqProject project, @@ -121,36 +114,13 @@ public Project employ( final Project created = this.projects.employ( new ProjectFromReq(project).value() ); - /* - * @todo #1:45min/DEV define appropriate agent according to location - * of the project. We need to define appropriate agent and call - * corresponding implementation to invite collaborators here. - */ - if (new ExistsRole(jwt, "user_github").value()) { - final String location = new RepoPath(created.getLocation()).value(); - final String token = new IdpToken(jwt, "github", this.url).value(); - final Repo repo = new RtGithub(token).repos() - .get( - new Coordinates.Simple(location) - ); - new InviteCollaborator( - repo, - "tracehubgit" - ).exec(); - new CreateLabels( - repo, - new ListOf<>( - new Label("new", Color.PINK) - ) - ).exec(); - new CreateWebhook( - this.host, - token, - location, - "url", - new ListOf<>("push", "issues") - ).exec(); - } + final String provider = new IdProvider(jwt).value(); + final Scalar token = new IdpToken(jwt, provider, this.url); + final Scalar location = new RepoPath(created.getLocation()); + final Platform platform = this.platforms.get(provider); + platform.inviteCollaborator(token, location); + platform.createLabel(token, location); + platform.createWebhook(token, location); return created; } diff --git a/src/main/java/git/tracehub/pmo/platforms/Platform.java b/src/main/java/git/tracehub/pmo/platforms/Platform.java new file mode 100644 index 0000000..8ff319f --- /dev/null +++ b/src/main/java/git/tracehub/pmo/platforms/Platform.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package git.tracehub.pmo.platforms; + +import org.cactoos.Scalar; + +/** + * Platform. + * + * @since 0.0.0 + */ +public interface Platform { + + /** + * Create webhook. + * + * @param token Token + * @param location Repository location + */ + void createWebhook(Scalar token, Scalar location); + + /** + * Create label. + * + * @param token Token + * @param location Repository location + */ + void createLabel(Scalar token, Scalar location); + + /** + * Invite collaborator. + * + * @param token Token + * @param location Repository location + */ + void inviteCollaborator(Scalar token, Scalar location); + +} diff --git a/src/main/java/git/tracehub/pmo/platforms/github/GithubPlatform.java b/src/main/java/git/tracehub/pmo/platforms/github/GithubPlatform.java new file mode 100644 index 0000000..8b293df --- /dev/null +++ b/src/main/java/git/tracehub/pmo/platforms/github/GithubPlatform.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package git.tracehub.pmo.platforms.github; + +import com.jcabi.github.Coordinates; +import com.jcabi.github.RtGithub; +import git.tracehub.pmo.platforms.Label; +import git.tracehub.pmo.platforms.Platform; +import git.tracehub.pmo.platforms.github.webhook.CreateWebhook; +import java.awt.Color; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import org.cactoos.Scalar; +import org.cactoos.list.ListOf; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +/** + * Github platform. + * + * @checkstyle DesignForExtensionCheck (70 lines) + * @since 0.0.0 + */ +@Component("github") +@RequiredArgsConstructor +public class GithubPlatform implements Platform { + + /** + * Github host. + */ + @Value("${platforms.github}") + private String host; + + @Override + @SneakyThrows + public void createWebhook( + final Scalar token, + final Scalar location + ) { + new CreateWebhook( + this.host, + token.value(), + location.value(), + "http://it/webhook", + new ListOf<>("push", "issues") + ).exec(); + } + + @Override + @SneakyThrows + public void createLabel( + final Scalar token, + final Scalar location + ) { + new CreateLabels( + new RtGithub(token.value()).repos() + .get(new Coordinates.Simple(location.value())), + new ListOf<>(new Label("new", Color.PINK)) + ).exec(); + } + + @Override + @SneakyThrows + public void inviteCollaborator( + final Scalar token, + final Scalar location + ) { + new InviteCollaborator( + new RtGithub(token.value()).repos() + .get(new Coordinates.Simple(location.value())), + "tracehubgit" + ).exec(); + } +} diff --git a/src/main/java/git/tracehub/pmo/security/ExistsRole.java b/src/main/java/git/tracehub/pmo/security/IdProvider.java similarity index 70% rename from src/main/java/git/tracehub/pmo/security/ExistsRole.java rename to src/main/java/git/tracehub/pmo/security/IdProvider.java index 8c7901e..2661ba8 100644 --- a/src/main/java/git/tracehub/pmo/security/ExistsRole.java +++ b/src/main/java/git/tracehub/pmo/security/IdProvider.java @@ -17,33 +17,35 @@ package git.tracehub.pmo.security; +import java.util.Collection; import lombok.RequiredArgsConstructor; import org.cactoos.Scalar; +import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.oauth2.jwt.Jwt; /** - * Does the user have provided role from token. + * Identity provider. * * @since 0.0.0 */ @RequiredArgsConstructor -public final class ExistsRole implements Scalar { +public final class IdProvider implements Scalar { /** * JWT. */ private final Jwt jwt; - /** - * Role. - */ - private final String role; - @Override - public Boolean value() { - return new AuthoritiesConverter().convert(this.jwt).getAuthorities() - .contains(new SimpleGrantedAuthority(this.role)); + public String value() { + String provider = "gitlab"; + final Collection roles = new AuthoritiesConverter() + .convert(this.jwt).getAuthorities(); + if (roles.contains(new SimpleGrantedAuthority("user_github"))) { + provider = "github"; + } + return provider; } } From 18650a3430e174f05fafa9076227b2c3627ab0b6 Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Tue, 13 Feb 2024 17:20:12 +0300 Subject: [PATCH 21/29] Tests fixed --- .../pmo/controller/ProjectControllerTest.java | 27 +++++++++++++++++++ ...xistsRoleTest.java => IdProviderTest.java} | 26 +++++++++--------- 2 files changed, 41 insertions(+), 12 deletions(-) rename src/test/java/git/tracehub/pmo/security/{ExistsRoleTest.java => IdProviderTest.java} (73%) diff --git a/src/test/java/git/tracehub/pmo/controller/ProjectControllerTest.java b/src/test/java/git/tracehub/pmo/controller/ProjectControllerTest.java index 5245649..8c700ce 100644 --- a/src/test/java/git/tracehub/pmo/controller/ProjectControllerTest.java +++ b/src/test/java/git/tracehub/pmo/controller/ProjectControllerTest.java @@ -17,13 +17,18 @@ package git.tracehub.pmo.controller; +import git.tracehub.pmo.platforms.Platform; +import git.tracehub.pmo.platforms.github.GithubPlatform; +import git.tracehub.pmo.project.Project; import git.tracehub.pmo.project.Projects; import io.github.eocqrs.eokson.Jocument; import io.github.eocqrs.eokson.JsonOf; import io.github.eocqrs.eokson.MutableJson; +import java.util.Map; import org.cactoos.io.ResourceOf; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; @@ -58,6 +63,13 @@ final class ProjectControllerTest { @SuppressWarnings("PMD.UnusedPrivateField") private Projects projects; + /** + * Platforms. + */ + @MockBean + @SuppressWarnings("PMD.UnusedPrivateField") + private Map platforms; + @Test void returnsForbiddenOnUnauthorizedUser() throws Exception { this.mvc.perform( @@ -86,6 +98,21 @@ void returnsProjectById() throws Exception { @Test void createsNewProject() throws Exception { + final Platform platform = Mockito.mock(GithubPlatform.class); + Mockito.when(this.platforms.get(Mockito.any())) + .thenReturn(platform); + Mockito.when(this.projects.employ(Mockito.any(Project.class))) + .thenReturn( + new Project( + "74bb5ec8-0e6b-4618-bfa4-a0b76b7b312d", + "Location", + "Description", + true + ) + ); + Mockito.doNothing().when(platform).createWebhook(Mockito.any(), Mockito.any()); + Mockito.doNothing().when(platform).createLabel(Mockito.any(), Mockito.any()); + Mockito.doNothing().when(platform).inviteCollaborator(Mockito.any(), Mockito.any()); this.mvc.perform( MockMvcRequestBuilders.post("/projects") .with(SecurityMockMvcRequestPostProcessors.jwt()) diff --git a/src/test/java/git/tracehub/pmo/security/ExistsRoleTest.java b/src/test/java/git/tracehub/pmo/security/IdProviderTest.java similarity index 73% rename from src/test/java/git/tracehub/pmo/security/ExistsRoleTest.java rename to src/test/java/git/tracehub/pmo/security/IdProviderTest.java index 9bec336..3f9fb6e 100644 --- a/src/test/java/git/tracehub/pmo/security/ExistsRoleTest.java +++ b/src/test/java/git/tracehub/pmo/security/IdProviderTest.java @@ -30,12 +30,12 @@ import org.springframework.security.oauth2.jwt.Jwt; /** - * Test suite for {@link ExistsRole}. + * Test suite for {@link IdProvider}. * * @since 0.0.0 */ @ExtendWith(MockitoExtension.class) -final class ExistsRoleTest { +final class IdProviderTest { /** * JWT. @@ -44,30 +44,32 @@ final class ExistsRoleTest { private Jwt jwt; @Test - void returnsTrueIfRoleExists() { + void returnsGithubAsProvider() { + final String provider = "github"; Mockito.when(this.jwt.getClaimAsMap("realm_access")).thenReturn( new MapOf<>( - new MapEntry<>("roles", new ListOf<>("role")) + new MapEntry<>("roles", new ListOf<>("user_github")) ) ); MatcherAssert.assertThat( - "Role doesn't exist", - new ExistsRole(this.jwt, "role").value(), - new IsEqual<>(true) + "Provider %s doesn't exist".formatted(provider), + new IdProvider(this.jwt).value(), + new IsEqual<>(provider) ); } @Test - void returnsFalseIfRoleDoesNotExist() { + void returnsGitlabAsProvider() { + final String provider = "gitlab"; Mockito.when(this.jwt.getClaimAsMap("realm_access")).thenReturn( new MapOf<>( - new MapEntry<>("roles", new ListOf<>()) + new MapEntry<>("roles", new ListOf<>("user_gitlab")) ) ); MatcherAssert.assertThat( - "Role exists", - new ExistsRole(this.jwt, "role").value(), - new IsEqual<>(false) + "Provider %s doesn't exist".formatted(provider), + new IdProvider(this.jwt).value(), + new IsEqual<>(provider) ); } From 1628928bea1dbdd4fde3fdde3895d5fb4ecda8ec Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Tue, 13 Feb 2024 17:36:40 +0300 Subject: [PATCH 22/29] Resolved #47 --- .../tracehub/pmo/project/DefaultProjects.java | 6 +++--- .../git/tracehub/pmo/project/Projects.java | 6 +++--- .../changelog/2024/004-performers-naming.sql | 21 +++++++++++++++++++ ....sql => select-projects-by-user-login.sql} | 2 +- src/test/resources/pre/sql/projects.sql | 2 +- 5 files changed, 29 insertions(+), 8 deletions(-) create mode 100644 src/main/resources/db/changelog/2024/004-performers-naming.sql rename src/main/resources/sql/{select-projects-by-user-email.sql => select-projects-by-user-login.sql} (97%) diff --git a/src/main/java/git/tracehub/pmo/project/DefaultProjects.java b/src/main/java/git/tracehub/pmo/project/DefaultProjects.java index e149850..c6f73a7 100644 --- a/src/main/java/git/tracehub/pmo/project/DefaultProjects.java +++ b/src/main/java/git/tracehub/pmo/project/DefaultProjects.java @@ -63,12 +63,12 @@ public Project byId(final UUID id) { @Override @SneakyThrows - public List byUser(final String email) { + public List byUser(final String login) { return new JdbcSession(this.source) .sql( - new SqlStatement("select-projects-by-user-email.sql") + new SqlStatement("select-projects-by-user-login.sql") .asString() - ).set(email) + ).set(login) .select( (rs, stmt) -> { final List projects = new ArrayList<>(5); diff --git a/src/main/java/git/tracehub/pmo/project/Projects.java b/src/main/java/git/tracehub/pmo/project/Projects.java index 8df4392..69c7e11 100644 --- a/src/main/java/git/tracehub/pmo/project/Projects.java +++ b/src/main/java/git/tracehub/pmo/project/Projects.java @@ -36,12 +36,12 @@ public interface Projects { Project byId(UUID id); /** - * Projects by user email. + * Projects by user login. * - * @param email User Email + * @param login User login * @return List of projects */ - List byUser(String email); + List byUser(String login); /** * Employ new project. diff --git a/src/main/resources/db/changelog/2024/004-performers-naming.sql b/src/main/resources/db/changelog/2024/004-performers-naming.sql new file mode 100644 index 0000000..a1b9a54 --- /dev/null +++ b/src/main/resources/db/changelog/2024/004-performers-naming.sql @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +--liquibase formatted sql + +--changeset hizmailovich:1 +ALTER TABLE projects.performer RENAME COLUMN email TO login; \ No newline at end of file diff --git a/src/main/resources/sql/select-projects-by-user-email.sql b/src/main/resources/sql/select-projects-by-user-login.sql similarity index 97% rename from src/main/resources/sql/select-projects-by-user-email.sql rename to src/main/resources/sql/select-projects-by-user-login.sql index 8c29a6b..61a9ceb 100644 --- a/src/main/resources/sql/select-projects-by-user-email.sql +++ b/src/main/resources/sql/select-projects-by-user-login.sql @@ -22,4 +22,4 @@ SELECT p.id, p.active FROM projects.project p INNER JOIN projects.performer on p.id = performer.project -WHERE performer.email = ?; +WHERE performer.login = ?; diff --git a/src/test/resources/pre/sql/projects.sql b/src/test/resources/pre/sql/projects.sql index 4c5aa0b..0f06b25 100644 --- a/src/test/resources/pre/sql/projects.sql +++ b/src/test/resources/pre/sql/projects.sql @@ -10,7 +10,7 @@ VALUES ('74bb5ec8-0e6b-4618-bfa4-a0b76b7b312d', true) ON CONFLICT (id) DO NOTHING; -INSERT INTO projects.performer (email, +INSERT INTO projects.performer (login, project, permission) VALUES ('user', From c1abcf47145e3612b43bac6dae7ca61b1e6a40bb Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Wed, 14 Feb 2024 11:34:35 +0300 Subject: [PATCH 23/29] Values passed --- .../tracehub/pmo/controller/ProjectController.java | 2 +- .../tracehub/pmo/controller/TicketController.java | 2 +- .../git/tracehub/pmo/project/DefaultProjects.java | 12 +++++++----- .../java/git/tracehub/pmo/project/Projects.java | 3 ++- .../git/tracehub/pmo/ticket/DefaultTickets.java | 14 ++++++++------ src/main/java/git/tracehub/pmo/ticket/Tickets.java | 4 +++- 6 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/main/java/git/tracehub/pmo/controller/ProjectController.java b/src/main/java/git/tracehub/pmo/controller/ProjectController.java index def4e8e..60b65c7 100644 --- a/src/main/java/git/tracehub/pmo/controller/ProjectController.java +++ b/src/main/java/git/tracehub/pmo/controller/ProjectController.java @@ -112,7 +112,7 @@ public Project employ( @AuthenticationPrincipal final Jwt jwt ) { final Project created = this.projects.employ( - new ProjectFromReq(project).value() + new ProjectFromReq(project) ); final String provider = new IdProvider(jwt).value(); final Scalar token = new IdpToken(jwt, provider, this.url); diff --git a/src/main/java/git/tracehub/pmo/controller/TicketController.java b/src/main/java/git/tracehub/pmo/controller/TicketController.java index f5428a7..4af12d8 100644 --- a/src/main/java/git/tracehub/pmo/controller/TicketController.java +++ b/src/main/java/git/tracehub/pmo/controller/TicketController.java @@ -87,7 +87,7 @@ public Ticket byNumber( @ResponseStatus(HttpStatus.CREATED) public Ticket create(@RequestBody @Valid final RqTicket ticket) { return this.tickets.create( - new TicketFromReq(ticket).value() + new TicketFromReq(ticket) ); } diff --git a/src/main/java/git/tracehub/pmo/project/DefaultProjects.java b/src/main/java/git/tracehub/pmo/project/DefaultProjects.java index c6f73a7..de20d90 100644 --- a/src/main/java/git/tracehub/pmo/project/DefaultProjects.java +++ b/src/main/java/git/tracehub/pmo/project/DefaultProjects.java @@ -25,6 +25,7 @@ import javax.sql.DataSource; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; +import org.cactoos.Scalar; import org.springframework.stereotype.Component; /** @@ -82,14 +83,15 @@ public List byUser(final String login) { @Override @SneakyThrows - public Project employ(final Project project) { + public Project employ(final Scalar project) { + final Project value = project.value(); return new JdbcSession(this.source) .sql( new SqlStatement("insert-project.sql").asString() - ).set(project.getName()) - .set(project.getLocation()) - .set(project.getDescription()) - .set(project.isActive()) + ).set(value.getName()) + .set(value.getLocation()) + .set(value.getDescription()) + .set(value.isActive()) .update( (rs, stmt) -> { rs.next(); diff --git a/src/main/java/git/tracehub/pmo/project/Projects.java b/src/main/java/git/tracehub/pmo/project/Projects.java index 69c7e11..f61c6d9 100644 --- a/src/main/java/git/tracehub/pmo/project/Projects.java +++ b/src/main/java/git/tracehub/pmo/project/Projects.java @@ -19,6 +19,7 @@ import java.util.List; import java.util.UUID; +import org.cactoos.Scalar; /** * Projects. @@ -49,5 +50,5 @@ public interface Projects { * @param project Project to Employ * @return Project */ - Project employ(Project project); + Project employ(Scalar project); } diff --git a/src/main/java/git/tracehub/pmo/ticket/DefaultTickets.java b/src/main/java/git/tracehub/pmo/ticket/DefaultTickets.java index e6ac16b..ae80b80 100644 --- a/src/main/java/git/tracehub/pmo/ticket/DefaultTickets.java +++ b/src/main/java/git/tracehub/pmo/ticket/DefaultTickets.java @@ -23,6 +23,7 @@ import javax.sql.DataSource; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; +import org.cactoos.Scalar; import org.springframework.stereotype.Component; /** @@ -84,15 +85,16 @@ public Ticket byNumber(final int number, final String repo) { @Override @SneakyThrows - public Ticket create(final Ticket ticket) { + public Ticket create(final Scalar ticket) { + final Ticket value = ticket.value(); return new JdbcSession(this.source) .sql( new SqlStatement("insert-ticket.sql").asString() - ).set(ticket.getProject()) - .set(ticket.getNumber()) - .set(ticket.getRepo()) - .set(ticket.getJob()) - .set(ticket.getStatus().name()) + ).set(value.getProject()) + .set(value.getNumber()) + .set(value.getRepo()) + .set(value.getJob()) + .set(value.getStatus().name()) .update( (rs, stmt) -> { rs.next(); diff --git a/src/main/java/git/tracehub/pmo/ticket/Tickets.java b/src/main/java/git/tracehub/pmo/ticket/Tickets.java index 15a13bc..6c204fd 100644 --- a/src/main/java/git/tracehub/pmo/ticket/Tickets.java +++ b/src/main/java/git/tracehub/pmo/ticket/Tickets.java @@ -17,6 +17,8 @@ package git.tracehub.pmo.ticket; +import org.cactoos.Scalar; + /** * Tickets. * @@ -48,6 +50,6 @@ public interface Tickets { * @param ticket Ticket * @return Ticket */ - Ticket create(Ticket ticket); + Ticket create(Scalar ticket); } From f0fd18c9928ac057912a48def268f5ea03b2d9d1 Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Wed, 14 Feb 2024 11:34:45 +0300 Subject: [PATCH 24/29] Tests fixed --- .../git/tracehub/pmo/controller/ProjectControllerTest.java | 3 ++- .../java/git/tracehub/pmo/project/DefaultProjectsTest.java | 4 ++-- src/test/java/git/tracehub/pmo/ticket/DefaultTicketsTest.java | 4 ++-- src/test/java/it/database/DefaultProjectsIT.java | 2 +- src/test/java/it/database/DefaultTicketsIT.java | 2 +- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/test/java/git/tracehub/pmo/controller/ProjectControllerTest.java b/src/test/java/git/tracehub/pmo/controller/ProjectControllerTest.java index 8c700ce..8f27333 100644 --- a/src/test/java/git/tracehub/pmo/controller/ProjectControllerTest.java +++ b/src/test/java/git/tracehub/pmo/controller/ProjectControllerTest.java @@ -25,6 +25,7 @@ import io.github.eocqrs.eokson.JsonOf; import io.github.eocqrs.eokson.MutableJson; import java.util.Map; +import org.cactoos.Scalar; import org.cactoos.io.ResourceOf; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -101,7 +102,7 @@ void createsNewProject() throws Exception { final Platform platform = Mockito.mock(GithubPlatform.class); Mockito.when(this.platforms.get(Mockito.any())) .thenReturn(platform); - Mockito.when(this.projects.employ(Mockito.any(Project.class))) + Mockito.when(this.projects.employ(Mockito.any(Scalar.class))) .thenReturn( new Project( "74bb5ec8-0e6b-4618-bfa4-a0b76b7b312d", diff --git a/src/test/java/git/tracehub/pmo/project/DefaultProjectsTest.java b/src/test/java/git/tracehub/pmo/project/DefaultProjectsTest.java index 902157b..b388f92 100644 --- a/src/test/java/git/tracehub/pmo/project/DefaultProjectsTest.java +++ b/src/test/java/git/tracehub/pmo/project/DefaultProjectsTest.java @@ -155,7 +155,7 @@ void employsProject() throws SQLException { ); this.mock(expected); Mockito.when(this.set.next()).thenReturn(true); - final Project project = this.projects.employ(expected); + final Project project = this.projects.employ(() -> expected); MatcherAssert.assertThat( "Project %s is null".formatted(project), true, @@ -190,7 +190,7 @@ void throwsOnCreatingInvalidProject() throws SQLException { new Assertion<>( "Exception is not thrown or valid", () -> this.projects.employ( - new Project( + () -> new Project( "Test Project", "Location", "Description", diff --git a/src/test/java/git/tracehub/pmo/ticket/DefaultTicketsTest.java b/src/test/java/git/tracehub/pmo/ticket/DefaultTicketsTest.java index b6882bc..fe083cf 100644 --- a/src/test/java/git/tracehub/pmo/ticket/DefaultTicketsTest.java +++ b/src/test/java/git/tracehub/pmo/ticket/DefaultTicketsTest.java @@ -162,7 +162,7 @@ void createsTicket() throws SQLException { ); this.mock(expected); Mockito.when(this.set.next()).thenReturn(true); - final Ticket ticket = this.tickets.create(expected); + final Ticket ticket = this.tickets.create(() -> expected); MatcherAssert.assertThat( "Ticket %s isn't created".formatted(ticket), true, @@ -214,7 +214,7 @@ void throwsOnCreatingInvalidTicket() throws SQLException { new Assertion<>( "Exception is not thrown or valid", () -> this.tickets.create( - new Ticket( + () -> new Ticket( UUID.randomUUID(), 35, "user/repo", diff --git a/src/test/java/it/database/DefaultProjectsIT.java b/src/test/java/it/database/DefaultProjectsIT.java index 9e2c1b1..9f18465 100644 --- a/src/test/java/it/database/DefaultProjectsIT.java +++ b/src/test/java/it/database/DefaultProjectsIT.java @@ -105,7 +105,7 @@ void employsProject() { "Description", true ); - final Project project = this.projects.employ(expected); + final Project project = this.projects.employ(() -> expected); MatcherAssert.assertThat( "Project %s is null".formatted(project), true, diff --git a/src/test/java/it/database/DefaultTicketsIT.java b/src/test/java/it/database/DefaultTicketsIT.java index 5398800..6edcce8 100644 --- a/src/test/java/it/database/DefaultTicketsIT.java +++ b/src/test/java/it/database/DefaultTicketsIT.java @@ -113,7 +113,7 @@ void createsTicket() { "path/to/job", Ticket.Status.OPENED ); - final Ticket ticket = this.tickets.create(expected); + final Ticket ticket = this.tickets.create(() -> expected); MatcherAssert.assertThat( "Ticket %s is null".formatted(ticket), true, From 8518ac4fee4a22dc362d318aaff4914d851c623f Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Wed, 14 Feb 2024 12:55:32 +0300 Subject: [PATCH 25/29] Increment fixed --- src/main/resources/db/changelog/2024/002-tickets.sql | 6 +++--- src/main/resources/db/changelog/2024/003-naming.sql | 2 +- .../resources/db/changelog/2024/004-performers-naming.sql | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/resources/db/changelog/2024/002-tickets.sql b/src/main/resources/db/changelog/2024/002-tickets.sql index 6a115a5..009582f 100644 --- a/src/main/resources/db/changelog/2024/002-tickets.sql +++ b/src/main/resources/db/changelog/2024/002-tickets.sql @@ -17,13 +17,13 @@ --liquibase formatted sql ---changeset hizmailovich:1 +--changeset hizmailovich:4 CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; ---changeset hizmailovich:2 +--changeset hizmailovich:5 CREATE SCHEMA IF NOT EXISTS projects; ---changeset hizmailovich:3 +--changeset hizmailovich:6 CREATE TABLE IF NOT EXISTS projects.tickets ( id uuid DEFAULT uuid_generate_v4() PRIMARY KEY, diff --git a/src/main/resources/db/changelog/2024/003-naming.sql b/src/main/resources/db/changelog/2024/003-naming.sql index 2d54255..760923e 100644 --- a/src/main/resources/db/changelog/2024/003-naming.sql +++ b/src/main/resources/db/changelog/2024/003-naming.sql @@ -17,7 +17,7 @@ --liquibase formatted sql ---changeset hizmailovich:1 +--changeset hizmailovich:7 ALTER TABLE projects.projects RENAME TO project; ALTER TABLE projects.performers RENAME TO performer; ALTER TABLE projects.tickets RENAME TO ticket; \ No newline at end of file diff --git a/src/main/resources/db/changelog/2024/004-performers-naming.sql b/src/main/resources/db/changelog/2024/004-performers-naming.sql index a1b9a54..3f7746f 100644 --- a/src/main/resources/db/changelog/2024/004-performers-naming.sql +++ b/src/main/resources/db/changelog/2024/004-performers-naming.sql @@ -17,5 +17,5 @@ --liquibase formatted sql ---changeset hizmailovich:1 +--changeset hizmailovich:8 ALTER TABLE projects.performer RENAME COLUMN email TO login; \ No newline at end of file From d3c00d347a9bd54a37b90f253ad027a3f1c2502e Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Wed, 14 Feb 2024 12:55:45 +0300 Subject: [PATCH 26/29] Platform refactored --- .../pmo/controller/ProjectController.java | 11 ++-- .../git/tracehub/pmo/platforms/Platform.java | 20 +------ .../{GithubPlatform.java => Github.java} | 55 ++++++------------- .../git/tracehub/pmo/security/WebConfig.java | 23 ++++++++ 4 files changed, 47 insertions(+), 62 deletions(-) rename src/main/java/git/tracehub/pmo/platforms/github/{GithubPlatform.java => Github.java} (66%) diff --git a/src/main/java/git/tracehub/pmo/controller/ProjectController.java b/src/main/java/git/tracehub/pmo/controller/ProjectController.java index 60b65c7..ba58223 100644 --- a/src/main/java/git/tracehub/pmo/controller/ProjectController.java +++ b/src/main/java/git/tracehub/pmo/controller/ProjectController.java @@ -31,7 +31,6 @@ import java.util.Map; import java.util.UUID; import lombok.RequiredArgsConstructor; -import org.cactoos.Scalar; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; @@ -115,12 +114,10 @@ public Project employ( new ProjectFromReq(project) ); final String provider = new IdProvider(jwt).value(); - final Scalar token = new IdpToken(jwt, provider, this.url); - final Scalar location = new RepoPath(created.getLocation()); - final Platform platform = this.platforms.get(provider); - platform.inviteCollaborator(token, location); - platform.createLabel(token, location); - platform.createWebhook(token, location); + this.platforms.get(provider).prepare( + new IdpToken(jwt, provider, this.url), + new RepoPath(created.getLocation()) + ); return created; } diff --git a/src/main/java/git/tracehub/pmo/platforms/Platform.java b/src/main/java/git/tracehub/pmo/platforms/Platform.java index 8ff319f..7626d77 100644 --- a/src/main/java/git/tracehub/pmo/platforms/Platform.java +++ b/src/main/java/git/tracehub/pmo/platforms/Platform.java @@ -27,27 +27,11 @@ public interface Platform { /** - * Create webhook. + * Prepare. * * @param token Token * @param location Repository location */ - void createWebhook(Scalar token, Scalar location); - - /** - * Create label. - * - * @param token Token - * @param location Repository location - */ - void createLabel(Scalar token, Scalar location); - - /** - * Invite collaborator. - * - * @param token Token - * @param location Repository location - */ - void inviteCollaborator(Scalar token, Scalar location); + void prepare(Scalar token, Scalar location); } diff --git a/src/main/java/git/tracehub/pmo/platforms/github/GithubPlatform.java b/src/main/java/git/tracehub/pmo/platforms/github/Github.java similarity index 66% rename from src/main/java/git/tracehub/pmo/platforms/github/GithubPlatform.java rename to src/main/java/git/tracehub/pmo/platforms/github/Github.java index 8b293df..89c7746 100644 --- a/src/main/java/git/tracehub/pmo/platforms/github/GithubPlatform.java +++ b/src/main/java/git/tracehub/pmo/platforms/github/Github.java @@ -27,63 +27,44 @@ import lombok.SneakyThrows; import org.cactoos.Scalar; import org.cactoos.list.ListOf; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; /** * Github platform. * - * @checkstyle DesignForExtensionCheck (70 lines) * @since 0.0.0 */ -@Component("github") @RequiredArgsConstructor -public class GithubPlatform implements Platform { +public final class Github implements Platform { /** - * Github host. + * Host. */ - @Value("${platforms.github}") - private String host; + private final String host; @Override @SneakyThrows - public void createWebhook( + public void prepare( final Scalar token, final Scalar location ) { - new CreateWebhook( - this.host, - token.value(), - location.value(), - "http://it/webhook", - new ListOf<>("push", "issues") + final String tkn = token.value(); + final String loc = location.value(); + new InviteCollaborator( + new RtGithub(tkn).repos() + .get(new Coordinates.Simple(loc)), + "tracehubgit" ).exec(); - } - - @Override - @SneakyThrows - public void createLabel( - final Scalar token, - final Scalar location - ) { new CreateLabels( - new RtGithub(token.value()).repos() - .get(new Coordinates.Simple(location.value())), + new RtGithub(tkn).repos() + .get(new Coordinates.Simple(loc)), new ListOf<>(new Label("new", Color.PINK)) ).exec(); - } - - @Override - @SneakyThrows - public void inviteCollaborator( - final Scalar token, - final Scalar location - ) { - new InviteCollaborator( - new RtGithub(token.value()).repos() - .get(new Coordinates.Simple(location.value())), - "tracehubgit" + new CreateWebhook( + this.host, + tkn, + loc, + "http://it/webhook", + new ListOf<>("push", "issues") ).exec(); } } diff --git a/src/main/java/git/tracehub/pmo/security/WebConfig.java b/src/main/java/git/tracehub/pmo/security/WebConfig.java index 4b81e27..b72fc2a 100644 --- a/src/main/java/git/tracehub/pmo/security/WebConfig.java +++ b/src/main/java/git/tracehub/pmo/security/WebConfig.java @@ -17,6 +17,8 @@ package git.tracehub.pmo.security; +import git.tracehub.pmo.platforms.Platform; +import git.tracehub.pmo.platforms.github.Github; import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Info; @@ -25,7 +27,10 @@ import io.swagger.v3.oas.models.security.Scopes; import io.swagger.v3.oas.models.security.SecurityRequirement; import io.swagger.v3.oas.models.security.SecurityScheme; +import java.util.Map; import lombok.SneakyThrows; +import org.cactoos.map.MapEntry; +import org.cactoos.map.MapOf; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -58,6 +63,12 @@ public class WebConfig { @Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}") private String url; + /** + * Github host. + */ + @Value("${platforms.github}") + private String github; + /** * Filter. * @@ -140,4 +151,16 @@ name, new SecurityScheme() ); } + /** + * Platforms. + * + * @return Map of implemented platforms + */ + @Bean + public Map platforms() { + return new MapOf<>( + new MapEntry<>("github", new Github(this.github)) + ); + } + } From 56a718d88655acbb1ae2605cc3bc4b159239a840 Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Wed, 14 Feb 2024 12:55:52 +0300 Subject: [PATCH 27/29] Tests fixed --- .../pmo/controller/ProjectControllerTest.java | 8 +++---- .../pmo/project/DefaultProjectsTest.java | 19 +++-------------- .../pmo/ticket/DefaultTicketsTest.java | 21 +++---------------- 3 files changed, 9 insertions(+), 39 deletions(-) diff --git a/src/test/java/git/tracehub/pmo/controller/ProjectControllerTest.java b/src/test/java/git/tracehub/pmo/controller/ProjectControllerTest.java index 8f27333..ef04b27 100644 --- a/src/test/java/git/tracehub/pmo/controller/ProjectControllerTest.java +++ b/src/test/java/git/tracehub/pmo/controller/ProjectControllerTest.java @@ -18,7 +18,7 @@ package git.tracehub.pmo.controller; import git.tracehub.pmo.platforms.Platform; -import git.tracehub.pmo.platforms.github.GithubPlatform; +import git.tracehub.pmo.platforms.github.Github; import git.tracehub.pmo.project.Project; import git.tracehub.pmo.project.Projects; import io.github.eocqrs.eokson.Jocument; @@ -99,7 +99,7 @@ void returnsProjectById() throws Exception { @Test void createsNewProject() throws Exception { - final Platform platform = Mockito.mock(GithubPlatform.class); + final Platform platform = Mockito.mock(Github.class); Mockito.when(this.platforms.get(Mockito.any())) .thenReturn(platform); Mockito.when(this.projects.employ(Mockito.any(Scalar.class))) @@ -111,9 +111,7 @@ void createsNewProject() throws Exception { true ) ); - Mockito.doNothing().when(platform).createWebhook(Mockito.any(), Mockito.any()); - Mockito.doNothing().when(platform).createLabel(Mockito.any(), Mockito.any()); - Mockito.doNothing().when(platform).inviteCollaborator(Mockito.any(), Mockito.any()); + Mockito.doNothing().when(platform).prepare(Mockito.any(), Mockito.any()); this.mvc.perform( MockMvcRequestBuilders.post("/projects") .with(SecurityMockMvcRequestPostProcessors.jwt()) diff --git a/src/test/java/git/tracehub/pmo/project/DefaultProjectsTest.java b/src/test/java/git/tracehub/pmo/project/DefaultProjectsTest.java index b388f92..c3358b0 100644 --- a/src/test/java/git/tracehub/pmo/project/DefaultProjectsTest.java +++ b/src/test/java/git/tracehub/pmo/project/DefaultProjectsTest.java @@ -104,7 +104,7 @@ void returnsProjectById() throws SQLException { "Description", true ); - this.mock(expected); + new MockProject(this.set).exec(expected); Mockito.when(this.set.next()).thenReturn(true); final Project project = this.projects.byId(expected.getId()); MatcherAssert.assertThat( @@ -129,7 +129,7 @@ void returnsProjectsByUser() throws SQLException { "Description", true ); - this.mock(expected); + new MockProject(this.set).exec(expected); Mockito.when(this.set.next()).thenReturn(true, false); final List actual = this.projects.byUser(email); MatcherAssert.assertThat( @@ -153,7 +153,7 @@ void employsProject() throws SQLException { "Description", true ); - this.mock(expected); + new MockProject(this.set).exec(expected); Mockito.when(this.set.next()).thenReturn(true); final Project project = this.projects.employ(() -> expected); MatcherAssert.assertThat( @@ -201,17 +201,4 @@ void throwsOnCreatingInvalidProject() throws SQLException { ).affirm(); } - private void mock(final Project project) throws SQLException { - Mockito.when(this.set.getString("id")) - .thenReturn(project.getId().toString()); - Mockito.when(this.set.getString("name")) - .thenReturn(project.getName()); - Mockito.when(this.set.getString("location")) - .thenReturn(project.getLocation()); - Mockito.when(this.set.getString("description")) - .thenReturn(project.getDescription()); - Mockito.when(this.set.getBoolean("active")) - .thenReturn(project.isActive()); - } - } diff --git a/src/test/java/git/tracehub/pmo/ticket/DefaultTicketsTest.java b/src/test/java/git/tracehub/pmo/ticket/DefaultTicketsTest.java index fe083cf..c6d02f7 100644 --- a/src/test/java/git/tracehub/pmo/ticket/DefaultTicketsTest.java +++ b/src/test/java/git/tracehub/pmo/ticket/DefaultTicketsTest.java @@ -104,7 +104,7 @@ void returnsTicketByJob() throws SQLException { "path/to/job", Ticket.Status.OPENED ); - this.mock(expected); + new MockTicket(this.set).exec(expected); Mockito.when(this.set.next()).thenReturn(true); final Ticket ticket = this.tickets.byJob( expected.getJob(), @@ -132,7 +132,7 @@ void returnsTicketByIssueNumber() throws SQLException { "path/to/job", Ticket.Status.OPENED ); - this.mock(expected); + new MockTicket(this.set).exec(expected); Mockito.when(this.set.next()).thenReturn(true); final Ticket ticket = this.tickets.byNumber( expected.getNumber(), @@ -160,7 +160,7 @@ void createsTicket() throws SQLException { "path/to/job", Ticket.Status.OPENED ); - this.mock(expected); + new MockTicket(this.set).exec(expected); Mockito.when(this.set.next()).thenReturn(true); final Ticket ticket = this.tickets.create(() -> expected); MatcherAssert.assertThat( @@ -226,19 +226,4 @@ void throwsOnCreatingInvalidTicket() throws SQLException { ).affirm(); } - private void mock(final Ticket ticket) throws SQLException { - Mockito.when(this.set.getString("id")) - .thenReturn(ticket.getId().toString()); - Mockito.when(this.set.getString("project")) - .thenReturn(ticket.getProject().toString()); - Mockito.when(this.set.getInt("number")) - .thenReturn(ticket.getNumber()); - Mockito.when(this.set.getString("repo")) - .thenReturn(ticket.getRepo()); - Mockito.when(this.set.getString("job")) - .thenReturn(ticket.getJob()); - Mockito.when(this.set.getString("status")) - .thenReturn(ticket.getStatus().name()); - } - } From cc5d1f467a0ef58f5a659e0ac2bf1c7230b6e1ce Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Wed, 14 Feb 2024 12:56:13 +0300 Subject: [PATCH 28/29] Mocked objects moved to new classes --- .../git/tracehub/pmo/project/MockProject.java | 58 ++++++++++++++++++ .../git/tracehub/pmo/ticket/MockTicket.java | 60 +++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 src/test/java/git/tracehub/pmo/project/MockProject.java create mode 100644 src/test/java/git/tracehub/pmo/ticket/MockTicket.java diff --git a/src/test/java/git/tracehub/pmo/project/MockProject.java b/src/test/java/git/tracehub/pmo/project/MockProject.java new file mode 100644 index 0000000..82676f0 --- /dev/null +++ b/src/test/java/git/tracehub/pmo/project/MockProject.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package git.tracehub.pmo.project; + +import java.sql.ResultSet; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import org.cactoos.Proc; +import org.mockito.Mockito; + +/** + * Mock project into ResultSet. + * + * @since 0.0.0 + */ +@RequiredArgsConstructor +@SuppressWarnings({ + "JTCOP.RuleCorrectTestName", + "JTCOP.RuleAllTestsHaveProductionClass" +}) +final class MockProject implements Proc { + + /** + * ResultSet. + */ + private final ResultSet set; + + @Override + @SneakyThrows + public void exec(final Project project) { + Mockito.when(this.set.getString("id")) + .thenReturn(project.getId().toString()); + Mockito.when(this.set.getString("name")) + .thenReturn(project.getName()); + Mockito.when(this.set.getString("location")) + .thenReturn(project.getLocation()); + Mockito.when(this.set.getString("description")) + .thenReturn(project.getDescription()); + Mockito.when(this.set.getBoolean("active")) + .thenReturn(project.isActive()); + } + +} diff --git a/src/test/java/git/tracehub/pmo/ticket/MockTicket.java b/src/test/java/git/tracehub/pmo/ticket/MockTicket.java new file mode 100644 index 0000000..f951a4a --- /dev/null +++ b/src/test/java/git/tracehub/pmo/ticket/MockTicket.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023-2024 Tracehub.git + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to read + * the Software only. Permissions is hereby NOT GRANTED to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package git.tracehub.pmo.ticket; + +import java.sql.ResultSet; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import org.cactoos.Proc; +import org.mockito.Mockito; + +/** + * Mock ticket into ResultSet. + * + * @since 0.0.0 + */ +@RequiredArgsConstructor +@SuppressWarnings({ + "JTCOP.RuleCorrectTestName", + "JTCOP.RuleAllTestsHaveProductionClass" +}) +final class MockTicket implements Proc { + + /** + * ResultSet. + */ + private final ResultSet set; + + @Override + @SneakyThrows + public void exec(final Ticket ticket) { + Mockito.when(this.set.getString("id")) + .thenReturn(ticket.getId().toString()); + Mockito.when(this.set.getString("project")) + .thenReturn(ticket.getProject().toString()); + Mockito.when(this.set.getInt("number")) + .thenReturn(ticket.getNumber()); + Mockito.when(this.set.getString("repo")) + .thenReturn(ticket.getRepo()); + Mockito.when(this.set.getString("job")) + .thenReturn(ticket.getJob()); + Mockito.when(this.set.getString("status")) + .thenReturn(ticket.getStatus().name()); + } + +} From cc0964da7675e6614c41278376ebe2d9da02a302 Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Thu, 15 Feb 2024 13:54:13 +0300 Subject: [PATCH 29/29] Component added --- .../tracehub/pmo/platforms/github/Github.java | 8 +++++-- .../git/tracehub/pmo/security/WebConfig.java | 23 ------------------- 2 files changed, 6 insertions(+), 25 deletions(-) diff --git a/src/main/java/git/tracehub/pmo/platforms/github/Github.java b/src/main/java/git/tracehub/pmo/platforms/github/Github.java index 89c7746..c98a55a 100644 --- a/src/main/java/git/tracehub/pmo/platforms/github/Github.java +++ b/src/main/java/git/tracehub/pmo/platforms/github/Github.java @@ -27,19 +27,23 @@ import lombok.SneakyThrows; import org.cactoos.Scalar; import org.cactoos.list.ListOf; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; /** * Github platform. * * @since 0.0.0 */ +@Component @RequiredArgsConstructor public final class Github implements Platform { /** - * Host. + * Github host. */ - private final String host; + @Value("${platforms.github}") + private String host; @Override @SneakyThrows diff --git a/src/main/java/git/tracehub/pmo/security/WebConfig.java b/src/main/java/git/tracehub/pmo/security/WebConfig.java index b72fc2a..4b81e27 100644 --- a/src/main/java/git/tracehub/pmo/security/WebConfig.java +++ b/src/main/java/git/tracehub/pmo/security/WebConfig.java @@ -17,8 +17,6 @@ package git.tracehub.pmo.security; -import git.tracehub.pmo.platforms.Platform; -import git.tracehub.pmo.platforms.github.Github; import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Info; @@ -27,10 +25,7 @@ import io.swagger.v3.oas.models.security.Scopes; import io.swagger.v3.oas.models.security.SecurityRequirement; import io.swagger.v3.oas.models.security.SecurityScheme; -import java.util.Map; import lombok.SneakyThrows; -import org.cactoos.map.MapEntry; -import org.cactoos.map.MapOf; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -63,12 +58,6 @@ public class WebConfig { @Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}") private String url; - /** - * Github host. - */ - @Value("${platforms.github}") - private String github; - /** * Filter. * @@ -151,16 +140,4 @@ name, new SecurityScheme() ); } - /** - * Platforms. - * - * @return Map of implemented platforms - */ - @Bean - public Map platforms() { - return new MapOf<>( - new MapEntry<>("github", new Github(this.github)) - ); - } - }