From 7a9b973928ff623f60e0c133f1d48f51338e347f Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Thu, 25 Jan 2024 15:57:44 +0300 Subject: [PATCH 01/12] Token from identity provider extracted --- .../git/tracehub/pmo/security/IdpToken.java | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/main/java/git/tracehub/pmo/security/IdpToken.java b/src/main/java/git/tracehub/pmo/security/IdpToken.java index d31a528..33925e8 100644 --- a/src/main/java/git/tracehub/pmo/security/IdpToken.java +++ b/src/main/java/git/tracehub/pmo/security/IdpToken.java @@ -20,6 +20,7 @@ import com.jcabi.http.Request; import com.jcabi.http.request.JdkRequest; import com.jcabi.http.response.RestResponse; +import java.net.HttpURLConnection; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import org.cactoos.Scalar; @@ -54,15 +55,8 @@ public final class IdpToken implements Scalar { @Override @SneakyThrows public String value() { - /* - * @todo #1:45min/DEV fix 403 Forbidden error when trying to get - * token from IDP. It seems that the user hasn't enough permissions - * to get the token from IDP. We need to configure Keycloak to allow - * the user to read the token. See the following link for more info: - * https://www.keycloak.org/docs/latest/server_admin/#retrieving-external-idp-tokens - */ - new JdkRequest( - "%s//broker/%s/token".formatted( + return new JdkRequest( + "%s/broker/%s/token".formatted( this.url, this.provider ) @@ -72,8 +66,11 @@ public String value() { HttpHeaders.AUTHORIZATION, "Bearer %s".formatted(this.jwt.getTokenValue()) ).fetch() - .as(RestResponse.class); - return null; + .as(RestResponse.class) + .assertStatus(HttpURLConnection.HTTP_OK) + .body() + .split("&")[0] + .split("=")[1]; } } From b0d539d742741a150695cc3ae99cd2dbc01faf72 Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Thu, 25 Jan 2024 18:03:43 +0300 Subject: [PATCH 02/12] Refactored --- .../pmo/platforms/github/InviteCollaborator.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/main/java/git/tracehub/pmo/platforms/github/InviteCollaborator.java b/src/main/java/git/tracehub/pmo/platforms/github/InviteCollaborator.java index 4ada9c9..358d643 100644 --- a/src/main/java/git/tracehub/pmo/platforms/github/InviteCollaborator.java +++ b/src/main/java/git/tracehub/pmo/platforms/github/InviteCollaborator.java @@ -18,9 +18,8 @@ package git.tracehub.pmo.platforms.github; import com.jcabi.github.Coordinates; -import com.jcabi.github.RtGithub; +import com.jcabi.github.Github; import git.tracehub.pmo.platforms.Action; -import git.tracehub.pmo.platforms.RepoPath; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; @@ -43,18 +42,16 @@ public final class InviteCollaborator implements Action { private final String username; /** - * Token. + * Github. */ - private final String token; + private final Github github; @Override @SneakyThrows public void exec() { - new RtGithub(this.token).repos() + this.github.repos() .get( - new Coordinates.Simple( - new RepoPath(this.location).value() - ) + new Coordinates.Simple(this.location) ).collaborators() .add(this.username); } From b91c5868f41de095909ed4d3c766eeee752a1bf8 Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Thu, 25 Jan 2024 18:04:03 +0300 Subject: [PATCH 03/12] Code moved from action --- pom.xml | 6 ++++++ .../git/tracehub/pmo/controller/ProjectController.java | 8 ++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 866b1ae..2431c45 100644 --- a/pom.xml +++ b/pom.xml @@ -51,6 +51,7 @@ SOFTWARE. 1.20.1 3.2.0 1.19.3 + 4.0.2 @@ -153,6 +154,11 @@ SOFTWARE. testcontainers ${testcontainers.version} + + org.glassfish.grizzly + grizzly-http-server + ${grizzly.version} + org.testcontainers postgresql diff --git a/src/main/java/git/tracehub/pmo/controller/ProjectController.java b/src/main/java/git/tracehub/pmo/controller/ProjectController.java index ee7d4f4..065c637 100644 --- a/src/main/java/git/tracehub/pmo/controller/ProjectController.java +++ b/src/main/java/git/tracehub/pmo/controller/ProjectController.java @@ -17,6 +17,8 @@ package git.tracehub.pmo.controller; +import com.jcabi.github.RtGithub; +import git.tracehub.pmo.platforms.RepoPath; import git.tracehub.pmo.platforms.github.InviteCollaborator; import git.tracehub.pmo.project.Project; import git.tracehub.pmo.project.Projects; @@ -117,9 +119,11 @@ public Project employ( */ if (new ExistsRole(jwt, "user_github").value()) { new InviteCollaborator( - created.getLocation(), + new RepoPath(created.getLocation()).value(), "tracehubgit", - new IdpToken(jwt, "github", this.url).value() + new RtGithub( + new IdpToken(jwt, "github", this.url).value() + ) ).exec(); } return created; From 38c2710fc8120482db6a5bb2cd83e7c0a96008c2 Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Thu, 25 Jan 2024 18:04:15 +0300 Subject: [PATCH 04/12] Unit tests --- .../github/InviteCollaboratorTest.java | 60 +++++++++++++++++++ .../pmo/platforms/github/package-info.java | 23 +++++++ src/test/java/it/security/package-info.java | 23 +++++++ 3 files changed, 106 insertions(+) create mode 100644 src/test/java/git/tracehub/pmo/platforms/github/InviteCollaboratorTest.java create mode 100644 src/test/java/git/tracehub/pmo/platforms/github/package-info.java create mode 100644 src/test/java/it/security/package-info.java diff --git a/src/test/java/git/tracehub/pmo/platforms/github/InviteCollaboratorTest.java b/src/test/java/git/tracehub/pmo/platforms/github/InviteCollaboratorTest.java new file mode 100644 index 0000000..6f2740e --- /dev/null +++ b/src/test/java/git/tracehub/pmo/platforms/github/InviteCollaboratorTest.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.platforms.github; + +import com.jcabi.github.Collaborators; +import com.jcabi.github.Github; +import com.jcabi.github.Repo; +import com.jcabi.github.Repos; +import com.jcabi.github.mock.MkGithub; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +/** + * Test suite for {@link InviteCollaborator}. + * + * @since 0.0.0 + */ +final class InviteCollaboratorTest { + + @Test + void invitesCollaboratorSuccessfully() { + final Github github = Mockito.mock(Github.class); + final Repos repos = Mockito.mock(Repos.class); + final Repo repo = Mockito.mock(Repo.class); + Mockito.when(github.repos()).thenReturn(repos); + Mockito.when(repos.get(Mockito.any())).thenReturn(repo); + Mockito.when(repo.collaborators()).thenReturn(Mockito.mock(Collaborators.class)); + new InviteCollaborator("user/repo", "user", github).exec(); + Mockito.verify(github, Mockito.times(1)).repos(); + Mockito.verify(repos, Mockito.times(1)).get(Mockito.any()); + Mockito.verify(repo, Mockito.times(1)).collaborators(); + } + + @Test + void trowsOnInvalidLocation() { + Assertions.assertThrows( + IllegalArgumentException.class, + () -> new InviteCollaborator("user", "user", new MkGithub("user")) + .exec(), + "Exception is not thrown or valid" + ); + } + +} diff --git a/src/test/java/git/tracehub/pmo/platforms/github/package-info.java b/src/test/java/git/tracehub/pmo/platforms/github/package-info.java new file mode 100644 index 0000000..79c7e03 --- /dev/null +++ b/src/test/java/git/tracehub/pmo/platforms/github/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. + */ + +/** + * Github Integration Tests. + * + * @since 0.0.0 + */ +package git.tracehub.pmo.platforms.github; diff --git a/src/test/java/it/security/package-info.java b/src/test/java/it/security/package-info.java new file mode 100644 index 0000000..c2a6119 --- /dev/null +++ b/src/test/java/it/security/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. + */ + +/** + * Security Integration Tests. + * + * @since 0.0.0 + */ +package it.security; From d56eb8a95519b7cc08d58d46344038f28357cce7 Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Thu, 25 Jan 2024 18:04:23 +0300 Subject: [PATCH 05/12] Integrations added --- src/test/java/it/ServerIntegration.java | 62 ++++++++++++++++++++ src/test/java/it/security/IdpTokenIT.java | 71 +++++++++++++++++++++++ src/test/resources/application-web.yaml | 15 +++++ 3 files changed, 148 insertions(+) create mode 100644 src/test/java/it/ServerIntegration.java create mode 100644 src/test/java/it/security/IdpTokenIT.java create mode 100644 src/test/resources/application-web.yaml diff --git a/src/test/java/it/ServerIntegration.java b/src/test/java/it/ServerIntegration.java new file mode 100644 index 0000000..eb93224 --- /dev/null +++ b/src/test/java/it/ServerIntegration.java @@ -0,0 +1,62 @@ +/* + * 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; + +import com.jcabi.http.mock.MkContainer; +import com.jcabi.http.mock.MkGrizzlyContainer; +import java.io.IOException; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.springframework.test.annotation.DirtiesContext; + +/** + * Web Server Integration Suite. + * + * @since 0.0.0 + */ +@DirtiesContext +@SuppressWarnings({ + "JTCOP.RuleCorrectTestName", + "JTCOP.RuleAllTestsHaveProductionClass", + "PMD.ProhibitPublicStaticMethods" +}) +public interface ServerIntegration { + + /** + * Web Server Container. + */ + MkContainer SERVER = new MkGrizzlyContainer(); + + /** + * Start container. + * + * @throws IOException If fails + */ + @BeforeAll + static void start() throws IOException { + ServerIntegration.SERVER.start(); + } + + /** + * Stop container. + */ + @AfterAll + static void stop() { + ServerIntegration.SERVER.stop(); + } +} diff --git a/src/test/java/it/security/IdpTokenIT.java b/src/test/java/it/security/IdpTokenIT.java new file mode 100644 index 0000000..4cb1a1d --- /dev/null +++ b/src/test/java/it/security/IdpTokenIT.java @@ -0,0 +1,71 @@ +/* + * 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.security; + +import com.jcabi.http.mock.MkAnswer; +import git.tracehub.pmo.PmoApplication; +import git.tracehub.pmo.security.IdpToken; +import it.PostgresIntegration; +import it.ServerIntegration; +import java.net.HttpURLConnection; +import org.hamcrest.MatcherAssert; +import org.hamcrest.core.IsEqual; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.security.oauth2.jwt.Jwt; +import org.springframework.test.context.ActiveProfiles; + +/** + * Integration tests for {@link IdpToken}. + * + * @since 0.0.0 + */ +@ActiveProfiles("web") +@SpringBootTest( + classes = PmoApplication.class, + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT +) +@SuppressWarnings("JTCOP.RuleAllTestsHaveProductionClass") +final class IdpTokenIT + implements ServerIntegration, PostgresIntegration { + + @Test + void retrievesIdpTokenSuccessfully() { + final String url = ServerIntegration.SERVER.home().toString(); + final String expected = "token"; + ServerIntegration.SERVER.next( + new MkAnswer.Simple( + HttpURLConnection.HTTP_OK, + "access_token=%s&expires_in=3600&token_type=bearer" + .formatted(expected) + ) + ); + final String token = new IdpToken( + Mockito.mock(Jwt.class), + "provider", + url.substring(0, url.length() - 1) + ).value(); + MatcherAssert.assertThat( + "Access token %s isn't correct".formatted(token), + token, + new IsEqual<>(expected) + ); + } + +} diff --git a/src/test/resources/application-web.yaml b/src/test/resources/application-web.yaml new file mode 100644 index 0000000..ada6504 --- /dev/null +++ b/src/test/resources/application-web.yaml @@ -0,0 +1,15 @@ +application: + title: IT + version: 0.0.1 +spring: + datasource: + username: test + password: test + liquibase: + user: test + password: test + security: + oauth2: + resourceserver: + jwt: + issuer-uri: url From 6a402e48c27da57e7bc700a4831aae4a1d0fc717 Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Tue, 30 Jan 2024 14:37:36 +0300 Subject: [PATCH 06/12] Unit test added --- .../tracehub/pmo/security/IpdTokenTest.java | 48 ++++++++++++++++ src/test/resources/data/realm.json | 55 ++++++++++++++++--- 2 files changed, 95 insertions(+), 8 deletions(-) create mode 100644 src/test/java/git/tracehub/pmo/security/IpdTokenTest.java diff --git a/src/test/java/git/tracehub/pmo/security/IpdTokenTest.java b/src/test/java/git/tracehub/pmo/security/IpdTokenTest.java new file mode 100644 index 0000000..bd4937d --- /dev/null +++ b/src/test/java/git/tracehub/pmo/security/IpdTokenTest.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.security; + +import java.io.IOException; +import org.junit.jupiter.api.Test; +import org.llorllale.cactoos.matchers.Assertion; +import org.llorllale.cactoos.matchers.Throws; +import org.mockito.Mockito; +import org.springframework.security.oauth2.jwt.Jwt; + +/** + * Test suite for {@link IdpToken}. + * + * @since 0.0.0 + */ +final class IpdTokenTest { + + @Test + @SuppressWarnings("JTCOP.RuleAssertionMessage") + void throwsOnInvalidHost() { + new Assertion<>( + "Exception is not thrown or valid", + () -> new IdpToken( + Mockito.mock(Jwt.class), + "provider", + "http://localhost:1000" + ).value(), + new Throws<>(IOException.class) + ).affirm(); + } + +} diff --git a/src/test/resources/data/realm.json b/src/test/resources/data/realm.json index 550b39f..edd501e 100644 --- a/src/test/resources/data/realm.json +++ b/src/test/resources/data/realm.json @@ -43,13 +43,35 @@ "quickLoginCheckMilliSeconds": 1000, "maxDeltaTimeSeconds": 43200, "failureFactor": 30, + "roles": { + "realm": [ + { + "id": "79dad14b-4887-4002-a3f3-05dbd3c8d1bf", + "name": "user_github", + "description": "", + "composite": false, + "clientRole": false, + "containerId": "test", + "attributes": {} + }, + { + "id": "d6258175-81e1-4185-956f-19be7552950e", + "name": "read-token", + "description": "", + "composite": false, + "clientRole": false, + "containerId": "test", + "attributes": {} + } + ] + }, "defaultRole": { "id": "ae0de638-8b16-4d7f-9c1d-e1a55129f895", - "name": "default-roles-baeldung", + "name": "default-roles-test", "description": "${role_default-roles}", "composite": true, "clientRole": false, - "containerId": "baeldung" + "containerId": "test" }, "requiredCredentials": [ "password" @@ -112,13 +134,13 @@ "clientId": "account", "name": "${client_account}", "rootUrl": "${authBaseUrl}", - "baseUrl": "/realms/baeldung/account/", + "baseUrl": "/realms/test/account/", "surrogateAuthRequired": false, "enabled": true, "alwaysDisplayInConsole": false, "clientAuthenticatorType": "client-secret", "redirectUris": [ - "/realms/baeldung/account/*" + "/realms/test/account/*" ], "webOrigins": [], "notBefore": 0, @@ -153,13 +175,13 @@ "clientId": "account-console", "name": "${client_account-console}", "rootUrl": "${authBaseUrl}", - "baseUrl": "/realms/baeldung/account/", + "baseUrl": "/realms/test/account/", "surrogateAuthRequired": false, "enabled": true, "alwaysDisplayInConsole": false, "clientAuthenticatorType": "client-secret", "redirectUris": [ - "/realms/baeldung/account/*" + "/realms/test/account/*" ], "webOrigins": [], "notBefore": 0, @@ -414,6 +436,16 @@ ] } ], + "groups": [ + { + "id": "c0dde556-f6b3-4025-8de2-55e42319e1d3", + "name": "broker", + "path": "/broker" + } + ], + "defaultGroups": [ + "/broker" + ], "clientScopes": [ { "id": "b7ffedbd-ba94-4fd4-ba1e-0145252e10ef", @@ -1795,9 +1827,16 @@ "clientRoles": { "account": [ "view-profile", - "manage-account" + "manage-account", + "user_github" + ], + "broker": [ + "read-token" ] - } + }, + "realmRoles": [ + "user_github" + ] } ] } \ No newline at end of file From e24cc4d07fee855dbf3274c95d66cdcf7d618ced Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Tue, 30 Jan 2024 16:44:25 +0300 Subject: [PATCH 07/12] Tests for controller --- .../pmo/controller/ProjectControllerTest.java | 103 ++++++++++++++++++ .../pmo/controller}/package-info.java | 4 +- .../tracehub/pmo/security/IpdTokenTest.java | 31 ++++++ src/test/java/it/ServerIntegration.java | 62 ----------- src/test/java/it/security/IdpTokenIT.java | 71 ------------ src/test/resources/data/project.json | 5 + 6 files changed, 141 insertions(+), 135 deletions(-) create mode 100644 src/test/java/git/tracehub/pmo/controller/ProjectControllerTest.java rename src/test/java/{it/security => git/tracehub/pmo/controller}/package-info.java (93%) delete mode 100644 src/test/java/it/ServerIntegration.java delete mode 100644 src/test/java/it/security/IdpTokenIT.java create mode 100644 src/test/resources/data/project.json diff --git a/src/test/java/git/tracehub/pmo/controller/ProjectControllerTest.java b/src/test/java/git/tracehub/pmo/controller/ProjectControllerTest.java new file mode 100644 index 0000000..92a0a59 --- /dev/null +++ b/src/test/java/git/tracehub/pmo/controller/ProjectControllerTest.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.controller; + +import git.tracehub.pmo.project.Projects; +import git.tracehub.pmo.security.IdpToken; +import io.github.eocqrs.eokson.Jocument; +import io.github.eocqrs.eokson.JsonOf; +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 IdpToken}. + * + * @since 0.0.0 + */ +@ActiveProfiles("web") +@ExtendWith(SpringExtension.class) +@WebMvcTest(controllers = ProjectController.class) +final class ProjectControllerTest { + + /** + * Mocked mvc. + */ + @Autowired + private MockMvc mvc; + + /** + * Projects. + */ + @MockBean + @SuppressWarnings("PMD.UnusedPrivateField") + private Projects projects; + + @Test + void returnsForbiddenOnUnauthorizedUser() throws Exception { + this.mvc.perform( + MockMvcRequestBuilders.post("/") + .contentType(MediaType.APPLICATION_JSON) + ).andExpect(MockMvcResultMatchers.status().isForbidden()); + } + + @Test + void returnsProjectByUser() throws Exception { + this.mvc.perform( + MockMvcRequestBuilders.get("/") + .with(SecurityMockMvcRequestPostProcessors.jwt()) + .contentType(MediaType.APPLICATION_JSON) + ).andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void returnsProjectById() throws Exception { + this.mvc.perform( + MockMvcRequestBuilders.get("/74bb5ec8-0e6b-4618-bfa4-a0b76b7b312d") + .with(SecurityMockMvcRequestPostProcessors.jwt()) + .contentType(MediaType.APPLICATION_JSON) + ).andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void createsNewProject() throws Exception { + this.mvc.perform( + MockMvcRequestBuilders.post("/") + .with(SecurityMockMvcRequestPostProcessors.jwt()) + .contentType(MediaType.APPLICATION_JSON) + .content( + new Jocument( + new JsonOf( + new ResourceOf("data/project.json").stream() + ) + ).toString() + ) + ).andExpect(MockMvcResultMatchers.status().isCreated()); + } + +} diff --git a/src/test/java/it/security/package-info.java b/src/test/java/git/tracehub/pmo/controller/package-info.java similarity index 93% rename from src/test/java/it/security/package-info.java rename to src/test/java/git/tracehub/pmo/controller/package-info.java index c2a6119..5ca9dfa 100644 --- a/src/test/java/it/security/package-info.java +++ b/src/test/java/git/tracehub/pmo/controller/package-info.java @@ -16,8 +16,8 @@ */ /** - * Security Integration Tests. + * Controllers Tests. * * @since 0.0.0 */ -package it.security; +package git.tracehub.pmo.controller; diff --git a/src/test/java/git/tracehub/pmo/security/IpdTokenTest.java b/src/test/java/git/tracehub/pmo/security/IpdTokenTest.java index bd4937d..1444bd7 100644 --- a/src/test/java/git/tracehub/pmo/security/IpdTokenTest.java +++ b/src/test/java/git/tracehub/pmo/security/IpdTokenTest.java @@ -17,7 +17,13 @@ package git.tracehub.pmo.security; +import com.jcabi.http.mock.MkAnswer; +import com.jcabi.http.mock.MkContainer; +import com.jcabi.http.mock.MkGrizzlyContainer; import java.io.IOException; +import java.net.HttpURLConnection; +import org.hamcrest.MatcherAssert; +import org.hamcrest.core.IsEqual; import org.junit.jupiter.api.Test; import org.llorllale.cactoos.matchers.Assertion; import org.llorllale.cactoos.matchers.Throws; @@ -31,6 +37,31 @@ */ final class IpdTokenTest { + @Test + void retrievesTokenSuccessfully() throws IOException { + final String expected = "token"; + final MkContainer container = new MkGrizzlyContainer() + .next( + new MkAnswer.Simple( + HttpURLConnection.HTTP_OK, + "access_token=%s&expires_in=3600&token_type=bearer" + .formatted(expected) + ) + ).start(); + final String url = container.home().toString(); + final String token = new IdpToken( + Mockito.mock(Jwt.class), + "provider", + url.substring(0, url.length() - 1) + ).value(); + MatcherAssert.assertThat( + "Access token %s isn't correct".formatted(token), + token, + new IsEqual<>(expected) + ); + container.stop(); + } + @Test @SuppressWarnings("JTCOP.RuleAssertionMessage") void throwsOnInvalidHost() { diff --git a/src/test/java/it/ServerIntegration.java b/src/test/java/it/ServerIntegration.java deleted file mode 100644 index eb93224..0000000 --- a/src/test/java/it/ServerIntegration.java +++ /dev/null @@ -1,62 +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 it; - -import com.jcabi.http.mock.MkContainer; -import com.jcabi.http.mock.MkGrizzlyContainer; -import java.io.IOException; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.springframework.test.annotation.DirtiesContext; - -/** - * Web Server Integration Suite. - * - * @since 0.0.0 - */ -@DirtiesContext -@SuppressWarnings({ - "JTCOP.RuleCorrectTestName", - "JTCOP.RuleAllTestsHaveProductionClass", - "PMD.ProhibitPublicStaticMethods" -}) -public interface ServerIntegration { - - /** - * Web Server Container. - */ - MkContainer SERVER = new MkGrizzlyContainer(); - - /** - * Start container. - * - * @throws IOException If fails - */ - @BeforeAll - static void start() throws IOException { - ServerIntegration.SERVER.start(); - } - - /** - * Stop container. - */ - @AfterAll - static void stop() { - ServerIntegration.SERVER.stop(); - } -} diff --git a/src/test/java/it/security/IdpTokenIT.java b/src/test/java/it/security/IdpTokenIT.java deleted file mode 100644 index 4cb1a1d..0000000 --- a/src/test/java/it/security/IdpTokenIT.java +++ /dev/null @@ -1,71 +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 it.security; - -import com.jcabi.http.mock.MkAnswer; -import git.tracehub.pmo.PmoApplication; -import git.tracehub.pmo.security.IdpToken; -import it.PostgresIntegration; -import it.ServerIntegration; -import java.net.HttpURLConnection; -import org.hamcrest.MatcherAssert; -import org.hamcrest.core.IsEqual; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.security.oauth2.jwt.Jwt; -import org.springframework.test.context.ActiveProfiles; - -/** - * Integration tests for {@link IdpToken}. - * - * @since 0.0.0 - */ -@ActiveProfiles("web") -@SpringBootTest( - classes = PmoApplication.class, - webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT -) -@SuppressWarnings("JTCOP.RuleAllTestsHaveProductionClass") -final class IdpTokenIT - implements ServerIntegration, PostgresIntegration { - - @Test - void retrievesIdpTokenSuccessfully() { - final String url = ServerIntegration.SERVER.home().toString(); - final String expected = "token"; - ServerIntegration.SERVER.next( - new MkAnswer.Simple( - HttpURLConnection.HTTP_OK, - "access_token=%s&expires_in=3600&token_type=bearer" - .formatted(expected) - ) - ); - final String token = new IdpToken( - Mockito.mock(Jwt.class), - "provider", - url.substring(0, url.length() - 1) - ).value(); - MatcherAssert.assertThat( - "Access token %s isn't correct".formatted(token), - token, - new IsEqual<>(expected) - ); - } - -} diff --git a/src/test/resources/data/project.json b/src/test/resources/data/project.json new file mode 100644 index 0000000..33ce260 --- /dev/null +++ b/src/test/resources/data/project.json @@ -0,0 +1,5 @@ +{ + "name": "IT project", + "active": true, + "location": "github@hizmailovich/draft:master" +} \ No newline at end of file From a37eb36c720bb4e6159c335e0a5b6ab3f667f69d Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Tue, 30 Jan 2024 16:52:25 +0300 Subject: [PATCH 08/12] Doc fixed --- .../git/tracehub/pmo/controller/ProjectControllerTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/java/git/tracehub/pmo/controller/ProjectControllerTest.java b/src/test/java/git/tracehub/pmo/controller/ProjectControllerTest.java index 92a0a59..7cdc406 100644 --- a/src/test/java/git/tracehub/pmo/controller/ProjectControllerTest.java +++ b/src/test/java/git/tracehub/pmo/controller/ProjectControllerTest.java @@ -18,7 +18,6 @@ package git.tracehub.pmo.controller; import git.tracehub.pmo.project.Projects; -import git.tracehub.pmo.security.IdpToken; import io.github.eocqrs.eokson.Jocument; import io.github.eocqrs.eokson.JsonOf; import org.cactoos.io.ResourceOf; @@ -36,7 +35,7 @@ import org.springframework.test.web.servlet.result.MockMvcResultMatchers; /** - * Test suite for {@link IdpToken}. + * Test suite for {@link ProjectController}. * * @since 0.0.0 */ From 7226537965c273d115581ccf7bb91370dfa451da Mon Sep 17 00:00:00 2001 From: Hanna Izmailovich Date: Tue, 30 Jan 2024 18:46:37 +0300 Subject: [PATCH 09/12] Scope added Co-authored-by: Aliaksei Bialiauski --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index 2431c45..8f9385a 100644 --- a/pom.xml +++ b/pom.xml @@ -158,6 +158,7 @@ SOFTWARE. org.glassfish.grizzly grizzly-http-server ${grizzly.version} + test org.testcontainers From 81d7bc0f23c4dad1811d78f8d9d4a741b980a01b Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Tue, 30 Jan 2024 19:06:24 +0300 Subject: [PATCH 10/12] Mocked objects added --- .../github/InviteCollaboratorTest.java | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/test/java/git/tracehub/pmo/platforms/github/InviteCollaboratorTest.java b/src/test/java/git/tracehub/pmo/platforms/github/InviteCollaboratorTest.java index 6f2740e..231e311 100644 --- a/src/test/java/git/tracehub/pmo/platforms/github/InviteCollaboratorTest.java +++ b/src/test/java/git/tracehub/pmo/platforms/github/InviteCollaboratorTest.java @@ -17,14 +17,14 @@ package git.tracehub.pmo.platforms.github; -import com.jcabi.github.Collaborators; -import com.jcabi.github.Github; import com.jcabi.github.Repo; import com.jcabi.github.Repos; import com.jcabi.github.mock.MkGithub; +import java.io.IOException; +import org.hamcrest.MatcherAssert; +import org.hamcrest.core.IsEqual; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import org.mockito.Mockito; /** * Test suite for {@link InviteCollaborator}. @@ -34,17 +34,18 @@ final class InviteCollaboratorTest { @Test - void invitesCollaboratorSuccessfully() { - final Github github = Mockito.mock(Github.class); - final Repos repos = Mockito.mock(Repos.class); - final Repo repo = Mockito.mock(Repo.class); - Mockito.when(github.repos()).thenReturn(repos); - Mockito.when(repos.get(Mockito.any())).thenReturn(repo); - Mockito.when(repo.collaborators()).thenReturn(Mockito.mock(Collaborators.class)); - new InviteCollaborator("user/repo", "user", github).exec(); - Mockito.verify(github, Mockito.times(1)).repos(); - Mockito.verify(repos, Mockito.times(1)).get(Mockito.any()); - Mockito.verify(repo, Mockito.times(1)).collaborators(); + void invitesCollaboratorSuccessfully() throws IOException { + final String collaborator = "name"; + final MkGithub github = new MkGithub("user"); + final Repo repo = github.repos().create( + new Repos.RepoCreate("repo", false) + ); + new InviteCollaborator("user/repo", collaborator, github).exec(); + MatcherAssert.assertThat( + "Collaborator %s isn't invited".formatted(collaborator), + repo.collaborators().isCollaborator(collaborator), + new IsEqual<>(true) + ); } @Test From a8e45570a7de367faff931f15f0c9b9587427ebc Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Tue, 30 Jan 2024 19:06:32 +0300 Subject: [PATCH 11/12] Doc fixed --- .../java/git/tracehub/pmo/platforms/github/package-info.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/git/tracehub/pmo/platforms/github/package-info.java b/src/test/java/git/tracehub/pmo/platforms/github/package-info.java index 79c7e03..1db16f4 100644 --- a/src/test/java/git/tracehub/pmo/platforms/github/package-info.java +++ b/src/test/java/git/tracehub/pmo/platforms/github/package-info.java @@ -16,7 +16,7 @@ */ /** - * Github Integration Tests. + * Github Platform Tests. * * @since 0.0.0 */ From 2f2eb7c9f9b96e45e5aca83a1cd5593508b9308a Mon Sep 17 00:00:00 2001 From: hizmailovich Date: Wed, 31 Jan 2024 15:28:12 +0300 Subject: [PATCH 12/12] Message fixed --- .../tracehub/pmo/platforms/github/InviteCollaboratorTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/git/tracehub/pmo/platforms/github/InviteCollaboratorTest.java b/src/test/java/git/tracehub/pmo/platforms/github/InviteCollaboratorTest.java index 231e311..ad99202 100644 --- a/src/test/java/git/tracehub/pmo/platforms/github/InviteCollaboratorTest.java +++ b/src/test/java/git/tracehub/pmo/platforms/github/InviteCollaboratorTest.java @@ -42,7 +42,8 @@ void invitesCollaboratorSuccessfully() throws IOException { ); new InviteCollaborator("user/repo", collaborator, github).exec(); MatcherAssert.assertThat( - "Collaborator %s isn't invited".formatted(collaborator), + "Collaborator %s isn't invited as expected" + .formatted(collaborator), repo.collaborators().isCollaborator(collaborator), new IsEqual<>(true) );