From 473792061d40a0027b57d65a97f3da06e4b8c7bd Mon Sep 17 00:00:00 2001 From: Fiete Ostkamp Date: Wed, 16 Aug 2023 08:01:39 +0000 Subject: Consistently use the bff name in the bff code base - rename package name from org.onap.portal.bff to org.onap.portalng.bff - replace all other occurences of portal-bff with bff Other: - remove Sonarqube plugin Issue-ID: PORTALNG-40 Signed-off-by: Fiete Ostkamp Change-Id: I50548630212e46a0ab84c88ff5fef743dafe9d38 --- .../main/java/org/onap/portal/bff/Application.java | 36 -- .../java/org/onap/portalng/bff/Application.java | 36 ++ .../main/resources/application-access-control.yml | 2 +- app/src/main/resources/application-development.yml | 4 +- app/src/main/resources/application-local.yml | 4 +- app/src/main/resources/application.yml | 4 +- .../onap/portal/bff/ApiDocsIntegrationTest.java | 40 -- .../org/onap/portal/bff/BaseIntegrationTest.java | 241 ----------- .../portal/bff/HealthCheckIntegrationTest.java | 48 --- .../java/org/onap/portal/bff/TokenGenerator.java | 122 ------ .../org/onap/portal/bff/actions/ActionDto.java | 39 -- .../onap/portal/bff/actions/ActionFixtures.java | 106 ----- .../org/onap/portal/bff/actions/ActionsMocks.java | 228 ----------- .../bff/actions/CreateActionsIntegrationTest.java | 85 ---- .../bff/actions/GetActionsIntegrationTest.java | 79 ---- .../bff/actions/ListActionsIntegrationTest.java | 78 ---- .../portal/bff/headers/XRequestIdHeaderTest.java | 75 ---- .../idtoken/IdTokenExchangeFilterFunctionTest.java | 89 ---- .../CreatePreferencesIntegrationTest.java | 115 ------ .../preferences/GetPreferencesIntegrationTest.java | 77 ---- .../portal/bff/preferences/PreferencesMocks.java | 182 --------- .../UpdatePreferencesIntegrationTest.java | 114 ------ .../bff/roles/ListRealmRolesIntegrationTest.java | 88 ---- .../java/org/onap/portal/bff/roles/RolesMocks.java | 57 --- .../bff/users/CreateUserIntegrationTest.java | 307 -------------- .../bff/users/DeleteUserIntegrationTest.java | 83 ---- .../bff/users/GetUserDetailIntegrationTest.java | 126 ------ .../users/ListAssignedRolesIntegrationTest.java | 111 ----- .../users/ListAvailableRolesIntegrationTest.java | 113 ----- .../portal/bff/users/ListUsersIntegrationTest.java | 238 ----------- .../users/UpdateAssignedRolesIntegrationTest.java | 453 --------------------- .../bff/users/UpdateUserIntegrationTest.java | 134 ------ .../users/UpdateUserPasswordIntegrationTest.java | 107 ----- .../onap/portalng/bff/ApiDocsIntegrationTest.java | 40 ++ .../org/onap/portalng/bff/BaseIntegrationTest.java | 241 +++++++++++ .../portalng/bff/HealthCheckIntegrationTest.java | 48 +++ .../java/org/onap/portalng/bff/TokenGenerator.java | 122 ++++++ .../org/onap/portalng/bff/actions/ActionDto.java | 39 ++ .../onap/portalng/bff/actions/ActionFixtures.java | 106 +++++ .../onap/portalng/bff/actions/ActionsMocks.java | 228 +++++++++++ .../bff/actions/CreateActionsIntegrationTest.java | 85 ++++ .../bff/actions/GetActionsIntegrationTest.java | 79 ++++ .../bff/actions/ListActionsIntegrationTest.java | 78 ++++ .../portalng/bff/headers/XRequestIdHeaderTest.java | 75 ++++ .../idtoken/IdTokenExchangeFilterFunctionTest.java | 89 ++++ .../CreatePreferencesIntegrationTest.java | 115 ++++++ .../preferences/GetPreferencesIntegrationTest.java | 77 ++++ .../portalng/bff/preferences/PreferencesMocks.java | 182 +++++++++ .../UpdatePreferencesIntegrationTest.java | 114 ++++++ .../bff/roles/ListRealmRolesIntegrationTest.java | 88 ++++ .../org/onap/portalng/bff/roles/RolesMocks.java | 57 +++ .../bff/users/CreateUserIntegrationTest.java | 307 ++++++++++++++ .../bff/users/DeleteUserIntegrationTest.java | 83 ++++ .../bff/users/GetUserDetailIntegrationTest.java | 126 ++++++ .../users/ListAssignedRolesIntegrationTest.java | 111 +++++ .../users/ListAvailableRolesIntegrationTest.java | 113 +++++ .../bff/users/ListUsersIntegrationTest.java | 238 +++++++++++ .../users/UpdateAssignedRolesIntegrationTest.java | 453 +++++++++++++++++++++ .../bff/users/UpdateUserIntegrationTest.java | 134 ++++++ .../users/UpdateUserPasswordIntegrationTest.java | 107 +++++ .../test/resources/application-access-control.yml | 2 +- app/src/test/resources/application-development.yml | 2 +- app/src/test/resources/application.yml | 2 +- 63 files changed, 3581 insertions(+), 3581 deletions(-) delete mode 100644 app/src/main/java/org/onap/portal/bff/Application.java create mode 100644 app/src/main/java/org/onap/portalng/bff/Application.java delete mode 100644 app/src/test/java/org/onap/portal/bff/ApiDocsIntegrationTest.java delete mode 100644 app/src/test/java/org/onap/portal/bff/BaseIntegrationTest.java delete mode 100644 app/src/test/java/org/onap/portal/bff/HealthCheckIntegrationTest.java delete mode 100644 app/src/test/java/org/onap/portal/bff/TokenGenerator.java delete mode 100644 app/src/test/java/org/onap/portal/bff/actions/ActionDto.java delete mode 100644 app/src/test/java/org/onap/portal/bff/actions/ActionFixtures.java delete mode 100644 app/src/test/java/org/onap/portal/bff/actions/ActionsMocks.java delete mode 100644 app/src/test/java/org/onap/portal/bff/actions/CreateActionsIntegrationTest.java delete mode 100644 app/src/test/java/org/onap/portal/bff/actions/GetActionsIntegrationTest.java delete mode 100644 app/src/test/java/org/onap/portal/bff/actions/ListActionsIntegrationTest.java delete mode 100644 app/src/test/java/org/onap/portal/bff/headers/XRequestIdHeaderTest.java delete mode 100644 app/src/test/java/org/onap/portal/bff/idtoken/IdTokenExchangeFilterFunctionTest.java delete mode 100644 app/src/test/java/org/onap/portal/bff/preferences/CreatePreferencesIntegrationTest.java delete mode 100644 app/src/test/java/org/onap/portal/bff/preferences/GetPreferencesIntegrationTest.java delete mode 100644 app/src/test/java/org/onap/portal/bff/preferences/PreferencesMocks.java delete mode 100644 app/src/test/java/org/onap/portal/bff/preferences/UpdatePreferencesIntegrationTest.java delete mode 100644 app/src/test/java/org/onap/portal/bff/roles/ListRealmRolesIntegrationTest.java delete mode 100644 app/src/test/java/org/onap/portal/bff/roles/RolesMocks.java delete mode 100644 app/src/test/java/org/onap/portal/bff/users/CreateUserIntegrationTest.java delete mode 100644 app/src/test/java/org/onap/portal/bff/users/DeleteUserIntegrationTest.java delete mode 100644 app/src/test/java/org/onap/portal/bff/users/GetUserDetailIntegrationTest.java delete mode 100644 app/src/test/java/org/onap/portal/bff/users/ListAssignedRolesIntegrationTest.java delete mode 100644 app/src/test/java/org/onap/portal/bff/users/ListAvailableRolesIntegrationTest.java delete mode 100644 app/src/test/java/org/onap/portal/bff/users/ListUsersIntegrationTest.java delete mode 100644 app/src/test/java/org/onap/portal/bff/users/UpdateAssignedRolesIntegrationTest.java delete mode 100644 app/src/test/java/org/onap/portal/bff/users/UpdateUserIntegrationTest.java delete mode 100644 app/src/test/java/org/onap/portal/bff/users/UpdateUserPasswordIntegrationTest.java create mode 100644 app/src/test/java/org/onap/portalng/bff/ApiDocsIntegrationTest.java create mode 100644 app/src/test/java/org/onap/portalng/bff/BaseIntegrationTest.java create mode 100644 app/src/test/java/org/onap/portalng/bff/HealthCheckIntegrationTest.java create mode 100644 app/src/test/java/org/onap/portalng/bff/TokenGenerator.java create mode 100644 app/src/test/java/org/onap/portalng/bff/actions/ActionDto.java create mode 100644 app/src/test/java/org/onap/portalng/bff/actions/ActionFixtures.java create mode 100644 app/src/test/java/org/onap/portalng/bff/actions/ActionsMocks.java create mode 100644 app/src/test/java/org/onap/portalng/bff/actions/CreateActionsIntegrationTest.java create mode 100644 app/src/test/java/org/onap/portalng/bff/actions/GetActionsIntegrationTest.java create mode 100644 app/src/test/java/org/onap/portalng/bff/actions/ListActionsIntegrationTest.java create mode 100644 app/src/test/java/org/onap/portalng/bff/headers/XRequestIdHeaderTest.java create mode 100644 app/src/test/java/org/onap/portalng/bff/idtoken/IdTokenExchangeFilterFunctionTest.java create mode 100644 app/src/test/java/org/onap/portalng/bff/preferences/CreatePreferencesIntegrationTest.java create mode 100644 app/src/test/java/org/onap/portalng/bff/preferences/GetPreferencesIntegrationTest.java create mode 100644 app/src/test/java/org/onap/portalng/bff/preferences/PreferencesMocks.java create mode 100644 app/src/test/java/org/onap/portalng/bff/preferences/UpdatePreferencesIntegrationTest.java create mode 100644 app/src/test/java/org/onap/portalng/bff/roles/ListRealmRolesIntegrationTest.java create mode 100644 app/src/test/java/org/onap/portalng/bff/roles/RolesMocks.java create mode 100644 app/src/test/java/org/onap/portalng/bff/users/CreateUserIntegrationTest.java create mode 100644 app/src/test/java/org/onap/portalng/bff/users/DeleteUserIntegrationTest.java create mode 100644 app/src/test/java/org/onap/portalng/bff/users/GetUserDetailIntegrationTest.java create mode 100644 app/src/test/java/org/onap/portalng/bff/users/ListAssignedRolesIntegrationTest.java create mode 100644 app/src/test/java/org/onap/portalng/bff/users/ListAvailableRolesIntegrationTest.java create mode 100644 app/src/test/java/org/onap/portalng/bff/users/ListUsersIntegrationTest.java create mode 100644 app/src/test/java/org/onap/portalng/bff/users/UpdateAssignedRolesIntegrationTest.java create mode 100644 app/src/test/java/org/onap/portalng/bff/users/UpdateUserIntegrationTest.java create mode 100644 app/src/test/java/org/onap/portalng/bff/users/UpdateUserPasswordIntegrationTest.java (limited to 'app/src') diff --git a/app/src/main/java/org/onap/portal/bff/Application.java b/app/src/main/java/org/onap/portal/bff/Application.java deleted file mode 100644 index 32a07e8..0000000 --- a/app/src/main/java/org/onap/portal/bff/Application.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * - * Copyright (c) 2022. Deutsche Telekom AG - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * - * - */ - -package org.onap.portal.bff; - -import org.onap.portal.bff.config.PortalBffConfig; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.context.properties.EnableConfigurationProperties; - -@EnableConfigurationProperties(PortalBffConfig.class) -@SpringBootApplication -public class Application { - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } -} diff --git a/app/src/main/java/org/onap/portalng/bff/Application.java b/app/src/main/java/org/onap/portalng/bff/Application.java new file mode 100644 index 0000000..679d103 --- /dev/null +++ b/app/src/main/java/org/onap/portalng/bff/Application.java @@ -0,0 +1,36 @@ +/* + * + * Copyright (c) 2022. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + * + */ + +package org.onap.portalng.bff; + +import org.onap.portalng.bff.config.BffConfig; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.EnableConfigurationProperties; + +@EnableConfigurationProperties(BffConfig.class) +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/app/src/main/resources/application-access-control.yml b/app/src/main/resources/application-access-control.yml index d967c53..450ab8a 100644 --- a/app/src/main/resources/application-access-control.yml +++ b/app/src/main/resources/application-access-control.yml @@ -1,4 +1,4 @@ -portal-bff.access-control: +bff.access-control: ACTIONS_CREATE: [ onap_admin, onap_designer, onap_operator ] ACTIONS_GET: [ onap_admin, onap_designer, onap_operator ] ACTIONS_LIST: [ onap_admin, onap_designer, onap_operator ] diff --git a/app/src/main/resources/application-development.yml b/app/src/main/resources/application-development.yml index 50dfb51..c7e869f 100644 --- a/app/src/main/resources/application-development.yml +++ b/app/src/main/resources/application-development.yml @@ -9,7 +9,7 @@ spring: registration: keycloak: provider: keycloak - client-id: portal-bff + client-id: bff client-secret: 5933482a-9f4c-44e0-9814-dca17e0a9137 authorization-grant-type: client_credentials resourceserver: @@ -22,7 +22,7 @@ management: exposure: include: "*" -portal-bff: +bff: realm: ONAP portal-prefs-url: ${PORTAL_PREFS_URL} portal-history-url: ${PORTAL_HISTORY_URL} diff --git a/app/src/main/resources/application-local.yml b/app/src/main/resources/application-local.yml index e90a13b..0cb6e6b 100644 --- a/app/src/main/resources/application-local.yml +++ b/app/src/main/resources/application-local.yml @@ -9,7 +9,7 @@ spring: registration: keycloak: provider: keycloak - client-id: portal-bff + client-id: bff client-secret: pKOuVH1bwRZoNzp5P5t4GV8CqcCJYVtr authorization-grant-type: client_credentials resourceserver: @@ -22,7 +22,7 @@ management: exposure: include: "*" -portal-bff: +bff: realm: ONAP portal-prefs-url: http://localhost:9001 portal-history-url: http://localhost:9002 diff --git a/app/src/main/resources/application.yml b/app/src/main/resources/application.yml index 83686b5..6e74453 100644 --- a/app/src/main/resources/application.yml +++ b/app/src/main/resources/application.yml @@ -16,7 +16,7 @@ management: spring: application: - name: portal-bff + name: bff profiles: include: - access-control @@ -40,7 +40,7 @@ spring: serialization: FAIL_ON_EMPTY_BEANS: false -portal-bff: +bff: realm: ${KEYCLOAK_REALM} portal-prefs-url: ${PORTAL_PREFS_URL} portal-history-url: ${PORTAL_HISTORY_URL} diff --git a/app/src/test/java/org/onap/portal/bff/ApiDocsIntegrationTest.java b/app/src/test/java/org/onap/portal/bff/ApiDocsIntegrationTest.java deleted file mode 100644 index 66edfee..0000000 --- a/app/src/test/java/org/onap/portal/bff/ApiDocsIntegrationTest.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * - * Copyright (c) 2022. Deutsche Telekom AG - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * - * - */ - -package org.onap.portal.bff; - -import org.junit.jupiter.api.Test; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; - -class ApiDocsIntegrationTest extends BaseIntegrationTest { - - @Test - void apiDocsAreAvailable() { - unauthenticatedRequestSpecification() - .given() - .accept(MediaType.TEXT_HTML_VALUE) - .when() - .get("/api-docs.html") - .then() - .statusCode(HttpStatus.OK.value()); - } -} diff --git a/app/src/test/java/org/onap/portal/bff/BaseIntegrationTest.java b/app/src/test/java/org/onap/portal/bff/BaseIntegrationTest.java deleted file mode 100644 index c02082c..0000000 --- a/app/src/test/java/org/onap/portal/bff/BaseIntegrationTest.java +++ /dev/null @@ -1,241 +0,0 @@ -/* - * - * Copyright (c) 2022. Deutsche Telekom AG - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * - * - */ - -package org.onap.portal.bff; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.tomakehurst.wiremock.client.WireMock; -import com.github.tomakehurst.wiremock.extension.responsetemplating.ResponseTemplateTransformer; -import com.nimbusds.jose.jwk.JWKSet; -import io.restassured.RestAssured; -import io.restassured.filter.log.RequestLoggingFilter; -import io.restassured.filter.log.ResponseLoggingFilter; -import io.restassured.specification.RequestSpecification; -import java.net.URISyntaxException; -import java.time.Clock; -import java.time.OffsetDateTime; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.UUID; -import org.apache.http.client.utils.URIBuilder; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.onap.portal.bff.config.IdTokenExchangeFilterFunction; -import org.onap.portal.bff.config.PortalBffConfig; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.boot.test.web.server.LocalServerPort; -import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock; -import org.springframework.cloud.contract.wiremock.WireMockConfigurationCustomizer; -import org.springframework.context.annotation.Bean; -import org.springframework.http.MediaType; - -/** Base class for all tests that has the common config including port, realm, logging and auth. */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -@AutoConfigureWireMock(port = 0) -public abstract class BaseIntegrationTest { - - @TestConfiguration - public static class Config { - @Bean - WireMockConfigurationCustomizer optionsCustomizer() { - return options -> options.extensions(new ResponseTemplateTransformer(true)); - } - } - - @LocalServerPort protected int port; - - @Value("${portal-bff.realm}") - protected String realm; - - @Autowired protected ObjectMapper objectMapper; - @Autowired private TokenGenerator tokenGenerator; - - @Autowired protected PortalBffConfig portalBffConfig; - - @BeforeAll - public static void setup() { - RestAssured.filters(new RequestLoggingFilter(), new ResponseLoggingFilter()); - } - - /** Mocks the OIDC auth flow. */ - @BeforeEach - public void mockAuth() { - WireMock.reset(); - - WireMock.stubFor( - WireMock.get( - WireMock.urlMatching( - String.format("/auth/realms/%s/protocol/openid-connect/certs", realm))) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", JWKSet.MIME_TYPE) - .withBody(tokenGenerator.getJwkSet().toString()))); - - final TokenGenerator.TokenGeneratorConfig config = - TokenGenerator.TokenGeneratorConfig.builder().port(port).realm(realm).build(); - - WireMock.stubFor( - WireMock.post( - WireMock.urlMatching( - String.format("/auth/realms/%s/protocol/openid-connect/token", realm))) - .withBasicAuth("test", "test") - .withRequestBody(WireMock.containing("grant_type=client_credentials")) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withBody( - objectMapper - .createObjectNode() - .put("token_type", "bearer") - .put("access_token", tokenGenerator.generateToken(config)) - .put("expires_in", config.getExpireIn().getSeconds()) - .put("refresh_token", tokenGenerator.generateToken(config)) - .put("refresh_expires_in", config.getExpireIn().getSeconds()) - .put("not-before-policy", 0) - .put("session_state", UUID.randomUUID().toString()) - .put("scope", "email profile") - .toString()))); - } - - /** - * Object to store common attributes of requests that are going to be made. Adds an Identity - * header for the onap_admin role to the request. - */ - protected RequestSpecification requestSpecification() { - final String idToken = tokenGenerator.generateToken(getTokenGeneratorConfig("onap_admin")); - - return unauthenticatedRequestSpecification() - .auth() - .preemptive() - .oauth2(idToken) - .header(IdTokenExchangeFilterFunction.X_AUTH_IDENTITY_HEADER, "Bearer " + idToken); - } - - /** - * Object to store common attributes of requests that are going to be made. Adds an Identity - * header for the given role to the request. - * - * @param role the role used for RBAC - * @return the templated request - */ - protected RequestSpecification requestSpecification(String role) { - final String idToken = tokenGenerator.generateToken(getTokenGeneratorConfig(role)); - - return unauthenticatedRequestSpecification() - .auth() - .preemptive() - .oauth2(idToken) - .header(IdTokenExchangeFilterFunction.X_AUTH_IDENTITY_HEADER, "Bearer " + idToken); - } - - /** - * Object to store common attributes of requests that are going to be made. Adds an Identity - * header for the given roles to the request. - * - * @param roles the roles used for RBAC - * @return the templated request - */ - protected RequestSpecification requestSpecification(List roles) { - final String idToken = tokenGenerator.generateToken(getTokenGeneratorConfig(roles)); - - return unauthenticatedRequestSpecification() - .auth() - .preemptive() - .oauth2(idToken) - .header(IdTokenExchangeFilterFunction.X_AUTH_IDENTITY_HEADER, "Bearer " + idToken); - } - - /** Get a RequestSpecification that does not have an Identity header. */ - protected RequestSpecification unauthenticatedRequestSpecification() { - return RestAssured.given().port(port); - } - - /** - * Builds an OAuth2 configuration including the role, port and realm. This config can be used to - * generate OAuth2 access tokens. - * - * @param role the role used for RBAC - * @return the OAuth2 configuration - */ - protected TokenGenerator.TokenGeneratorConfig getTokenGeneratorConfig(String role) { - return TokenGenerator.TokenGeneratorConfig.builder() - .port(port) - .realm(realm) - .roles(Collections.singletonList(role)) - .build(); - } - - /** - * Builds an OAuth2 configuration including the roles, port and realm. This config can be used to - * generate OAuth2 access tokens. - * - * @param roles the roles used for RBAC - * @return the OAuth2 configuration - */ - protected TokenGenerator.TokenGeneratorConfig getTokenGeneratorConfig(List roles) { - return TokenGenerator.TokenGeneratorConfig.builder() - .port(port) - .realm(realm) - .roles(roles) - .build(); - } - - public static OffsetDateTime offsetNow() { - return OffsetDateTime.now(Clock.systemUTC()); - } - - public static String randomUUID() { - return UUID.randomUUID().toString(); - } - - public static String adjustPath( - String basePath, Optional page, Optional pageSize) { - return adjustPath(basePath, page, pageSize, Optional.empty()); - } - - public static String adjustPath( - String basePath, - Optional page, - Optional pageSize, - Optional filter) { - URIBuilder builder; - try { - builder = new URIBuilder(basePath); - if (page.isPresent()) { - builder.addParameter("page", String.valueOf(page.get())); - } - if (pageSize.isPresent()) { - builder.addParameter("pageSize", String.valueOf(pageSize.get())); - } - if (filter.isPresent()) { - builder.addParameter("filter", filter.get()); - } - return builder.build().toString(); - } catch (URISyntaxException e) { - e.printStackTrace(); - } - return basePath; - } -} diff --git a/app/src/test/java/org/onap/portal/bff/HealthCheckIntegrationTest.java b/app/src/test/java/org/onap/portal/bff/HealthCheckIntegrationTest.java deleted file mode 100644 index cef85e1..0000000 --- a/app/src/test/java/org/onap/portal/bff/HealthCheckIntegrationTest.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * - * Copyright (c) 2022. Deutsche Telekom AG - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * - * - */ - -package org.onap.portal.bff; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.availability.ApplicationAvailability; -import org.springframework.boot.availability.LivenessState; -import org.springframework.boot.availability.ReadinessState; - -class HealthCheckIntegrationTest extends BaseIntegrationTest { - - @Autowired private ApplicationAvailability applicationAvailability; - - @Test - void livenessProbeIsAvailable() { - - assertThat(applicationAvailability.getLivenessState()).isEqualTo(LivenessState.CORRECT); - } - - @Test - void readinessProbeIsAvailable() { - - assertThat(applicationAvailability.getReadinessState()) - .isEqualTo(ReadinessState.ACCEPTING_TRAFFIC); - } -} diff --git a/app/src/test/java/org/onap/portal/bff/TokenGenerator.java b/app/src/test/java/org/onap/portal/bff/TokenGenerator.java deleted file mode 100644 index 33b9207..0000000 --- a/app/src/test/java/org/onap/portal/bff/TokenGenerator.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * - * Copyright (c) 2022. Deutsche Telekom AG - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * - * - */ - -package org.onap.portal.bff; - -import com.nimbusds.jose.JOSEObjectType; -import com.nimbusds.jose.JWSAlgorithm; -import com.nimbusds.jose.JWSHeader; -import com.nimbusds.jose.JWSSigner; -import com.nimbusds.jose.crypto.RSASSASigner; -import com.nimbusds.jose.jwk.JWKSet; -import com.nimbusds.jose.jwk.KeyUse; -import com.nimbusds.jose.jwk.RSAKey; -import com.nimbusds.jose.jwk.gen.RSAKeyGenerator; -import com.nimbusds.jwt.JWTClaimsSet; -import com.nimbusds.jwt.SignedJWT; -import java.time.Clock; -import java.time.Duration; -import java.time.Instant; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.UUID; -import lombok.Builder; -import lombok.Getter; -import lombok.NonNull; -import org.springframework.stereotype.Component; - -@Component -public class TokenGenerator { - - private static final String ROLES_CLAIM = "roles"; - - private final Clock clock; - private final RSAKey jwk; - private final JWKSet jwkSet; - private final JWSSigner signer; - - public TokenGenerator(Clock clock) { - try { - this.clock = clock; - jwk = - new RSAKeyGenerator(2048) - .keyUse(KeyUse.SIGNATURE) - .keyID(UUID.randomUUID().toString()) - .generate(); - jwkSet = new JWKSet(jwk); - signer = new RSASSASigner(jwk); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - public JWKSet getJwkSet() { - return jwkSet; - } - - public String generateToken(TokenGeneratorConfig config) { - final Instant iat = clock.instant(); - final Instant exp = iat.plus(config.expireIn); - - final JWTClaimsSet claims = - new JWTClaimsSet.Builder() - .jwtID(UUID.randomUUID().toString()) - .subject(UUID.randomUUID().toString()) - .issuer(config.issuer()) - .issueTime(Date.from(iat)) - .expirationTime(Date.from(exp)) - .claim(ROLES_CLAIM, config.getRoles()) - .build(); - - final SignedJWT jwt = - new SignedJWT( - new JWSHeader.Builder(JWSAlgorithm.RS256) - .keyID(jwk.getKeyID()) - .type(JOSEObjectType.JWT) - .build(), - claims); - - try { - jwt.sign(signer); - } catch (Exception e) { - throw new RuntimeException(e); - } - - return jwt.serialize(); - } - - @Getter - @Builder - public static class TokenGeneratorConfig { - private final int port; - - @NonNull private final String realm; - - @NonNull @Builder.Default private final Duration expireIn = Duration.ofMinutes(5); - - @Builder.Default private final List roles = Collections.emptyList(); - - public String issuer() { - return String.format("http://localhost:%d/auth/realms/%s", port, realm); - } - } -} diff --git a/app/src/test/java/org/onap/portal/bff/actions/ActionDto.java b/app/src/test/java/org/onap/portal/bff/actions/ActionDto.java deleted file mode 100644 index c88a0db..0000000 --- a/app/src/test/java/org/onap/portal/bff/actions/ActionDto.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * - * Copyright (c) 2022. Deutsche Telekom AG - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * - * - */ - -package org.onap.portal.bff.actions; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Getter -@Setter -@AllArgsConstructor -@NoArgsConstructor -public class ActionDto { - String type; - String action; - String message; - String downStreamSystem; - String downStreamId; -} diff --git a/app/src/test/java/org/onap/portal/bff/actions/ActionFixtures.java b/app/src/test/java/org/onap/portal/bff/actions/ActionFixtures.java deleted file mode 100644 index 3e7c917..0000000 --- a/app/src/test/java/org/onap/portal/bff/actions/ActionFixtures.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * - * Copyright (c) 2022. Deutsche Telekom AG - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * - * - */ - -package org.onap.portal.bff.actions; - -import java.time.OffsetDateTime; -import java.time.temporal.ChronoUnit; -import org.onap.portal.bff.openapi.client_portal_history.model.ActionResponsePortalHistoryDto; -import org.onap.portal.bff.openapi.client_portal_history.model.ActionsListResponsePortalHistoryDto; -import org.onap.portal.bff.openapi.client_portal_history.model.CreateActionRequestPortalHistoryDto; -import org.onap.portal.bff.openapi.server.model.CreateActionRequestApiDto; - -public class ActionFixtures { - - public static ActionsListResponsePortalHistoryDto generateActionsListResponse( - Integer numberOfActions, Integer totalCount, OffsetDateTime createdAt) { - ActionsListResponsePortalHistoryDto actionsListResponsePortalHistoryDto = - new ActionsListResponsePortalHistoryDto(); - for (Integer i = 0; i < numberOfActions; i++) { - actionsListResponsePortalHistoryDto.addActionsListItem( - generateActionResponse( - "Instantiation", "create", null, i.toString(), "SO", i, createdAt)); - } - actionsListResponsePortalHistoryDto.setTotalCount(totalCount); - return actionsListResponsePortalHistoryDto; - } - - public static ActionResponsePortalHistoryDto generateActionResponse( - String type, - String action, - String message, - String id, - String downStreamSystem, - Integer deltaHours, - OffsetDateTime createdAt) { - ActionDto actionDto = new ActionDto(); - actionDto.setType(type); - actionDto.setAction(action); - actionDto.setMessage(message); - actionDto.setDownStreamSystem(downStreamSystem); - actionDto.setDownStreamId(id); - - return new ActionResponsePortalHistoryDto() - .action(actionDto) - .actionCreatedAt(createdAt.minus(deltaHours, ChronoUnit.HOURS)); - } - - public static CreateActionRequestPortalHistoryDto generateActionRequestPortalHistoryDto( - String type, - String action, - String message, - String id, - String downStreamSystem, - String userId, - OffsetDateTime createdAt) { - ActionDto actionDto = new ActionDto(); - actionDto.setType(type); - actionDto.setAction(action); - actionDto.setMessage(message); - actionDto.setDownStreamSystem(downStreamSystem); - actionDto.setDownStreamId(id); - return new CreateActionRequestPortalHistoryDto() - .action(actionDto) - .actionCreatedAt(createdAt) - .userId(userId); - } - - public static CreateActionRequestApiDto generateCreateActionRequestApiDto( - String type, - String action, - String message, - String id, - String downStreamSystem, - String userId, - OffsetDateTime createdAt) { - ActionDto actionDto = new ActionDto(); - actionDto.setType(type); - actionDto.setAction(action); - actionDto.setMessage(message); - actionDto.setDownStreamSystem(downStreamSystem); - actionDto.setDownStreamId(id); - - return new CreateActionRequestApiDto() - .action(actionDto) - .actionCreatedAt(createdAt) - .userId(userId); - } -} diff --git a/app/src/test/java/org/onap/portal/bff/actions/ActionsMocks.java b/app/src/test/java/org/onap/portal/bff/actions/ActionsMocks.java deleted file mode 100644 index 0bb27d7..0000000 --- a/app/src/test/java/org/onap/portal/bff/actions/ActionsMocks.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * - * Copyright (c) 2022. Deutsche Telekom AG - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * - * - */ - -package org.onap.portal.bff.actions; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.github.tomakehurst.wiremock.client.WireMock; -import com.github.tomakehurst.wiremock.matching.EqualToPattern; -import io.restassured.http.Header; -import org.apache.http.HttpHeaders; -import org.onap.portal.bff.BaseIntegrationTest; -import org.onap.portal.bff.openapi.client_portal_history.model.ActionResponsePortalHistoryDto; -import org.onap.portal.bff.openapi.client_portal_history.model.ActionsListResponsePortalHistoryDto; -import org.onap.portal.bff.openapi.client_portal_history.model.ProblemPortalHistoryDto; -import org.onap.portal.bff.openapi.server.model.ActionsListResponseApiDto; -import org.onap.portal.bff.openapi.server.model.ActionsResponseApiDto; -import org.onap.portal.bff.openapi.server.model.CreateActionRequestApiDto; -import org.onap.portal.bff.openapi.server.model.ProblemApiDto; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; - -public class ActionsMocks extends BaseIntegrationTest { - protected static final String X_REQUEST_ID = "addf6005-3075-4c80-b7bc-2c70b7d42b00"; - - // used for test thatActionsListCanBeRetrieved - protected ActionsListResponseApiDto listActions() { - return requestSpecification() - .given() - .accept(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", X_REQUEST_ID)) - .when() - .get("/actions") - .then() - .statusCode(HttpStatus.OK.value()) - .extract() - .body() - .as(ActionsListResponseApiDto.class); - } - - // used for test thatActionsListCanBeRetrieved - protected void mockListActions( - ActionsListResponsePortalHistoryDto actionsListResponsePortalHistoryDto) throws Exception { - WireMock.stubFor( - WireMock.get(WireMock.urlEqualTo("/v1/actions?page=1&pageSize=10")) - .withHeader("X-Request-Id", new EqualToPattern(X_REQUEST_ID)) - .willReturn( - WireMock.aResponse() - .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) - .withBody( - objectMapper.writeValueAsString(actionsListResponsePortalHistoryDto)))); - } - - // used for test thatActionsListCanNotBeRetrieved - protected ProblemApiDto listActionsProblem() { - return requestSpecification() - .given() - .accept(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", X_REQUEST_ID)) - .when() - .get("/actions") - .then() - .statusCode(HttpStatus.BAD_GATEWAY.value()) - .extract() - .body() - .as(ProblemApiDto.class); - } - - // used for test thatActionsListCanNotBeRetrieved - protected void mockListActionsProblem(ProblemPortalHistoryDto problemPortalHistoryDto) - throws Exception { - WireMock.stubFor( - WireMock.get(WireMock.urlEqualTo("/v1/actions?page=1&pageSize=10")) - .withHeader("X-Request-Id", new EqualToPattern(X_REQUEST_ID)) - .willReturn( - WireMock.aResponse() - .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_PROBLEM_JSON_VALUE) - .withStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()) - .withBody(objectMapper.writeValueAsString(problemPortalHistoryDto)))); - } - - // used for test thatActionCanBeRetrieved - protected void mockGetActions( - ActionsListResponsePortalHistoryDto actionsListResponsePortalHistoryDto, - String userId, - Integer showLastHours) - throws Exception { - WireMock.stubFor( - WireMock.get( - WireMock.urlEqualTo( - "/v1/actions/" - + userId - + "?page=1&pageSize=10" - + "&showLastHours=" - + showLastHours)) - .withHeader("X-Request-Id", new EqualToPattern(X_REQUEST_ID)) - .willReturn( - WireMock.aResponse() - .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) - .withBody( - objectMapper.writeValueAsString(actionsListResponsePortalHistoryDto)))); - } - // used for test thatActionCanBeRetrieved - protected ActionsListResponseApiDto getActions(String userId) { - return requestSpecification() - .given() - .accept(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", X_REQUEST_ID)) - .when() - .get("/actions/" + userId + "?page=1&pageSize=10&showLastHours=2") - .then() - .statusCode(HttpStatus.OK.value()) - .extract() - .body() - .as(ActionsListResponseApiDto.class); - } - - // used for test thatActionCanBeRetrievedWithoutParameterShowLastHours - protected void mockGetActionsWithoutParameterShowLastHours( - ActionsListResponsePortalHistoryDto actionsListResponsePortalHistoryDto, String userId) - throws Exception { - WireMock.stubFor( - WireMock.get(WireMock.urlEqualTo("/v1/actions/" + userId + "?page=1&pageSize=10")) - .withHeader("X-Request-Id", new EqualToPattern(X_REQUEST_ID)) - .willReturn( - WireMock.aResponse() - .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) - .withBody( - objectMapper.writeValueAsString(actionsListResponsePortalHistoryDto)))); - } - // used for test thatActionCanBeRetrievedWithoutParameterShowLastHours - protected ActionsListResponseApiDto getActionsWithoutParameterShowLastHours(String userId) { - return requestSpecification() - .given() - .accept(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", X_REQUEST_ID)) - .when() - .get("/actions/" + userId + "?page=1&pageSize=10") - .then() - .statusCode(HttpStatus.OK.value()) - .extract() - .body() - .as(ActionsListResponseApiDto.class); - } - - // Used for thatActionCanBeCreated - protected void mockCreateActions( - String userId, ActionResponsePortalHistoryDto actionResponsePortalHistoryDto) - throws Exception { - WireMock.stubFor( - WireMock.post(WireMock.urlEqualTo("/v1/actions/" + userId)) - .withHeader("X-Request-Id", new EqualToPattern(X_REQUEST_ID)) - .withRequestBody(WireMock.matchingJsonPath("$.action")) - .willReturn( - WireMock.aResponse() - .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) - .withStatus(200) - .withBody(objectMapper.writeValueAsString(actionResponsePortalHistoryDto)))); - } - - // Used for thatActionCanBeCreated - protected ActionsResponseApiDto createAction( - CreateActionRequestApiDto createActionRequestApiDto, String userId) throws Exception { - return requestSpecification() - .given() - .accept(MediaType.APPLICATION_JSON_VALUE) - .contentType(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", X_REQUEST_ID)) - .body(objectMapper.writeValueAsString(createActionRequestApiDto)) - .when() - .post("/actions/" + userId) - .then() - .statusCode(HttpStatus.OK.value()) - .extract() - .body() - .as(ActionsResponseApiDto.class); - } - - // Used for thatActionCanNotBeCreated - protected void mockCreateActionsProblem( - String userId, ProblemPortalHistoryDto problemPortalHistoryDto) - throws JsonProcessingException { - WireMock.stubFor( - WireMock.post(WireMock.urlEqualTo("/v1/actions/" + userId)) - .withHeader("X-Request-Id", new EqualToPattern(X_REQUEST_ID)) - .withRequestBody(WireMock.matchingJsonPath("$.action")) - .willReturn( - WireMock.aResponse() - .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_PROBLEM_JSON_VALUE) - .withStatus(500) - .withBody(objectMapper.writeValueAsString(problemPortalHistoryDto)))); - } - // Used for thatActionCanNotBeCreated - protected ProblemApiDto createActionProblem( - CreateActionRequestApiDto createActionRequestApiDto, String userId) - throws JsonProcessingException { - return requestSpecification() - .given() - .accept(MediaType.APPLICATION_JSON_VALUE) - .contentType(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", X_REQUEST_ID)) - .body(objectMapper.writeValueAsString(createActionRequestApiDto)) - .when() - .post("/actions/" + userId) - .then() - .statusCode(HttpStatus.BAD_GATEWAY.value()) - .extract() - .body() - .as(ProblemApiDto.class); - } -} diff --git a/app/src/test/java/org/onap/portal/bff/actions/CreateActionsIntegrationTest.java b/app/src/test/java/org/onap/portal/bff/actions/CreateActionsIntegrationTest.java deleted file mode 100644 index 0b6ec57..0000000 --- a/app/src/test/java/org/onap/portal/bff/actions/CreateActionsIntegrationTest.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * - * Copyright (c) 2022. Deutsche Telekom AG - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * - * - */ - -package org.onap.portal.bff.actions; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.time.OffsetDateTime; -import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.Test; -import org.onap.portal.bff.openapi.client_portal_history.model.ActionResponsePortalHistoryDto; -import org.onap.portal.bff.openapi.client_portal_history.model.ProblemPortalHistoryDto; -import org.onap.portal.bff.openapi.server.model.ActionsResponseApiDto; -import org.onap.portal.bff.openapi.server.model.CreateActionRequestApiDto; -import org.onap.portal.bff.openapi.server.model.ProblemApiDto; -import org.springframework.http.HttpStatus; - -class CreateActionsIntegrationTest extends ActionsMocks { - - @Test - void thatActionCanBeCreated() throws Exception { - String userId = "22-33-44-55"; - OffsetDateTime createdAt = OffsetDateTime.now(); - ActionResponsePortalHistoryDto actionResponsePortalHistoryDto = - ActionFixtures.generateActionResponse( - "Instantiation", "create", "no detail message", "223344", "SO", 0, createdAt); - CreateActionRequestApiDto createActionDto = - ActionFixtures.generateCreateActionRequestApiDto( - "Instantiation", "create", "no detail message", "223344", "SO", userId, createdAt); - - mockCreateActions(userId, actionResponsePortalHistoryDto); - - final ActionsResponseApiDto response = createAction(createActionDto, userId); - - assertThat(response.getActionCreatedAt()) - .isEqualTo(actionResponsePortalHistoryDto.getActionCreatedAt()); - Assertions.assertThat(objectMapper.writeValueAsString(response.getAction())) - .isEqualTo(objectMapper.writeValueAsString(actionResponsePortalHistoryDto.getAction())); - } - - @Test - void thatActionCanNotBeCreated() throws Exception { - String userId = "22-33-44-55"; - OffsetDateTime createdAt = OffsetDateTime.now(); - - ProblemPortalHistoryDto problemPortalHistoryDto = - new ProblemPortalHistoryDto() - .status(HttpStatus.INTERNAL_SERVER_ERROR.value()) - .detail("Internal database error") - .title("Internal Server Error") - .instance("portal-history"); - - CreateActionRequestApiDto createActionDto = - ActionFixtures.generateCreateActionRequestApiDto( - "Instantiation", "create", "no detail message", "223344", "SO", userId, createdAt); - - mockCreateActionsProblem(userId, problemPortalHistoryDto); - - final ProblemApiDto response = createActionProblem(createActionDto, userId); - - assertThat(response.getDownstreamSystem()) - .isEqualTo(ProblemApiDto.DownstreamSystemEnum.PORTAL_HISTORY); - - assertThat(response.getDownstreamStatus()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR.value()); - assertThat(response.getDetail()).isEqualTo(problemPortalHistoryDto.getDetail()); - } -} diff --git a/app/src/test/java/org/onap/portal/bff/actions/GetActionsIntegrationTest.java b/app/src/test/java/org/onap/portal/bff/actions/GetActionsIntegrationTest.java deleted file mode 100644 index 1f77036..0000000 --- a/app/src/test/java/org/onap/portal/bff/actions/GetActionsIntegrationTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * - * Copyright (c) 2022. Deutsche Telekom AG - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * - * - */ - -package org.onap.portal.bff.actions; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.time.OffsetDateTime; -import org.junit.jupiter.api.Test; -import org.onap.portal.bff.openapi.client_portal_history.model.ActionsListResponsePortalHistoryDto; -import org.onap.portal.bff.openapi.server.model.ActionsListResponseApiDto; - -class GetActionsIntegrationTest extends ActionsMocks { - - @Test - void thatActionCanBeRetrievedWithParameterShowLastHours() throws Exception { - int numberOfActions = 10; - Integer showLastHours = 2; - String userId = "22-33-44-55"; - OffsetDateTime createdAt = OffsetDateTime.now(); - ActionsListResponsePortalHistoryDto actionsListResponsePortalHistoryDto = - ActionFixtures.generateActionsListResponse(numberOfActions, 30, createdAt); - - mockGetActions(actionsListResponsePortalHistoryDto, userId, showLastHours); - - final ActionsListResponseApiDto response = getActions(userId); - - assertThat(response.getTotalCount()).isEqualTo(30); - assertThat(response.getItems()).hasSize(numberOfActions); - assertThat(response.getItems().get(0).getActionCreatedAt()) - .isEqualTo( - actionsListResponsePortalHistoryDto.getActionsList().get(0).getActionCreatedAt()); - assertThat(objectMapper.writeValueAsString(response.getItems().get(0).getAction())) - .isEqualTo( - objectMapper.writeValueAsString( - actionsListResponsePortalHistoryDto.getActionsList().get(0).getAction())); - } - - @Test - void thatActionCanBeRetrievedWithoutParameterShowLastHours() throws Exception { - int numberOfActions = 10; - String userId = "22-33-44-55"; - OffsetDateTime createdAt = OffsetDateTime.now(); - ActionsListResponsePortalHistoryDto actionsListResponsePortalHistoryDto = - ActionFixtures.generateActionsListResponse(numberOfActions, 30, createdAt); - - mockGetActionsWithoutParameterShowLastHours(actionsListResponsePortalHistoryDto, userId); - - final ActionsListResponseApiDto response = getActionsWithoutParameterShowLastHours(userId); - - assertThat(response.getTotalCount()).isEqualTo(30); - assertThat(response.getItems()).hasSize(numberOfActions); - assertThat(response.getItems().get(0).getActionCreatedAt()) - .isEqualTo( - actionsListResponsePortalHistoryDto.getActionsList().get(0).getActionCreatedAt()); - assertThat(objectMapper.writeValueAsString(response.getItems().get(0).getAction())) - .isEqualTo( - objectMapper.writeValueAsString( - actionsListResponsePortalHistoryDto.getActionsList().get(0).getAction())); - } -} diff --git a/app/src/test/java/org/onap/portal/bff/actions/ListActionsIntegrationTest.java b/app/src/test/java/org/onap/portal/bff/actions/ListActionsIntegrationTest.java deleted file mode 100644 index 7eb7078..0000000 --- a/app/src/test/java/org/onap/portal/bff/actions/ListActionsIntegrationTest.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * - * Copyright (c) 2022. Deutsche Telekom AG - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * - * - */ - -package org.onap.portal.bff.actions; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.time.OffsetDateTime; -import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.Test; -import org.onap.portal.bff.openapi.client_portal_history.model.ActionsListResponsePortalHistoryDto; -import org.onap.portal.bff.openapi.client_portal_history.model.ProblemPortalHistoryDto; -import org.onap.portal.bff.openapi.server.model.ActionsListResponseApiDto; -import org.onap.portal.bff.openapi.server.model.ProblemApiDto; -import org.springframework.http.HttpStatus; - -class ListActionsIntegrationTest extends ActionsMocks { - - @Test - void thatActionsListCanBeRetrieved() throws Exception { - int numberOfActions = 10; - OffsetDateTime createdAt = OffsetDateTime.now(); - ActionsListResponsePortalHistoryDto actionsListResponsePortalHistoryDto = - ActionFixtures.generateActionsListResponse(numberOfActions, 1000, createdAt); - - mockListActions(actionsListResponsePortalHistoryDto); - - final ActionsListResponseApiDto response = listActions(); - - assertThat(response.getTotalCount()).isEqualTo(1000); - assertThat(response.getItems()).hasSize(numberOfActions); - assertThat(response.getItems().get(0).getActionCreatedAt()) - .isEqualTo( - actionsListResponsePortalHistoryDto.getActionsList().get(0).getActionCreatedAt()); - Assertions.assertThat(objectMapper.writeValueAsString(response.getItems().get(0).getAction())) - .isEqualTo( - objectMapper.writeValueAsString( - actionsListResponsePortalHistoryDto.getActionsList().get(0).getAction())); - } - - @Test - void thatActionsListCanNotBeRetrieved() throws Exception { - - ProblemPortalHistoryDto problemPortalHistoryDto = - new ProblemPortalHistoryDto() - .status(HttpStatus.INTERNAL_SERVER_ERROR.value()) - .detail("Internal database error") - .title("Internal Server Error") - .instance("portal-history"); - - mockListActionsProblem(problemPortalHistoryDto); - - final ProblemApiDto response = listActionsProblem(); - - assertThat(response.getDownstreamSystem()) - .isEqualTo(ProblemApiDto.DownstreamSystemEnum.PORTAL_HISTORY); - assertThat(response.getDownstreamStatus()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR.value()); - assertThat(response.getDetail()).isEqualTo(problemPortalHistoryDto.getDetail()); - } -} diff --git a/app/src/test/java/org/onap/portal/bff/headers/XRequestIdHeaderTest.java b/app/src/test/java/org/onap/portal/bff/headers/XRequestIdHeaderTest.java deleted file mode 100644 index 50f75c7..0000000 --- a/app/src/test/java/org/onap/portal/bff/headers/XRequestIdHeaderTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * - * Copyright (c) 2022. Deutsche Telekom AG - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * - * - */ - -package org.onap.portal.bff.headers; - -import static org.assertj.core.api.Assertions.assertThat; - -import com.github.tomakehurst.wiremock.client.WireMock; -import com.github.tomakehurst.wiremock.matching.EqualToPattern; -import io.restassured.http.Header; -import org.junit.jupiter.api.Test; -import org.onap.portal.bff.BaseIntegrationTest; -import org.onap.portal.bff.openapi.client_portal_prefs.model.PreferencesPortalPrefsDto; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; - -class XRequestIdHeaderTest extends BaseIntegrationTest { - protected static final String X_REQUEST_ID = "addf6005-3075-4c80-b7bc-2c70b7d42b57"; - - @Test - void xRequestIdHeaderIsCorrectlySetInResponse() throws Exception { - // use preferences endpoint for testing the header - final PreferencesPortalPrefsDto preferencesPortalPrefsDto = new PreferencesPortalPrefsDto(); - - // mockGetTile(tileDetailResponsePortalServiceDto, X_REQUEST_ID); - mockGetPreferences(preferencesPortalPrefsDto, X_REQUEST_ID); - - final String response = getPreferencesExtractHeader(X_REQUEST_ID); - assertThat(response).isEqualTo(X_REQUEST_ID); - } - - protected void mockGetPreferences( - PreferencesPortalPrefsDto preferencesPortalPrefsDto, String xRequestId) throws Exception { - WireMock.stubFor( - WireMock.get(WireMock.urlEqualTo("/v1/preferences")) - .withHeader("X-Request-Id", new EqualToPattern(X_REQUEST_ID)) - .willReturn( - WireMock.aResponse() - .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) - .withHeader("X-Request-Id", xRequestId) - .withBody(objectMapper.writeValueAsString(preferencesPortalPrefsDto)))); - } - - protected String getPreferencesExtractHeader(String xRequestId) { - return requestSpecification() - .given() - .accept(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", xRequestId)) - .when() - .get("/preferences") - .then() - .statusCode(HttpStatus.OK.value()) - .extract() - .header("X-Request-Id"); - } -} diff --git a/app/src/test/java/org/onap/portal/bff/idtoken/IdTokenExchangeFilterFunctionTest.java b/app/src/test/java/org/onap/portal/bff/idtoken/IdTokenExchangeFilterFunctionTest.java deleted file mode 100644 index 7d65849..0000000 --- a/app/src/test/java/org/onap/portal/bff/idtoken/IdTokenExchangeFilterFunctionTest.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * - * Copyright (c) 2022. Deutsche Telekom AG - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * - * - */ - -package org.onap.portal.bff.idtoken; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.Mockito.mock; - -import java.net.URI; -import java.util.UUID; -import org.junit.jupiter.api.Test; -import org.onap.portal.bff.BaseIntegrationTest; -import org.onap.portal.bff.config.IdTokenExchangeFilterFunction; -import org.springframework.http.HttpMethod; -import org.springframework.mock.http.server.reactive.MockServerHttpRequest; -import org.springframework.mock.web.server.MockServerWebExchange; -import org.springframework.web.reactive.function.client.ClientRequest; -import org.springframework.web.reactive.function.client.ClientResponse; -import org.springframework.web.reactive.function.client.ExchangeFunction; -import org.springframework.web.server.ServerWebExchange; -import reactor.core.publisher.Mono; - -class IdTokenExchangeFilterFunctionTest extends BaseIntegrationTest { - - @Test - void idTokenIsCorrectlyPropagated() { - final IdTokenExchangeFilterFunction filterFunction = new IdTokenExchangeFilterFunction(); - - final String idToken = UUID.randomUUID().toString(); - final ServerWebExchange serverWebExchange = - MockServerWebExchange.builder( - MockServerHttpRequest.get("http://localhost:8000") - .header(IdTokenExchangeFilterFunction.X_AUTH_IDENTITY_HEADER, idToken)) - .build(); - - final ClientRequest request = - ClientRequest.create(HttpMethod.GET, URI.create("http://api-server:9000")) - .attribute(ServerWebExchange.class.getName(), serverWebExchange) - .build(); - final ClientResponse response = mock(ClientResponse.class); - - final ExchangeFunction exchange = - r -> { - assertThat(r.headers().getOrEmpty(IdTokenExchangeFilterFunction.X_AUTH_IDENTITY_HEADER)) - .containsExactly(idToken); - - return Mono.just(response); - }; - - final ClientResponse result = filterFunction.filter(request, exchange).block(); - assertThat(result).isEqualTo(response); - } - - @Test - void exceptionIsThrownWhenIdTokenIsMissingInRequest() { - final IdTokenExchangeFilterFunction filterFunction = new IdTokenExchangeFilterFunction(); - - final ServerWebExchange serverWebExchange = - MockServerWebExchange.builder(MockServerHttpRequest.get("http://localhost:8000")).build(); - - final ClientRequest request = - ClientRequest.create(HttpMethod.GET, URI.create("http://api-server:9000")) - .attribute(ServerWebExchange.class.getName(), serverWebExchange) - .build(); - final ExchangeFunction exchange = r -> Mono.just(mock(ClientResponse.class)); - - assertThatThrownBy(() -> filterFunction.filter(request, exchange).block()) - .hasMessage("Forbidden: ID token is missing"); - } -} diff --git a/app/src/test/java/org/onap/portal/bff/preferences/CreatePreferencesIntegrationTest.java b/app/src/test/java/org/onap/portal/bff/preferences/CreatePreferencesIntegrationTest.java deleted file mode 100644 index 5259de8..0000000 --- a/app/src/test/java/org/onap/portal/bff/preferences/CreatePreferencesIntegrationTest.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * - * Copyright (c) 2022. Deutsche Telekom AG - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * - * - */ - -package org.onap.portal.bff.preferences; - -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; - -import io.restassured.http.Header; -import org.junit.jupiter.api.Test; -import org.onap.portal.bff.openapi.client_portal_prefs.model.PreferencesPortalPrefsDto; -import org.onap.portal.bff.openapi.client_portal_prefs.model.ProblemPortalPrefsDto; -import org.onap.portal.bff.openapi.server.model.CreatePreferencesRequestApiDto; -import org.onap.portal.bff.openapi.server.model.PreferencesResponseApiDto; -import org.onap.portal.bff.openapi.server.model.ProblemApiDto; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; - -class CreatePreferencesIntegrationTest extends PreferencesMocks { - @Test - void thatPreferencesCanBeCreated() throws Exception { - PreferencesPortalPrefsDto preferencesPortalPrefsDto = new PreferencesPortalPrefsDto(); - preferencesPortalPrefsDto.setProperties( - "{\n" - + "\"properties\": {\n" - + "\"appStarter\": \"value1\",\n" - + "\"dashboard\": {\"key1:\" : \"value2\"}\n" - + "}\n" - + "\n" - + "}"); - mockCreatePreferences(preferencesPortalPrefsDto); - - final CreatePreferencesRequestApiDto request = - new CreatePreferencesRequestApiDto() - .properties( - "{\n" - + "\"properties\": {\n" - + "\"appStarter\": \"value1\",\n" - + "\"dashboard\": {\"key1:\" : \"value2\"}\n" - + "}\n" - + "\n" - + "}"); - final PreferencesResponseApiDto response = createPreferences(request); - assertThat(response).isNotNull(); - assertThat(response.getProperties()).isEqualTo(preferencesPortalPrefsDto.getProperties()); - } - - @Test - void thatPreferencesCanNotBeCreated() throws Exception { - final var problemPortalPrefsDto = new ProblemPortalPrefsDto(); - problemPortalPrefsDto.setStatus(HttpStatus.BAD_REQUEST.value()); - problemPortalPrefsDto.setTitle(HttpStatus.BAD_REQUEST.toString()); - problemPortalPrefsDto.setDetail("Some details"); - - final PreferencesPortalPrefsDto preferencesPortalPrefsDto = - new PreferencesPortalPrefsDto() - .properties( - "{\n" - + "\"properties\": {\n" - + "\"appStarter\": \"value1\",\n" - + "\"dashboard\": {\"key1:\" : \"value2\"}\n" - + "}\n" - + "\n" - + "}"); - mockCreatePreferencesError(preferencesPortalPrefsDto, problemPortalPrefsDto); - - CreatePreferencesRequestApiDto responseBody = - new CreatePreferencesRequestApiDto() - .properties( - "{\n" - + "\"properties\": {\n" - + "\"appStarter\": \"value1\",\n" - + "\"dashboard\": {\"key1:\" : \"value2\"}\n" - + "}\n" - + "\n" - + "}"); - final ProblemApiDto response = - requestSpecification() - .given() - .accept(MediaType.APPLICATION_PROBLEM_JSON_VALUE) - .contentType(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", X_REQUEST_ID)) - .body(responseBody) - .when() - .post("/preferences") - .then() - .statusCode(HttpStatus.BAD_GATEWAY.value()) - .extract() - .body() - .as(ProblemApiDto.class); - - assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_GATEWAY.value()); - assertThat(response.getDetail()).isEqualTo(problemPortalPrefsDto.getDetail()); - assertThat(response.getDownstreamSystem()) - .isEqualTo(ProblemApiDto.DownstreamSystemEnum.PORTAL_PREFS); - assertThat(response.getDownstreamStatus()).isEqualTo(HttpStatus.BAD_REQUEST.value()); - } -} diff --git a/app/src/test/java/org/onap/portal/bff/preferences/GetPreferencesIntegrationTest.java b/app/src/test/java/org/onap/portal/bff/preferences/GetPreferencesIntegrationTest.java deleted file mode 100644 index 1e1317b..0000000 --- a/app/src/test/java/org/onap/portal/bff/preferences/GetPreferencesIntegrationTest.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * - * Copyright (c) 2022. Deutsche Telekom AG - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * - * - */ - -package org.onap.portal.bff.preferences; - -import static org.assertj.core.api.Assertions.assertThat; - -import io.restassured.http.Header; -import org.junit.jupiter.api.Test; -import org.onap.portal.bff.openapi.client_portal_prefs.model.PreferencesPortalPrefsDto; -import org.onap.portal.bff.openapi.client_portal_prefs.model.ProblemPortalPrefsDto; -import org.onap.portal.bff.openapi.server.model.PreferencesResponseApiDto; -import org.onap.portal.bff.openapi.server.model.ProblemApiDto; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; - -class GetPreferencesIntegrationTest extends PreferencesMocks { - - @Test - void thatPreferencesCanBeRetrieved() throws Exception { - PreferencesPortalPrefsDto preferencesPortalPrefsDto = new PreferencesPortalPrefsDto(); - preferencesPortalPrefsDto.setProperties(getFixture(PREF_PROPERTIES_FILE, Object.class)); - mockGetPreferences(preferencesPortalPrefsDto); - - final PreferencesResponseApiDto response = getPreferences(); - assertThat(response).isNotNull(); - } - - @Test - void thatPreferencesCanNotBeRetrieved() throws Exception { - final ProblemPortalPrefsDto problemResponse = - new ProblemPortalPrefsDto() - .title("Unauthorized") - .status(HttpStatus.UNAUTHORIZED.value()) - .detail("Unauthorized error detail") - .instance("instance") - .type("type"); - - mockGetPreferencesError(problemResponse); - - final ProblemApiDto errorResponse = - requestSpecification() - .given() - .accept(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) - .when() - .get("/preferences") - .then() - .statusCode(HttpStatus.BAD_GATEWAY.value()) - .contentType(MediaType.APPLICATION_PROBLEM_JSON_VALUE) - .extract() - .body() - .as(ProblemApiDto.class); - - assertThat(errorResponse.getStatus()).isEqualTo(HttpStatus.BAD_GATEWAY.value()); - assertThat(errorResponse.getTitle()).isEqualTo(HttpStatus.UNAUTHORIZED.toString()); - assertThat(errorResponse.getDetail()).isEqualTo("Unauthorized error detail"); - } -} diff --git a/app/src/test/java/org/onap/portal/bff/preferences/PreferencesMocks.java b/app/src/test/java/org/onap/portal/bff/preferences/PreferencesMocks.java deleted file mode 100644 index e08c690..0000000 --- a/app/src/test/java/org/onap/portal/bff/preferences/PreferencesMocks.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * - * Copyright (c) 2022. Deutsche Telekom AG - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * - * - */ - -package org.onap.portal.bff.preferences; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.tomakehurst.wiremock.client.WireMock; -import com.github.tomakehurst.wiremock.matching.EqualToPattern; -import io.restassured.http.Header; -import java.io.File; -import java.io.IOException; -import org.apache.http.HttpHeaders; -import org.onap.portal.bff.BaseIntegrationTest; -import org.onap.portal.bff.openapi.client_portal_prefs.model.PreferencesPortalPrefsDto; -import org.onap.portal.bff.openapi.client_portal_prefs.model.ProblemPortalPrefsDto; -import org.onap.portal.bff.openapi.server.model.CreatePreferencesRequestApiDto; -import org.onap.portal.bff.openapi.server.model.PreferencesResponseApiDto; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; - -public class PreferencesMocks extends BaseIntegrationTest { - protected static final String X_REQUEST_ID = "addf6005-3075-4c80-b7bc-2c70b7d42b57"; - - protected static final String PREF_PROPERTIES_FILE = - "src/test/resources/preferences/preferencesProperties.json"; - - protected static final ObjectMapper objectMapper = - new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL); - - protected static T getFixture(final String fileName, Class type) throws IOException { - return objectMapper.readValue(new File(fileName), type); - } - - protected PreferencesResponseApiDto getPreferences() { - - return requestSpecification() - .given() - .accept(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", X_REQUEST_ID)) - .when() - .get("/preferences") - .then() - .statusCode(HttpStatus.OK.value()) - .extract() - .body() - .as(PreferencesResponseApiDto.class); - } - - protected void mockGetPreferences(PreferencesPortalPrefsDto preferencesPortalPrefsDto) - throws Exception { - WireMock.stubFor( - WireMock.get(WireMock.urlEqualTo("/v1/preferences")) - .withHeader("X-Request-Id", new EqualToPattern(X_REQUEST_ID)) - .willReturn( - WireMock.aResponse() - .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) - .withBody(objectMapper.writeValueAsString(preferencesPortalPrefsDto)))); - } - - protected void mockGetPreferencesError(ProblemPortalPrefsDto problem) throws Exception { - WireMock.stubFor( - WireMock.get(WireMock.urlEqualTo("/v1/preferences")) - .withHeader("X-Request-Id", new EqualToPattern(X_REQUEST_ID)) - .willReturn( - WireMock.aResponse() - .withHeader( - org.springframework.http.HttpHeaders.CONTENT_TYPE, - MediaType.APPLICATION_PROBLEM_JSON_VALUE) - .withBody(objectMapper.writeValueAsString(problem)) - .withStatus(HttpStatus.UNAUTHORIZED.value()))); - } - - protected PreferencesResponseApiDto createPreferences(CreatePreferencesRequestApiDto request) { - return requestSpecification() - .given() - .contentType(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", X_REQUEST_ID)) - .body(request) - .when() - .post("/preferences") - .then() - .statusCode(HttpStatus.OK.value()) - .extract() - .body() - .as(PreferencesResponseApiDto.class); - } - - protected void mockCreatePreferences(PreferencesPortalPrefsDto preferencesPortalPrefsDto) - throws Exception { - WireMock.stubFor( - WireMock.post(WireMock.urlEqualTo("/v1/preferences")) - .withHeader("X-Request-Id", new EqualToPattern(X_REQUEST_ID)) - .withRequestBody( - WireMock.equalToJson( - objectMapper.writeValueAsString(preferencesPortalPrefsDto), true, false)) - .willReturn( - WireMock.aResponse() - .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) - .withBody(objectMapper.writeValueAsString(preferencesPortalPrefsDto)))); - } - - protected void mockCreatePreferencesError( - PreferencesPortalPrefsDto preferencesPortalPrefsDto, - ProblemPortalPrefsDto problemPortalPrefsDto) - throws Exception { - WireMock.stubFor( - WireMock.post(WireMock.urlEqualTo("/v1/preferences")) - .withHeader("X-Request-Id", new EqualToPattern(X_REQUEST_ID)) - .withRequestBody( - WireMock.equalToJson( - objectMapper.writeValueAsString(preferencesPortalPrefsDto), true, false)) - .willReturn( - WireMock.aResponse() - .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) - .withStatus(HttpStatus.BAD_REQUEST.value()) - .withBody(objectMapper.writeValueAsString(problemPortalPrefsDto)))); - } - - protected PreferencesResponseApiDto updatePreferences(CreatePreferencesRequestApiDto request) { - return requestSpecification() - .given() - .contentType(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", X_REQUEST_ID)) - .body(request) - .when() - .put("/preferences") - .then() - .statusCode(HttpStatus.OK.value()) - .extract() - .body() - .as(PreferencesResponseApiDto.class); - } - - protected void mockUpdatePreferences(PreferencesPortalPrefsDto preferencesPortalPrefsDto) - throws Exception { - WireMock.stubFor( - WireMock.put(WireMock.urlEqualTo("/v1/preferences")) - .withHeader("X-Request-Id", new EqualToPattern(X_REQUEST_ID)) - .withRequestBody( - WireMock.equalToJson( - objectMapper.writeValueAsString(preferencesPortalPrefsDto), true, false)) - .willReturn( - WireMock.aResponse() - .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) - .withBody(objectMapper.writeValueAsString(preferencesPortalPrefsDto)))); - } - - protected void mockUpdatePreferencesError( - PreferencesPortalPrefsDto preferencesPortalPrefsDto, - ProblemPortalPrefsDto problemPortalPrefsDto) - throws Exception { - WireMock.stubFor( - WireMock.put(WireMock.urlEqualTo("/v1/preferences")) - .withRequestBody( - WireMock.equalToJson( - objectMapper.writeValueAsString(preferencesPortalPrefsDto), true, false)) - .willReturn( - WireMock.aResponse() - .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) - .withStatus(HttpStatus.BAD_REQUEST.value()) - .withBody(objectMapper.writeValueAsString(problemPortalPrefsDto)))); - } -} diff --git a/app/src/test/java/org/onap/portal/bff/preferences/UpdatePreferencesIntegrationTest.java b/app/src/test/java/org/onap/portal/bff/preferences/UpdatePreferencesIntegrationTest.java deleted file mode 100644 index 74d902c..0000000 --- a/app/src/test/java/org/onap/portal/bff/preferences/UpdatePreferencesIntegrationTest.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * - * Copyright (c) 2022. Deutsche Telekom AG - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * - * - */ - -package org.onap.portal.bff.preferences; - -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; - -import io.restassured.http.Header; -import org.junit.jupiter.api.Test; -import org.onap.portal.bff.openapi.client_portal_prefs.model.PreferencesPortalPrefsDto; -import org.onap.portal.bff.openapi.client_portal_prefs.model.ProblemPortalPrefsDto; -import org.onap.portal.bff.openapi.server.model.CreatePreferencesRequestApiDto; -import org.onap.portal.bff.openapi.server.model.PreferencesResponseApiDto; -import org.onap.portal.bff.openapi.server.model.ProblemApiDto; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; - -class UpdatePreferencesIntegrationTest extends PreferencesMocks { - @Test - void thatPreferencesCanBeUpdated() throws Exception { - PreferencesPortalPrefsDto preferencesPortalPrefsDto = new PreferencesPortalPrefsDto(); - preferencesPortalPrefsDto.setProperties( - "{\n" - + "\"properties\": {\n" - + "\"appStarter\": \"value1\",\n" - + "\"dashboard\": {\"key1:\" : \"value2\"}\n" - + "}\n" - + "\n" - + "}"); - mockUpdatePreferences(preferencesPortalPrefsDto); - - final CreatePreferencesRequestApiDto requestApiDto = - new CreatePreferencesRequestApiDto() - .properties( - "{\n" - + "\"properties\": {\n" - + "\"appStarter\": \"value1\",\n" - + "\"dashboard\": {\"key1:\" : \"value2\"}\n" - + "}\n" - + "\n" - + "}"); - final PreferencesResponseApiDto response = updatePreferences(requestApiDto); - assertThat(response).isNotNull(); - assertThat(response.getProperties()).isEqualTo(preferencesPortalPrefsDto.getProperties()); - } - - @Test - void thatPreferencesCanNotBeUpdated() throws Exception { - final var problemPortalPrefsDto = new ProblemPortalPrefsDto(); - problemPortalPrefsDto.setStatus(HttpStatus.BAD_REQUEST.value()); - problemPortalPrefsDto.setTitle(HttpStatus.BAD_REQUEST.toString()); - problemPortalPrefsDto.setDetail("Some details"); - - final PreferencesPortalPrefsDto preferencesPortalPrefsDto = - new PreferencesPortalPrefsDto() - .properties( - "{\n" - + "\"properties\": {\n" - + "\"appStarter\": \"value1\",\n" - + "\"dashboard\": {\"key1:\" : \"value2\"}\n" - + "}\n" - + "\n" - + "}"); - mockUpdatePreferencesError(preferencesPortalPrefsDto, problemPortalPrefsDto); - - CreatePreferencesRequestApiDto requestApiDto = - new CreatePreferencesRequestApiDto() - .properties( - "{\n" - + "\"properties\": {\n" - + "\"appStarter\": \"value1\",\n" - + "\"dashboard\": {\"key1:\" : \"value2\"}\n" - + "}\n" - + "\n" - + "}"); - final ProblemApiDto response = - requestSpecification() - .given() - .accept(MediaType.APPLICATION_PROBLEM_JSON_VALUE) - .contentType(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", X_REQUEST_ID)) - .body(requestApiDto) - .when() - .put("/preferences") - .then() - .statusCode(HttpStatus.BAD_GATEWAY.value()) - .extract() - .body() - .as(ProblemApiDto.class); - - assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_GATEWAY.value()); - assertThat(response.getDownstreamSystem()) - .isEqualTo(ProblemApiDto.DownstreamSystemEnum.PORTAL_PREFS); - assertThat(response.getDownstreamStatus()).isEqualTo(HttpStatus.BAD_REQUEST.value()); - } -} diff --git a/app/src/test/java/org/onap/portal/bff/roles/ListRealmRolesIntegrationTest.java b/app/src/test/java/org/onap/portal/bff/roles/ListRealmRolesIntegrationTest.java deleted file mode 100644 index 8228ac9..0000000 --- a/app/src/test/java/org/onap/portal/bff/roles/ListRealmRolesIntegrationTest.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * - * Copyright (c) 2022. Deutsche Telekom AG - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * - * - */ - -package org.onap.portal.bff.roles; - -import static org.assertj.core.api.Assertions.assertThat; - -import com.github.tomakehurst.wiremock.client.WireMock; -import io.restassured.http.Header; -import java.util.List; -import org.junit.jupiter.api.Test; -import org.onap.portal.bff.openapi.client_portal_keycloak.model.ErrorResponseKeycloakDto; -import org.onap.portal.bff.openapi.client_portal_keycloak.model.RoleKeycloakDto; -import org.onap.portal.bff.openapi.server.model.ProblemApiDto; -import org.onap.portal.bff.openapi.server.model.RoleApiDto; -import org.onap.portal.bff.openapi.server.model.RoleListResponseApiDto; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; - -class ListRealmRolesIntegrationTest extends RolesMocks { - - @Test - void thatListOfRealmRolesCanBeProvided() throws Exception { - final RoleKeycloakDto keycloakRole1 = new RoleKeycloakDto().id("1").name("role1"); - final RoleKeycloakDto keycloakRole2 = new RoleKeycloakDto().id("2").name("role2"); - final List keycloakRoles = List.of(keycloakRole1, keycloakRole2); - mockListRealmRoles(keycloakRoles); - - final RoleApiDto role1 = new RoleApiDto().id("1").name("role1"); - final RoleApiDto role2 = new RoleApiDto().id("2").name("role2"); - - final RoleListResponseApiDto response = listRoles(); - assertThat(response).isNotNull(); - assertThat(response.getTotalCount()).isEqualTo(response.getItems().size()); - assertThat(response.getItems()).containsExactly(role1, role2); - } - - @Test - void thatListOfRealmRolesCanNotBeProvided() throws Exception { - final ErrorResponseKeycloakDto keycloakErrorResponse = - new ErrorResponseKeycloakDto().errorMessage("Some error message"); - - WireMock.stubFor( - WireMock.get(WireMock.urlMatching(String.format("/auth/admin/realms/%s/roles", realm))) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withStatus(400) - .withBody(objectMapper.writeValueAsString(keycloakErrorResponse)))); - - final ProblemApiDto response = - requestSpecification() - .given() - .accept(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) - .when() - .get("/roles") - .then() - .statusCode(HttpStatus.BAD_GATEWAY.value()) - .extract() - .body() - .as(ProblemApiDto.class); - - assertThat(response).isNotNull(); - assertThat(response.getTitle()).isEqualTo(HttpStatus.BAD_REQUEST.toString()); - assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_GATEWAY.value()); - assertThat(response.getDownstreamSystem()) - .isEqualTo(ProblemApiDto.DownstreamSystemEnum.KEYCLOAK); - } -} diff --git a/app/src/test/java/org/onap/portal/bff/roles/RolesMocks.java b/app/src/test/java/org/onap/portal/bff/roles/RolesMocks.java deleted file mode 100644 index 3243497..0000000 --- a/app/src/test/java/org/onap/portal/bff/roles/RolesMocks.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * - * Copyright (c) 2022. Deutsche Telekom AG - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * - * - */ - -package org.onap.portal.bff.roles; - -import com.github.tomakehurst.wiremock.client.WireMock; -import io.restassured.http.Header; -import java.util.List; -import org.onap.portal.bff.BaseIntegrationTest; -import org.onap.portal.bff.openapi.client_portal_keycloak.model.RoleKeycloakDto; -import org.onap.portal.bff.openapi.server.model.RoleListResponseApiDto; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; - -public class RolesMocks extends BaseIntegrationTest { - - protected RoleListResponseApiDto listRoles() { - return requestSpecification() - .given() - .accept(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) - .when() - .get("/roles") - .then() - .statusCode(HttpStatus.OK.value()) - .extract() - .body() - .as(RoleListResponseApiDto.class); - } - - protected void mockListRealmRoles(List roles) throws Exception { - WireMock.stubFor( - WireMock.get(WireMock.urlMatching(String.format("/auth/admin/realms/%s/roles", realm))) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withBody(objectMapper.writeValueAsString(roles)))); - } -} diff --git a/app/src/test/java/org/onap/portal/bff/users/CreateUserIntegrationTest.java b/app/src/test/java/org/onap/portal/bff/users/CreateUserIntegrationTest.java deleted file mode 100644 index 8fb1eba..0000000 --- a/app/src/test/java/org/onap/portal/bff/users/CreateUserIntegrationTest.java +++ /dev/null @@ -1,307 +0,0 @@ -/* - * - * Copyright (c) 2022. Deutsche Telekom AG - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * - * - */ - -package org.onap.portal.bff.users; - -import static org.assertj.core.api.Assertions.assertThat; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.restassured.http.Header; -import java.util.Collections; -import java.util.List; -import org.junit.jupiter.api.Test; -import org.onap.portal.bff.BaseIntegrationTest; -import org.onap.portal.bff.openapi.client_portal_keycloak.model.ErrorResponseKeycloakDto; -import org.onap.portal.bff.openapi.client_portal_keycloak.model.RequiredActionsKeycloakDto; -import org.onap.portal.bff.openapi.client_portal_keycloak.model.RoleKeycloakDto; -import org.onap.portal.bff.openapi.client_portal_keycloak.model.UserKeycloakDto; -import org.onap.portal.bff.openapi.server.model.CreateUserRequestApiDto; -import org.onap.portal.bff.openapi.server.model.ProblemApiDto; -import org.onap.portal.bff.openapi.server.model.RoleApiDto; -import org.onap.portal.bff.openapi.server.model.RoleListResponseApiDto; -import org.onap.portal.bff.openapi.server.model.UserResponseApiDto; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; - -class CreateUserIntegrationTest extends BaseIntegrationTest { - - @Test - void userCanBeCreated() throws Exception { - String xRequestID = "addf6005-3075-4c80-b7bc-2c70b7d42b57"; - - final UserKeycloakDto keycloakRequest = - new UserKeycloakDto() - .username("user1") - .email("user1@localhost.com") - .enabled(true) - .requiredActions(List.of(RequiredActionsKeycloakDto.UPDATE_PASSWORD)); - final String userId = randomUUID(); - mockCreateUser(keycloakRequest, userId); - - final UserKeycloakDto keycloakResponse = - new UserKeycloakDto() - .id(userId) - .username(keycloakRequest.getUsername()) - .email(keycloakRequest.getEmail()) - .firstName(keycloakRequest.getFirstName()) - .lastName(keycloakRequest.getLastName()) - .enabled(keycloakRequest.getEnabled()); - mockGetUser(userId, keycloakResponse); - - final RoleKeycloakDto onapAdmin = new RoleKeycloakDto().id(randomUUID()).name("onap_admin"); - mockAddRoles(userId, List.of(onapAdmin)); - mockAssignedRoles(userId, List.of(onapAdmin)); - mockListRealmRoles(List.of(onapAdmin)); - - requestSpecification() - .given() - .accept(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", xRequestID)) - .when() - .get("/users/{id}/roles", userId) - .then() - .statusCode(HttpStatus.OK.value()) - .extract() - .body() - .as(RoleListResponseApiDto.class); - mockSendUpdateEmail(userId, List.of(RequiredActionsKeycloakDto.UPDATE_PASSWORD)); - - final CreateUserRequestApiDto request = - new CreateUserRequestApiDto() - .username("user1") - .email("user1@localhost.com") - .firstName(null) - .lastName(null) - .enabled(true) - .addRolesItem(new RoleApiDto().id(onapAdmin.getId()).name("onap_admin")); - - final UserResponseApiDto response = - requestSpecification() - .given() - .accept(MediaType.APPLICATION_JSON_VALUE) - .contentType(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", xRequestID)) - .body(request) - .when() - .post("/users") - .then() - .statusCode(HttpStatus.OK.value()) - .extract() - .body() - .as(UserResponseApiDto.class); - - assertThat(response).isNotNull(); - assertThat(response.getId()).isEqualTo(userId); - assertThat(response.getUsername()).isEqualTo(request.getUsername()); - assertThat(response.getEmail()).isEqualTo(request.getEmail()); - assertThat(response.getFirstName()).isEqualTo(request.getFirstName()); - assertThat(response.getLastName()).isEqualTo(request.getLastName()); - assertThat(response.getEnabled()).isEqualTo(request.getEnabled()); - assertThat(response.getRealmRoles()).containsExactly("onap_admin"); - } - - @Test - void userCanNotBeCreated() throws Exception { - final UserKeycloakDto keycloakRequest = - new UserKeycloakDto() - .username("user1") - .email("user1@localhost.com") - .enabled(true) - .requiredActions(List.of(RequiredActionsKeycloakDto.UPDATE_PASSWORD)); - final String userId = randomUUID(); - mockCreateUser(keycloakRequest, userId); - - final UserKeycloakDto keycloakResponse = - new UserKeycloakDto() - .id(userId) - .username(keycloakRequest.getUsername()) - .email(keycloakRequest.getEmail()) - .firstName(keycloakRequest.getFirstName()) - .lastName(keycloakRequest.getLastName()) - .enabled(keycloakRequest.getEnabled()); - mockGetUser(userId, keycloakResponse); - - final RoleKeycloakDto onapAdmin = new RoleKeycloakDto().id(randomUUID()).name("onap_admin"); - mockAddRoles(userId, List.of(onapAdmin)); - mockListRealmRoles(List.of(onapAdmin)); - - final ErrorResponseKeycloakDto keycloakErrorResponse = - new ErrorResponseKeycloakDto().errorMessage("Some error message"); - - mockSendUpdateEmailWithProblem( - userId, List.of(RequiredActionsKeycloakDto.UPDATE_PASSWORD), keycloakErrorResponse); - - final CreateUserRequestApiDto request = - new CreateUserRequestApiDto() - .username("user1") - .email("user1@localhost.com") - .firstName(null) - .lastName(null) - .enabled(true) - .addRolesItem(new RoleApiDto().id(onapAdmin.getId()).name("onap_admin")); - - final ProblemApiDto response = - requestSpecification() - .given() - .accept(MediaType.APPLICATION_JSON_VALUE) - .contentType(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) - .body(request) - .when() - .post("/users") - .then() - .statusCode(HttpStatus.BAD_GATEWAY.value()) - .extract() - .body() - .as(ProblemApiDto.class); - - assertThat(response).isNotNull(); - assertThat(response.getTitle()).isEqualTo(HttpStatus.BAD_REQUEST.toString()); - assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_GATEWAY.value()); - assertThat(response.getDownstreamSystem()) - .isEqualTo(ProblemApiDto.DownstreamSystemEnum.KEYCLOAK); - } - - @Test - void userCanNotBeCreatedWithNonexistentRoles() throws Exception { - String xRequestID = "addf6005-3075-4c80-b7bc-2c70b7d42b57"; - - mockListRealmRoles(Collections.emptyList()); - - final CreateUserRequestApiDto request = - new CreateUserRequestApiDto() - .username("user1") - .email("user1@localhost.com") - .firstName(null) - .lastName(null) - .enabled(true) - .addRolesItem(new RoleApiDto().id("nonexistent_id").name("nonexistent_role")); - - final ProblemApiDto response = - requestSpecification() - .given() - .accept(MediaType.APPLICATION_JSON_VALUE) - .contentType(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", xRequestID)) - .body(request) - .when() - .post("/users") - .then() - .statusCode(HttpStatus.NOT_FOUND.value()) - .extract() - .body() - .as(ProblemApiDto.class); - - assertThat(response).isNotNull(); - assertThat(response.getTitle()).isEqualTo(HttpStatus.NOT_FOUND.toString()); - assertThat(response.getStatus()).isEqualTo(HttpStatus.NOT_FOUND.value()); - assertThat(response.getDownstreamSystem()) - .isEqualTo(ProblemApiDto.DownstreamSystemEnum.KEYCLOAK); - } - - protected void mockCreateUser(UserKeycloakDto request, String userId) throws Exception { - WireMock.stubFor( - WireMock.post(WireMock.urlMatching(String.format("/auth/admin/realms/%s/users", realm))) - .withRequestBody(WireMock.equalToJson(objectMapper.writeValueAsString(request))) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withHeader( - "location", - String.format("/auth/admin/realms/%s/users/%s", realm, userId)))); - } - - protected void mockGetUser(String userId, UserKeycloakDto response) throws Exception { - WireMock.stubFor( - WireMock.get( - WireMock.urlMatching( - String.format("/auth/admin/realms/%s/users/%s", realm, userId))) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withBody(objectMapper.writeValueAsString(response)))); - } - - protected void mockAddRoles(String userId, List response) throws Exception { - WireMock.stubFor( - WireMock.post( - WireMock.urlMatching( - String.format( - "/auth/admin/realms/%s/users/%s/role-mappings/realm", realm, userId))) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withBody(objectMapper.writeValueAsString(response)))); - } - - protected void mockSendUpdateEmailWithProblem( - String userId, - List request, - ErrorResponseKeycloakDto keycloakErrorResponse) - throws Exception { - WireMock.stubFor( - WireMock.put( - WireMock.urlMatching( - String.format( - "/auth/admin/realms/%s/users/%s/execute-actions-email", realm, userId))) - .withRequestBody(WireMock.equalTo(objectMapper.writeValueAsString(request))) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withStatus(400) - .withBody(objectMapper.writeValueAsString(keycloakErrorResponse)))); - } - - protected void mockAssignedRoles(String userID, List keycloakRoles) - throws JsonProcessingException { - WireMock.stubFor( - WireMock.get( - WireMock.urlMatching( - String.format( - "/auth/admin/realms/%s/users/%s/role-mappings/realm", realm, userID))) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withBody(objectMapper.writeValueAsString(keycloakRoles)))); - } - - protected void mockSendUpdateEmail(String userId, List request) - throws Exception { - WireMock.stubFor( - WireMock.put( - WireMock.urlMatching( - String.format( - "/auth/admin/realms/%s/users/%s/execute-actions-email", realm, userId))) - .withRequestBody(WireMock.equalTo(objectMapper.writeValueAsString(request))) - .willReturn( - WireMock.aResponse().withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE))); - } - - protected void mockListRealmRoles(List roles) throws Exception { - WireMock.stubFor( - WireMock.get(WireMock.urlMatching(String.format("/auth/admin/realms/%s/roles", realm))) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withBody(objectMapper.writeValueAsString(roles)))); - } -} diff --git a/app/src/test/java/org/onap/portal/bff/users/DeleteUserIntegrationTest.java b/app/src/test/java/org/onap/portal/bff/users/DeleteUserIntegrationTest.java deleted file mode 100644 index 69f6906..0000000 --- a/app/src/test/java/org/onap/portal/bff/users/DeleteUserIntegrationTest.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * - * Copyright (c) 2022. Deutsche Telekom AG - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * - * - */ - -package org.onap.portal.bff.users; - -import static org.assertj.core.api.Assertions.assertThat; - -import com.github.tomakehurst.wiremock.client.WireMock; -import io.restassured.http.Header; -import org.junit.jupiter.api.Test; -import org.onap.portal.bff.BaseIntegrationTest; -import org.onap.portal.bff.openapi.client_portal_keycloak.model.ErrorResponseKeycloakDto; -import org.onap.portal.bff.openapi.server.model.ProblemApiDto; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; - -class DeleteUserIntegrationTest extends BaseIntegrationTest { - - @Test - void userCanBeDeleted() { - WireMock.stubFor( - WireMock.delete(WireMock.urlMatching(String.format("/auth/admin/realms/%s/users/1", realm))) - .willReturn(WireMock.aResponse().withStatus(204))); - - requestSpecification() - .given() - .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) - .when() - .delete("/users/1") - .then() - .statusCode(HttpStatus.NO_CONTENT.value()); - } - - @Test - void userCanNotBeDeleted() throws Exception { - final ErrorResponseKeycloakDto keycloakErrorResponse = - new ErrorResponseKeycloakDto().errorMessage("Some error message"); - - WireMock.stubFor( - WireMock.delete(WireMock.urlMatching(String.format("/auth/admin/realms/%s/users/1", realm))) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withStatus(400) - .withBody(objectMapper.writeValueAsString(keycloakErrorResponse)))); - - ProblemApiDto response = - requestSpecification() - .given() - .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) - .when() - .delete("/users/1") - .then() - .statusCode(HttpStatus.BAD_GATEWAY.value()) - .extract() - .body() - .as(ProblemApiDto.class); - - assertThat(response).isNotNull(); - assertThat(response.getTitle()).isEqualTo(HttpStatus.BAD_REQUEST.toString()); - assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_GATEWAY.value()); - assertThat(response.getDownstreamSystem()) - .isEqualTo(ProblemApiDto.DownstreamSystemEnum.KEYCLOAK); - } -} diff --git a/app/src/test/java/org/onap/portal/bff/users/GetUserDetailIntegrationTest.java b/app/src/test/java/org/onap/portal/bff/users/GetUserDetailIntegrationTest.java deleted file mode 100644 index 7974549..0000000 --- a/app/src/test/java/org/onap/portal/bff/users/GetUserDetailIntegrationTest.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * - * Copyright (c) 2022. Deutsche Telekom AG - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * - * - */ - -package org.onap.portal.bff.users; - -import static org.assertj.core.api.Assertions.assertThat; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.restassured.http.Header; -import java.util.List; -import org.junit.jupiter.api.Test; -import org.onap.portal.bff.BaseIntegrationTest; -import org.onap.portal.bff.openapi.client_portal_keycloak.model.ErrorResponseKeycloakDto; -import org.onap.portal.bff.openapi.client_portal_keycloak.model.RoleKeycloakDto; -import org.onap.portal.bff.openapi.client_portal_keycloak.model.UserKeycloakDto; -import org.onap.portal.bff.openapi.server.model.ProblemApiDto; -import org.onap.portal.bff.openapi.server.model.UserResponseApiDto; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; - -class GetUserDetailIntegrationTest extends BaseIntegrationTest { - - @Test - void detailOfUserCanBeProvided() throws Exception { - final UserKeycloakDto keycloakUser = - new UserKeycloakDto().id("1").username("user1").email("user1@localhost").enabled(true); - - WireMock.stubFor( - WireMock.get(WireMock.urlMatching(String.format("/auth/admin/realms/%s/users/1", realm))) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withBody(objectMapper.writeValueAsString(keycloakUser)))); - - final RoleKeycloakDto keycloackRole = new RoleKeycloakDto().id(randomUUID()).name("onap_admin"); - mockAssignedRoles(keycloakUser.getId(), List.of(keycloackRole)); - - final UserResponseApiDto response = - requestSpecification() - .given() - .accept(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) - .when() - .get("/users/1") - .then() - .statusCode(HttpStatus.OK.value()) - .extract() - .body() - .as(UserResponseApiDto.class); - - assertThat(response).isNotNull(); - assertThat(response.getId()).isEqualTo("1"); - assertThat(response.getUsername()).isEqualTo("user1"); - assertThat(response.getEmail()).isEqualTo("user1@localhost"); - assertThat(response.getFirstName()).isNull(); - assertThat(response.getLastName()).isNull(); - assertThat(response.getRealmRoles()).containsExactly(keycloackRole.getName()); - } - - @Test - void detailOfNonExistentUserCanNotBeProvided() throws Exception { - - ErrorResponseKeycloakDto keycloakErrorResponse = - new ErrorResponseKeycloakDto().errorMessage("Some error message"); - - WireMock.stubFor( - WireMock.get(WireMock.urlMatching(String.format("/auth/admin/realms/%s/users/1", realm))) - .willReturn( - WireMock.aResponse() - .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) - .withStatus(400) - .withBody(objectMapper.writeValueAsString(keycloakErrorResponse)))); - - final ProblemApiDto response = - requestSpecification() - .given() - .accept(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) - .when() - .get("/users/1") - .then() - .statusCode(HttpStatus.BAD_GATEWAY.value()) - .extract() - .body() - .as(ProblemApiDto.class); - - assertThat(response).isNotNull(); - assertThat(response.getTitle()).isEqualTo(HttpStatus.BAD_REQUEST.toString()); - assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_GATEWAY.value()); - assertThat(response.getDownstreamSystem()) - .isEqualTo(ProblemApiDto.DownstreamSystemEnum.KEYCLOAK); - } - - protected void mockAssignedRoles(String userID, List keycloakRoles) - throws JsonProcessingException { - WireMock.stubFor( - WireMock.get( - WireMock.urlMatching( - String.format( - "/auth/admin/realms/%s/users/%s/role-mappings/realm", realm, userID))) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withBody(objectMapper.writeValueAsString(keycloakRoles)))); - } -} diff --git a/app/src/test/java/org/onap/portal/bff/users/ListAssignedRolesIntegrationTest.java b/app/src/test/java/org/onap/portal/bff/users/ListAssignedRolesIntegrationTest.java deleted file mode 100644 index 193f399..0000000 --- a/app/src/test/java/org/onap/portal/bff/users/ListAssignedRolesIntegrationTest.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * - * Copyright (c) 2022. Deutsche Telekom AG - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * - * - */ - -package org.onap.portal.bff.users; - -import static org.assertj.core.api.Assertions.assertThat; - -import com.github.tomakehurst.wiremock.client.WireMock; -import io.restassured.http.Header; -import java.util.List; -import org.junit.jupiter.api.Test; -import org.onap.portal.bff.BaseIntegrationTest; -import org.onap.portal.bff.openapi.client_portal_keycloak.model.ErrorResponseKeycloakDto; -import org.onap.portal.bff.openapi.client_portal_keycloak.model.RoleKeycloakDto; -import org.onap.portal.bff.openapi.server.model.ProblemApiDto; -import org.onap.portal.bff.openapi.server.model.RoleApiDto; -import org.onap.portal.bff.openapi.server.model.RoleListResponseApiDto; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; - -class ListAssignedRolesIntegrationTest extends BaseIntegrationTest { - - @Test - void listOfAssignedRolesCanBeProvided() throws Exception { - final RoleKeycloakDto keycloakRole1 = new RoleKeycloakDto().id("1").name("role1"); - final RoleKeycloakDto keycloakRole2 = new RoleKeycloakDto().id("2").name("role2"); - final List keycloakRoles = List.of(keycloakRole1, keycloakRole2); - - WireMock.stubFor( - WireMock.get( - WireMock.urlMatching( - String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withBody(objectMapper.writeValueAsString(keycloakRoles)))); - - final RoleListResponseApiDto response = - requestSpecification() - .given() - .accept(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) - .when() - .get("/users/1/roles") - .then() - .statusCode(HttpStatus.OK.value()) - .extract() - .body() - .as(RoleListResponseApiDto.class); - - final RoleApiDto role1 = new RoleApiDto().id("1").name("role1"); - final RoleApiDto role2 = new RoleApiDto().id("2").name("role2"); - - assertThat(response).isNotNull(); - assertThat(response.getTotalCount()).isEqualTo(response.getItems().size()); - assertThat(response.getItems()).containsExactly(role1, role2); - } - - @Test - void listOfAssignedRolesCanNotBeProvided() throws Exception { - final ErrorResponseKeycloakDto keycloakErrorResponse = - new ErrorResponseKeycloakDto().errorMessage("Some error message"); - - WireMock.stubFor( - WireMock.get( - WireMock.urlMatching( - String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withStatus(400) - .withBody(objectMapper.writeValueAsString(keycloakErrorResponse)))); - - final ProblemApiDto response = - requestSpecification() - .given() - .accept(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) - .when() - .get("/users/1/roles") - .then() - .statusCode(HttpStatus.BAD_GATEWAY.value()) - .extract() - .body() - .as(ProblemApiDto.class); - - assertThat(response).isNotNull(); - assertThat(response.getTitle()).isEqualTo(HttpStatus.BAD_REQUEST.toString()); - assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_GATEWAY.value()); - assertThat(response.getDownstreamSystem()) - .isEqualTo(ProblemApiDto.DownstreamSystemEnum.KEYCLOAK); - } -} diff --git a/app/src/test/java/org/onap/portal/bff/users/ListAvailableRolesIntegrationTest.java b/app/src/test/java/org/onap/portal/bff/users/ListAvailableRolesIntegrationTest.java deleted file mode 100644 index d5f9bbf..0000000 --- a/app/src/test/java/org/onap/portal/bff/users/ListAvailableRolesIntegrationTest.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * - * Copyright (c) 2022. Deutsche Telekom AG - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * - * - */ - -package org.onap.portal.bff.users; - -import static org.assertj.core.api.Assertions.assertThat; - -import com.github.tomakehurst.wiremock.client.WireMock; -import io.restassured.http.Header; -import java.util.List; -import org.junit.jupiter.api.Test; -import org.onap.portal.bff.BaseIntegrationTest; -import org.onap.portal.bff.openapi.client_portal_keycloak.model.ErrorResponseKeycloakDto; -import org.onap.portal.bff.openapi.client_portal_keycloak.model.RoleKeycloakDto; -import org.onap.portal.bff.openapi.server.model.ProblemApiDto; -import org.onap.portal.bff.openapi.server.model.RoleApiDto; -import org.onap.portal.bff.openapi.server.model.RoleListResponseApiDto; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; - -class ListAvailableRolesIntegrationTest extends BaseIntegrationTest { - - @Test - void listOfAvailableRolesCanBeProvided() throws Exception { - final RoleKeycloakDto keycloakRole1 = new RoleKeycloakDto().id("1").name("role1"); - final RoleKeycloakDto keycloakRole2 = new RoleKeycloakDto().id("2").name("role2"); - final List keycloakRoles = List.of(keycloakRole1, keycloakRole2); - - WireMock.stubFor( - WireMock.get( - WireMock.urlMatching( - String.format( - "/auth/admin/realms/%s/users/1/role-mappings/realm/available", realm))) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withBody(objectMapper.writeValueAsString(keycloakRoles)))); - - final RoleListResponseApiDto response = - requestSpecification() - .given() - .accept(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) - .when() - .get("/users/1/roles/available") - .then() - .statusCode(HttpStatus.OK.value()) - .extract() - .body() - .as(RoleListResponseApiDto.class); - - final RoleApiDto role1 = new RoleApiDto().id("1").name("role1"); - final RoleApiDto role2 = new RoleApiDto().id("2").name("role2"); - - assertThat(response).isNotNull(); - assertThat(response.getTotalCount()).isEqualTo(response.getItems().size()); - assertThat(response.getItems()).containsExactly(role1, role2); - } - - @Test - void listOfAvailableRolesCanNotBeProvided() throws Exception { - final ErrorResponseKeycloakDto keycloakErrorResponse = - new ErrorResponseKeycloakDto().errorMessage("Some error message"); - - WireMock.stubFor( - WireMock.get( - WireMock.urlMatching( - String.format( - "/auth/admin/realms/%s/users/1/role-mappings/realm/available", realm))) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withStatus(400) - .withBody(objectMapper.writeValueAsString(keycloakErrorResponse)))); - - ProblemApiDto response = - requestSpecification() - .given() - .accept(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) - .when() - .get("/users/1/roles/available") - .then() - .statusCode(HttpStatus.BAD_GATEWAY.value()) - .extract() - .body() - .as(ProblemApiDto.class); - - assertThat(response).isNotNull(); - assertThat(response.getTitle()).isEqualTo(HttpStatus.BAD_REQUEST.toString()); - assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_GATEWAY.value()); - assertThat(response.getDownstreamSystem()) - .isEqualTo(ProblemApiDto.DownstreamSystemEnum.KEYCLOAK); - } -} diff --git a/app/src/test/java/org/onap/portal/bff/users/ListUsersIntegrationTest.java b/app/src/test/java/org/onap/portal/bff/users/ListUsersIntegrationTest.java deleted file mode 100644 index 18c486a..0000000 --- a/app/src/test/java/org/onap/portal/bff/users/ListUsersIntegrationTest.java +++ /dev/null @@ -1,238 +0,0 @@ -/* - * - * Copyright (c) 2022. Deutsche Telekom AG - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * - * - */ - -package org.onap.portal.bff.users; - -import static org.assertj.core.api.Assertions.assertThat; - -import com.github.tomakehurst.wiremock.client.WireMock; -import io.restassured.http.Header; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import org.junit.jupiter.api.Test; -import org.onap.portal.bff.BaseIntegrationTest; -import org.onap.portal.bff.openapi.client_portal_keycloak.model.ErrorResponseKeycloakDto; -import org.onap.portal.bff.openapi.client_portal_keycloak.model.RoleKeycloakDto; -import org.onap.portal.bff.openapi.client_portal_keycloak.model.UserKeycloakDto; -import org.onap.portal.bff.openapi.server.model.ProblemApiDto; -import org.onap.portal.bff.openapi.server.model.UserListResponseApiDto; -import org.onap.portal.bff.openapi.server.model.UserResponseApiDto; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; - -class ListUsersIntegrationTest extends BaseIntegrationTest { - private final RoleKeycloakDto ONAP_ADMIN = - new RoleKeycloakDto().id(randomUUID()).name("onap_admin"); - private final RoleKeycloakDto OFFLINE_ACCESS = - new RoleKeycloakDto().id(randomUUID()).name("offline_access"); - - @Test - void listOfUsersWithDefaultPaginationCanBeProvided() throws Exception { - final UserKeycloakDto tAdmin = - new UserKeycloakDto() - .id("8f05caaf-0e36-4bcd-b9b3-0ae3d531acc2") - .username("t-admin") - .email("t-admin@example.xyz") - .firstName("FirstName4t-admin") - .lastName("LastName4t-admin") - .enabled(true); - - final UserKeycloakDto tDesigner = - new UserKeycloakDto() - .id("04ed5525-740d-42da-bc4c-2d3fcf955ee9") - .username("t-designer") - .email("t-designer@example.xyz") - .firstName("FirstName4t-designer") - .lastName("LastName4t-designer") - .enabled(true); - - mockGetUserCount(2); - mockListUsers(List.of(tAdmin, tDesigner), 0, 10); - mockListRealmRoles(List.of(ONAP_ADMIN, OFFLINE_ACCESS)); - mockListRoleUsers(OFFLINE_ACCESS.getName(), List.of(tAdmin, tDesigner)); - mockListRoleUsers(ONAP_ADMIN.getName(), List.of(tAdmin)); - - final UserResponseApiDto expectedTAdmin = - new UserResponseApiDto() - .id("8f05caaf-0e36-4bcd-b9b3-0ae3d531acc2") - .username("t-admin") - .email("t-admin@example.xyz") - .firstName("FirstName4t-admin") - .lastName("LastName4t-admin") - .enabled(true) - .addRealmRolesItem("onap_admin") - .addRealmRolesItem("offline_access"); - final UserResponseApiDto expectedTDesigner = - new UserResponseApiDto() - .id("04ed5525-740d-42da-bc4c-2d3fcf955ee9") - .username("t-designer") - .email("t-designer@example.xyz") - .firstName("FirstName4t-designer") - .lastName("LastName4t-designer") - .enabled(true) - .addRealmRolesItem("offline_access"); - - final UserListResponseApiDto response = listUsers(); - assertThat(response).isNotNull(); - assertThat(response.getTotalCount()).isEqualTo(2); - assertThat(response.getItems().get(0).getRealmRoles()) - .containsExactlyInAnyOrder( - expectedTAdmin.getRealmRoles().get(0), expectedTAdmin.getRealmRoles().get(1)); - assertThat(response.getItems().get(1).getRealmRoles()) - .containsExactly(expectedTDesigner.getRealmRoles().get(0)); - } - - @Test - void listOfUsersWithSpecifiedPaginationCanBeProvided() throws Exception { - final UserKeycloakDto keycloakUser = - new UserKeycloakDto() - .id("1") - .username("user1") - .email("user1@localhost") - .firstName("User1") - .lastName("Test") - .enabled(true); - - mockGetUserCount(1); - mockListUsers(List.of(keycloakUser), 60, 30); - mockListRealmRoles(Collections.emptyList()); - - final UserListResponseApiDto response = listUsers(Optional.of(3), Optional.of(30)); - assertThat(response).isNotNull(); - assertThat(response.getTotalCount()).isEqualTo(1); - assertThat(response.getItems()) - .containsExactly( - new UserResponseApiDto() - .id("1") - .username("user1") - .enabled(true) - .email("user1@localhost") - .firstName("User1") - .lastName("Test") - .realmRoles(java.util.List.of())); - } - - @Test - void listOfUsersWithSpecifiedPaginationCanNotBeProvided() throws Exception { - final ErrorResponseKeycloakDto keycloakErrorResponse = - new ErrorResponseKeycloakDto().errorMessage("Some error message"); - - mockGetUserCount(55); - mockListUsersWithProblems(keycloakErrorResponse, 60, 30); - mockListRealmRoles(Collections.emptyList()); - - ProblemApiDto response = - requestSpecification() - .given() - .accept(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) - .when() - .get(adjustPath("/users", Optional.of(3), Optional.of(30))) - .then() - .statusCode(HttpStatus.BAD_GATEWAY.value()) - .extract() - .body() - .as(ProblemApiDto.class); - - assertThat(response).isNotNull(); - assertThat(response.getTitle()).isEqualTo(HttpStatus.BAD_REQUEST.toString()); - assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_GATEWAY.value()); - assertThat(response.getDownstreamSystem()) - .isEqualTo(ProblemApiDto.DownstreamSystemEnum.KEYCLOAK); - } - - protected void mockGetUserCount(Integer userCount) { - WireMock.stubFor( - WireMock.get( - WireMock.urlMatching(String.format("/auth/admin/realms/%s/users/count", realm))) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withBody(userCount.toString()))); - } - - protected void mockListUsers(List keycloakUsers, Integer first, Integer max) - throws Exception { - WireMock.stubFor( - WireMock.get( - WireMock.urlMatching( - String.format( - "/auth/admin/realms/%s/users\\?first=%s&max=%s", realm, first, max))) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withBody(objectMapper.writeValueAsString(keycloakUsers)))); - } - - protected void mockListRealmRoles(List roles) throws Exception { - WireMock.stubFor( - WireMock.get(WireMock.urlMatching(String.format("/auth/admin/realms/%s/roles", realm))) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withBody(objectMapper.writeValueAsString(roles)))); - } - - protected void mockListRoleUsers(String roleName, List response) - throws Exception { - WireMock.stubFor( - WireMock.get( - WireMock.urlMatching( - String.format("/auth/admin/realms/%s/roles/%s/users", realm, roleName))) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withBody(objectMapper.writeValueAsString(response)))); - } - - protected UserListResponseApiDto listUsers() { - return listUsers(Optional.empty(), Optional.empty()); - } - - protected UserListResponseApiDto listUsers(Optional page, Optional pageSize) { - return requestSpecification() - .given() - .accept(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) - .when() - .get(adjustPath("/users", page, pageSize)) - .then() - .statusCode(HttpStatus.OK.value()) - .extract() - .body() - .as(UserListResponseApiDto.class); - } - - protected void mockListUsersWithProblems( - ErrorResponseKeycloakDto keycloakErrorResponse, Integer first, Integer max) throws Exception { - WireMock.stubFor( - WireMock.get( - WireMock.urlMatching( - String.format( - "/auth/admin/realms/%s/users\\?first=%s&max=%s", realm, first, max))) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withStatus(400) - .withBody(objectMapper.writeValueAsString(keycloakErrorResponse)))); - } -} diff --git a/app/src/test/java/org/onap/portal/bff/users/UpdateAssignedRolesIntegrationTest.java b/app/src/test/java/org/onap/portal/bff/users/UpdateAssignedRolesIntegrationTest.java deleted file mode 100644 index 8abe781..0000000 --- a/app/src/test/java/org/onap/portal/bff/users/UpdateAssignedRolesIntegrationTest.java +++ /dev/null @@ -1,453 +0,0 @@ -/* - * - * Copyright (c) 2022. Deutsche Telekom AG - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * - * - */ - -package org.onap.portal.bff.users; - -import static org.assertj.core.api.Assertions.assertThat; - -import com.github.tomakehurst.wiremock.client.WireMock; -import com.github.tomakehurst.wiremock.stubbing.Scenario; -import io.restassured.http.Header; -import java.util.Collections; -import java.util.List; -import org.junit.jupiter.api.Test; -import org.onap.portal.bff.BaseIntegrationTest; -import org.onap.portal.bff.openapi.client_portal_keycloak.model.ErrorResponseKeycloakDto; -import org.onap.portal.bff.openapi.client_portal_keycloak.model.RoleKeycloakDto; -import org.onap.portal.bff.openapi.server.model.ProblemApiDto; -import org.onap.portal.bff.openapi.server.model.RoleApiDto; -import org.onap.portal.bff.openapi.server.model.RoleListResponseApiDto; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; - -class UpdateAssignedRolesIntegrationTest extends BaseIntegrationTest { - - @Test - void listOfAssignedRolesCanBeUpdatedWhenPreviousAssignedRolesAreEmpty() throws Exception { - final RoleKeycloakDto keycloakRole1 = new RoleKeycloakDto().id("1").name("role1"); - final RoleKeycloakDto keycloakRole2 = new RoleKeycloakDto().id("2").name("role2"); - - final List keycloakAvailableRoles = List.of(keycloakRole1, keycloakRole2); - final List keycloakInitialAssignedRoles = List.of(); - final List keycloakUpdatedAssignedRoles = List.of(keycloakRole1); - - final List keycloakRolesToAdd = List.of(keycloakRole1); - - WireMock.stubFor( - WireMock.get( - WireMock.urlMatching( - String.format( - "/auth/admin/realms/%s/users/1/role-mappings/realm/available", realm))) - .inScenario("test") - .whenScenarioStateIs(Scenario.STARTED) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withBody(objectMapper.writeValueAsString(keycloakAvailableRoles)))); - - WireMock.stubFor( - WireMock.get( - WireMock.urlMatching( - String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) - .inScenario("test") - .whenScenarioStateIs(Scenario.STARTED) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withBody(objectMapper.writeValueAsString(keycloakInitialAssignedRoles)))); - - WireMock.stubFor( - WireMock.post( - WireMock.urlMatching( - String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) - .inScenario("test") - .whenScenarioStateIs(Scenario.STARTED) - .withRequestBody(WireMock.equalTo(objectMapper.writeValueAsString(keycloakRolesToAdd))) - .willReturn(WireMock.aResponse().withStatus(HttpStatus.NO_CONTENT.value())) - .willSetStateTo("rolesUpdated")); - - WireMock.stubFor( - WireMock.get( - WireMock.urlMatching( - String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) - .inScenario("test") - .whenScenarioStateIs("rolesUpdated") - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withBody(objectMapper.writeValueAsString(keycloakUpdatedAssignedRoles)))); - - final RoleApiDto roleToAssign = new RoleApiDto().id("1").name("role1"); - final List rolesToAssign = List.of(roleToAssign); - - final RoleListResponseApiDto response = - requestSpecification() - .given() - .accept(MediaType.APPLICATION_JSON_VALUE) - .contentType(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) - .body(rolesToAssign) - .when() - .put("/users/1/roles") - .then() - .statusCode(HttpStatus.OK.value()) - .extract() - .body() - .as(RoleListResponseApiDto.class); - - final RoleApiDto role = new RoleApiDto().id("1").name("role1"); - - assertThat(response).isNotNull(); - assertThat(response.getTotalCount()).isEqualTo(response.getItems().size()); - assertThat(response.getItems()).containsExactly(role); - } - - @Test - void listOfAssignedRolesCanBeUpdatedWhenPreviousAssignedRolesAreNotEmpty() throws Exception { - final RoleKeycloakDto keycloakRole1 = new RoleKeycloakDto().id("1").name("role1"); - final RoleKeycloakDto keycloakRole2 = new RoleKeycloakDto().id("2").name("role2"); - final RoleKeycloakDto keycloakRole3 = new RoleKeycloakDto().id("3").name("role3"); - - final List keycloakAvailableRoles = - List.of(keycloakRole1, keycloakRole2, keycloakRole3); - final List keycloakInitialAssignedRoles = - List.of(keycloakRole1, keycloakRole2); - final List keycloakUpdatedAssignedRoles = List.of(keycloakRole1); - - final List keycloakRolesToRemove = List.of(keycloakRole1, keycloakRole2); - final List keycloakRolesToAdd = List.of(keycloakRole1); - - WireMock.stubFor( - WireMock.get( - WireMock.urlMatching( - String.format( - "/auth/admin/realms/%s/users/1/role-mappings/realm/available", realm))) - .inScenario("test") - .whenScenarioStateIs(Scenario.STARTED) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withBody(objectMapper.writeValueAsString(keycloakAvailableRoles)))); - - WireMock.stubFor( - WireMock.get( - WireMock.urlMatching( - String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) - .inScenario("test") - .whenScenarioStateIs(Scenario.STARTED) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withBody(objectMapper.writeValueAsString(keycloakInitialAssignedRoles)))); - - WireMock.stubFor( - WireMock.delete( - WireMock.urlMatching( - String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) - .inScenario("test") - .whenScenarioStateIs(Scenario.STARTED) - .withRequestBody( - WireMock.equalTo(objectMapper.writeValueAsString(keycloakRolesToRemove))) - .willReturn(WireMock.aResponse().withStatus(HttpStatus.NO_CONTENT.value()))); - - WireMock.stubFor( - WireMock.post( - WireMock.urlMatching( - String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) - .inScenario("test") - .whenScenarioStateIs(Scenario.STARTED) - .withRequestBody(WireMock.equalTo(objectMapper.writeValueAsString(keycloakRolesToAdd))) - .willReturn(WireMock.aResponse().withStatus(HttpStatus.NO_CONTENT.value())) - .willSetStateTo("rolesUpdated")); - - WireMock.stubFor( - WireMock.get( - WireMock.urlMatching( - String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) - .inScenario("test") - .whenScenarioStateIs("rolesUpdated") - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withBody(objectMapper.writeValueAsString(keycloakUpdatedAssignedRoles)))); - - final RoleApiDto roleToAssign = new RoleApiDto().id("1").name("role1"); - final List rolesToAssign = List.of(roleToAssign); - - final RoleListResponseApiDto response = - requestSpecification() - .given() - .accept(MediaType.APPLICATION_JSON_VALUE) - .contentType(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) - .body(rolesToAssign) - .when() - .put("/users/1/roles") - .then() - .statusCode(HttpStatus.OK.value()) - .extract() - .body() - .as(RoleListResponseApiDto.class); - - final RoleApiDto role = new RoleApiDto().id("1").name("role1"); - - assertThat(response).isNotNull(); - assertThat(response.getTotalCount()).isEqualTo(response.getItems().size()); - assertThat(response.getItems()).containsExactly(role); - } - - @Test - void listOfAssignedRolesCanBeCleared() throws Exception { - final RoleKeycloakDto keycloakRole1 = new RoleKeycloakDto().id("1").name("role1"); - final RoleKeycloakDto keycloakRole2 = new RoleKeycloakDto().id("2").name("role2"); - - final List keycloakAvailableRoles = List.of(keycloakRole1, keycloakRole2); - final List keycloakAssignedRoles = Collections.emptyList(); - final List keycloakRolesToRemove = List.of(keycloakRole1, keycloakRole2); - - WireMock.stubFor( - WireMock.get( - WireMock.urlMatching( - String.format( - "/auth/admin/realms/%s/users/1/role-mappings/realm/available", realm))) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withBody(objectMapper.writeValueAsString(keycloakAvailableRoles)))); - - WireMock.stubFor( - WireMock.delete( - WireMock.urlMatching( - String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) - .withRequestBody( - WireMock.equalTo(objectMapper.writeValueAsString(keycloakRolesToRemove))) - .willReturn(WireMock.aResponse().withStatus(HttpStatus.NO_CONTENT.value()))); - - WireMock.stubFor( - WireMock.get( - WireMock.urlMatching( - String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withBody(objectMapper.writeValueAsString(keycloakAssignedRoles)))); - - final List rolesToAssign = Collections.emptyList(); - - final RoleListResponseApiDto response = - requestSpecification() - .given() - .accept(MediaType.APPLICATION_JSON_VALUE) - .contentType(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) - .body(rolesToAssign) - .when() - .put("/users/1/roles") - .then() - .statusCode(HttpStatus.OK.value()) - .extract() - .body() - .as(RoleListResponseApiDto.class); - - assertThat(response).isNotNull(); - assertThat(response.getTotalCount()).isEqualTo(response.getItems().size()); - assertThat(response.getItems()).isEmpty(); - } - - @Test - void listOfAssignedRolesCanNotBeUpdatedWhenPreviousAssignedRolesAreEmpty() throws Exception { - final ErrorResponseKeycloakDto keycloakErrorResponse = - new ErrorResponseKeycloakDto().errorMessage("Some error message"); - - final RoleKeycloakDto keycloakRole1 = new RoleKeycloakDto().id("1").name("role1"); - final RoleKeycloakDto keycloakRole2 = new RoleKeycloakDto().id("2").name("role2"); - - final List keycloakAvailableRoles = List.of(keycloakRole1, keycloakRole2); - final List keycloakInitialAssignedRoles = List.of(); - - final List keycloakRolesToAdd = List.of(keycloakRole1); - - WireMock.stubFor( - WireMock.get( - WireMock.urlMatching( - String.format( - "/auth/admin/realms/%s/users/1/role-mappings/realm/available", realm))) - .inScenario("test") - .whenScenarioStateIs(Scenario.STARTED) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withBody(objectMapper.writeValueAsString(keycloakAvailableRoles)))); - - WireMock.stubFor( - WireMock.get( - WireMock.urlMatching( - String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) - .inScenario("test") - .whenScenarioStateIs(Scenario.STARTED) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withBody(objectMapper.writeValueAsString(keycloakInitialAssignedRoles)))); - - WireMock.stubFor( - WireMock.post( - WireMock.urlMatching( - String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) - .inScenario("test") - .whenScenarioStateIs(Scenario.STARTED) - .withRequestBody(WireMock.equalTo(objectMapper.writeValueAsString(keycloakRolesToAdd))) - .willReturn(WireMock.aResponse().withStatus(HttpStatus.NO_CONTENT.value())) - .willSetStateTo("rolesUpdated")); - - WireMock.stubFor( - WireMock.get( - WireMock.urlMatching( - String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) - .inScenario("test") - .whenScenarioStateIs("rolesUpdated") - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withStatus(400) - .withBody(objectMapper.writeValueAsString(keycloakErrorResponse)))); - - final RoleApiDto roleToAssign = new RoleApiDto().id("1").name("role1"); - final List rolesToAssign = List.of(roleToAssign); - - ProblemApiDto response = - requestSpecification() - .given() - .accept(MediaType.APPLICATION_JSON_VALUE) - .contentType(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) - .body(rolesToAssign) - .when() - .put("/users/1/roles") - .then() - .statusCode(HttpStatus.BAD_GATEWAY.value()) - .extract() - .body() - .as(ProblemApiDto.class); - - assertThat(response).isNotNull(); - assertThat(response.getTitle()).isEqualTo(HttpStatus.BAD_REQUEST.toString()); - assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_GATEWAY.value()); - assertThat(response.getDownstreamSystem()) - .isEqualTo(ProblemApiDto.DownstreamSystemEnum.KEYCLOAK); - } - - @Test - void listOfAssignedRolesCanNotBeUpdatedWhenPreviousAssignedRolesAreNotEmpty() throws Exception { - final ErrorResponseKeycloakDto keycloakErrorResponse = - new ErrorResponseKeycloakDto().errorMessage("Some error message"); - - final RoleKeycloakDto keycloakRole1 = new RoleKeycloakDto().id("1").name("role1"); - final RoleKeycloakDto keycloakRole2 = new RoleKeycloakDto().id("2").name("role2"); - final RoleKeycloakDto keycloakRole3 = new RoleKeycloakDto().id("3").name("role3"); - - final List keycloakAvailableRoles = - List.of(keycloakRole1, keycloakRole2, keycloakRole3); - final List keycloakUpdatedAssignedRoles = List.of(keycloakRole1); - - final List keycloakRolesToRemove = List.of(keycloakRole1, keycloakRole2); - final List keycloakRolesToAdd = List.of(keycloakRole1); - - WireMock.stubFor( - WireMock.get( - WireMock.urlMatching( - String.format( - "/auth/admin/realms/%s/users/1/role-mappings/realm/available", realm))) - .inScenario("test") - .whenScenarioStateIs(Scenario.STARTED) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withBody(objectMapper.writeValueAsString(keycloakAvailableRoles)))); - - WireMock.stubFor( - WireMock.get( - WireMock.urlMatching( - String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) - .inScenario("test") - .whenScenarioStateIs(Scenario.STARTED) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withStatus(400) - .withBody(objectMapper.writeValueAsString(keycloakErrorResponse)))); - - WireMock.stubFor( - WireMock.delete( - WireMock.urlMatching( - String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) - .inScenario("test") - .whenScenarioStateIs(Scenario.STARTED) - .withRequestBody( - WireMock.equalTo(objectMapper.writeValueAsString(keycloakRolesToRemove))) - .willReturn(WireMock.aResponse().withStatus(HttpStatus.NO_CONTENT.value()))); - - WireMock.stubFor( - WireMock.post( - WireMock.urlMatching( - String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) - .inScenario("test") - .whenScenarioStateIs(Scenario.STARTED) - .withRequestBody(WireMock.equalTo(objectMapper.writeValueAsString(keycloakRolesToAdd))) - .willReturn(WireMock.aResponse().withStatus(HttpStatus.NO_CONTENT.value())) - .willSetStateTo("rolesUpdated")); - - WireMock.stubFor( - WireMock.get( - WireMock.urlMatching( - String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) - .inScenario("test") - .whenScenarioStateIs("rolesUpdated") - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withBody(objectMapper.writeValueAsString(keycloakUpdatedAssignedRoles)))); - - final RoleApiDto roleToAssign = new RoleApiDto().id("1").name("role1"); - final List rolesToAssign = List.of(roleToAssign); - - final ProblemApiDto response = - requestSpecification() - .given() - .accept(MediaType.APPLICATION_JSON_VALUE) - .contentType(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) - .body(rolesToAssign) - .when() - .put("/users/1/roles") - .then() - .statusCode(HttpStatus.BAD_GATEWAY.value()) - .extract() - .body() - .as(ProblemApiDto.class); - - assertThat(response).isNotNull(); - assertThat(response.getTitle()).isEqualTo(HttpStatus.BAD_REQUEST.toString()); - assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_GATEWAY.value()); - assertThat(response.getDownstreamSystem()) - .isEqualTo(ProblemApiDto.DownstreamSystemEnum.KEYCLOAK); - } -} diff --git a/app/src/test/java/org/onap/portal/bff/users/UpdateUserIntegrationTest.java b/app/src/test/java/org/onap/portal/bff/users/UpdateUserIntegrationTest.java deleted file mode 100644 index f75773c..0000000 --- a/app/src/test/java/org/onap/portal/bff/users/UpdateUserIntegrationTest.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * - * Copyright (c) 2022. Deutsche Telekom AG - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * - * - */ - -package org.onap.portal.bff.users; - -import static org.assertj.core.api.Assertions.assertThat; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.restassured.http.Header; -import java.util.List; -import org.junit.jupiter.api.Test; -import org.onap.portal.bff.BaseIntegrationTest; -import org.onap.portal.bff.openapi.client_portal_keycloak.model.ErrorResponseKeycloakDto; -import org.onap.portal.bff.openapi.client_portal_keycloak.model.RoleKeycloakDto; -import org.onap.portal.bff.openapi.client_portal_keycloak.model.UserKeycloakDto; -import org.onap.portal.bff.openapi.server.model.ProblemApiDto; -import org.onap.portal.bff.openapi.server.model.UpdateUserRequestApiDto; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; - -class UpdateUserIntegrationTest extends BaseIntegrationTest { - - @Test - void userCanBeUpdated() throws Exception { - final UserKeycloakDto keycloakRequest = new UserKeycloakDto().firstName("User1").enabled(false); - mockUpdateUser(keycloakRequest, "1"); - - final UpdateUserRequestApiDto request = - new UpdateUserRequestApiDto().email(null).firstName("User1").lastName(null).enabled(false); - - requestSpecification() - .given() - .contentType(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) - .body(request) - .when() - .put("/users/1") - .then() - .statusCode(HttpStatus.OK.value()); - } - - @Test - void userCanNotBeUpdated() throws Exception { - final ErrorResponseKeycloakDto keycloakErrorResponse = - new ErrorResponseKeycloakDto().errorMessage("Some error message"); - - final UserKeycloakDto keycloakRequest = new UserKeycloakDto().firstName("User1").enabled(false); - - WireMock.stubFor( - WireMock.put(WireMock.urlMatching(String.format("/auth/admin/realms/%s/users/1", realm))) - .withRequestBody(WireMock.equalTo(objectMapper.writeValueAsString(keycloakRequest))) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withStatus(400) - .withBody(objectMapper.writeValueAsString(keycloakErrorResponse)))); - - final UpdateUserRequestApiDto request = - new UpdateUserRequestApiDto().email(null).firstName("User1").lastName(null).enabled(false); - - final ProblemApiDto response = - requestSpecification() - .given() - .contentType(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) - .body(request) - .when() - .put("/users/1") - .then() - .statusCode(HttpStatus.BAD_GATEWAY.value()) - .extract() - .body() - .as(ProblemApiDto.class); - - assertThat(response).isNotNull(); - assertThat(response.getTitle()).isEqualTo(HttpStatus.BAD_REQUEST.toString()); - assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_GATEWAY.value()); - assertThat(response.getDownstreamSystem()) - .isEqualTo(ProblemApiDto.DownstreamSystemEnum.KEYCLOAK); - } - - protected void mockUpdateUser(UserKeycloakDto request, String userId) throws Exception { - WireMock.stubFor( - WireMock.put( - WireMock.urlMatching( - String.format("/auth/admin/realms/%s/users/%s", realm, userId))) - .withRequestBody(WireMock.equalTo(objectMapper.writeValueAsString(request))) - .willReturn( - WireMock.aResponse().withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE))); - } - - protected void mockGetUser(String userId, UserKeycloakDto response) throws Exception { - WireMock.stubFor( - WireMock.get( - WireMock.urlMatching( - String.format("/auth/admin/realms/%s/users/%s", realm, userId))) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withBody(objectMapper.writeValueAsString(response)))); - } - - protected void mockAssignedRoles(String userID, List keycloakRoles) - throws JsonProcessingException { - WireMock.stubFor( - WireMock.get( - WireMock.urlMatching( - String.format( - "/auth/admin/realms/%s/users/%s/role-mappings/realm", realm, userID))) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withBody(objectMapper.writeValueAsString(keycloakRoles)))); - } -} diff --git a/app/src/test/java/org/onap/portal/bff/users/UpdateUserPasswordIntegrationTest.java b/app/src/test/java/org/onap/portal/bff/users/UpdateUserPasswordIntegrationTest.java deleted file mode 100644 index 200ad69..0000000 --- a/app/src/test/java/org/onap/portal/bff/users/UpdateUserPasswordIntegrationTest.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * - * Copyright (c) 2022. Deutsche Telekom AG - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * - * - */ - -package org.onap.portal.bff.users; - -import static org.assertj.core.api.Assertions.assertThat; - -import com.github.tomakehurst.wiremock.client.WireMock; -import io.restassured.http.Header; -import org.junit.jupiter.api.Test; -import org.onap.portal.bff.BaseIntegrationTest; -import org.onap.portal.bff.openapi.client_portal_keycloak.model.CredentialKeycloakDto; -import org.onap.portal.bff.openapi.client_portal_keycloak.model.ErrorResponseKeycloakDto; -import org.onap.portal.bff.openapi.server.model.ProblemApiDto; -import org.onap.portal.bff.openapi.server.model.UpdateUserPasswordRequestApiDto; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; - -class UpdateUserPasswordIntegrationTest extends BaseIntegrationTest { - - @Test - void userPasswordCanBeUpdated() throws Exception { - final CredentialKeycloakDto keycloakRequest = - new CredentialKeycloakDto().temporary(true).value("pswd"); - - WireMock.stubFor( - WireMock.put( - WireMock.urlMatching( - String.format("/auth/admin/realms/%s/users/1/reset-password", realm))) - .withRequestBody(WireMock.equalTo(objectMapper.writeValueAsString(keycloakRequest))) - .willReturn(WireMock.aResponse().withStatus(204))); - - final UpdateUserPasswordRequestApiDto request = - new UpdateUserPasswordRequestApiDto().temporary(true).value("pswd"); - - requestSpecification() - .given() - .contentType(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) - .body(request) - .when() - .put("/users/1/password") - .then() - .statusCode(HttpStatus.NO_CONTENT.value()); - } - - @Test - void userPasswordCanNotBeUpdated() throws Exception { - final ErrorResponseKeycloakDto keycloakErrorResponse = - new ErrorResponseKeycloakDto().errorMessage("Some error message"); - - final CredentialKeycloakDto keycloakRequest = - new CredentialKeycloakDto().temporary(true).value("pswd"); - - WireMock.stubFor( - WireMock.put( - WireMock.urlMatching( - String.format("/auth/admin/realms/%s/users/1/reset-password", realm))) - .withRequestBody(WireMock.equalTo(objectMapper.writeValueAsString(keycloakRequest))) - .willReturn( - WireMock.aResponse() - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .withStatus(400) - .withBody(objectMapper.writeValueAsString(keycloakErrorResponse)))); - - final UpdateUserPasswordRequestApiDto request = - new UpdateUserPasswordRequestApiDto().temporary(true).value("pswd"); - - final ProblemApiDto response = - requestSpecification() - .given() - .contentType(MediaType.APPLICATION_JSON_VALUE) - .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) - .body(request) - .when() - .put("/users/1/password") - .then() - .statusCode(HttpStatus.BAD_GATEWAY.value()) - .extract() - .body() - .as(ProblemApiDto.class); - - assertThat(response).isNotNull(); - assertThat(response.getTitle()).isEqualTo(HttpStatus.BAD_REQUEST.toString()); - assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_GATEWAY.value()); - assertThat(response.getDownstreamSystem()) - .isEqualTo(ProblemApiDto.DownstreamSystemEnum.KEYCLOAK); - } -} diff --git a/app/src/test/java/org/onap/portalng/bff/ApiDocsIntegrationTest.java b/app/src/test/java/org/onap/portalng/bff/ApiDocsIntegrationTest.java new file mode 100644 index 0000000..98a5360 --- /dev/null +++ b/app/src/test/java/org/onap/portalng/bff/ApiDocsIntegrationTest.java @@ -0,0 +1,40 @@ +/* + * + * Copyright (c) 2022. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + * + */ + +package org.onap.portalng.bff; + +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; + +class ApiDocsIntegrationTest extends BaseIntegrationTest { + + @Test + void apiDocsAreAvailable() { + unauthenticatedRequestSpecification() + .given() + .accept(MediaType.TEXT_HTML_VALUE) + .when() + .get("/api-docs.html") + .then() + .statusCode(HttpStatus.OK.value()); + } +} diff --git a/app/src/test/java/org/onap/portalng/bff/BaseIntegrationTest.java b/app/src/test/java/org/onap/portalng/bff/BaseIntegrationTest.java new file mode 100644 index 0000000..8821b76 --- /dev/null +++ b/app/src/test/java/org/onap/portalng/bff/BaseIntegrationTest.java @@ -0,0 +1,241 @@ +/* + * + * Copyright (c) 2022. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + * + */ + +package org.onap.portalng.bff; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.tomakehurst.wiremock.client.WireMock; +import com.github.tomakehurst.wiremock.extension.responsetemplating.ResponseTemplateTransformer; +import com.nimbusds.jose.jwk.JWKSet; +import io.restassured.RestAssured; +import io.restassured.filter.log.RequestLoggingFilter; +import io.restassured.filter.log.ResponseLoggingFilter; +import io.restassured.specification.RequestSpecification; +import java.net.URISyntaxException; +import java.time.Clock; +import java.time.OffsetDateTime; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import org.apache.http.client.utils.URIBuilder; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.onap.portalng.bff.config.BffConfig; +import org.onap.portalng.bff.config.IdTokenExchangeFilterFunction; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock; +import org.springframework.cloud.contract.wiremock.WireMockConfigurationCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.http.MediaType; + +/** Base class for all tests that has the common config including port, realm, logging and auth. */ +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@AutoConfigureWireMock(port = 0) +public abstract class BaseIntegrationTest { + + @TestConfiguration + public static class Config { + @Bean + WireMockConfigurationCustomizer optionsCustomizer() { + return options -> options.extensions(new ResponseTemplateTransformer(true)); + } + } + + @LocalServerPort protected int port; + + @Value("${bff.realm}") + protected String realm; + + @Autowired protected ObjectMapper objectMapper; + @Autowired private TokenGenerator tokenGenerator; + + @Autowired protected BffConfig bffConfig; + + @BeforeAll + public static void setup() { + RestAssured.filters(new RequestLoggingFilter(), new ResponseLoggingFilter()); + } + + /** Mocks the OIDC auth flow. */ + @BeforeEach + public void mockAuth() { + WireMock.reset(); + + WireMock.stubFor( + WireMock.get( + WireMock.urlMatching( + String.format("/auth/realms/%s/protocol/openid-connect/certs", realm))) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", JWKSet.MIME_TYPE) + .withBody(tokenGenerator.getJwkSet().toString()))); + + final TokenGenerator.TokenGeneratorConfig config = + TokenGenerator.TokenGeneratorConfig.builder().port(port).realm(realm).build(); + + WireMock.stubFor( + WireMock.post( + WireMock.urlMatching( + String.format("/auth/realms/%s/protocol/openid-connect/token", realm))) + .withBasicAuth("test", "test") + .withRequestBody(WireMock.containing("grant_type=client_credentials")) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody( + objectMapper + .createObjectNode() + .put("token_type", "bearer") + .put("access_token", tokenGenerator.generateToken(config)) + .put("expires_in", config.getExpireIn().getSeconds()) + .put("refresh_token", tokenGenerator.generateToken(config)) + .put("refresh_expires_in", config.getExpireIn().getSeconds()) + .put("not-before-policy", 0) + .put("session_state", UUID.randomUUID().toString()) + .put("scope", "email profile") + .toString()))); + } + + /** + * Object to store common attributes of requests that are going to be made. Adds an Identity + * header for the onap_admin role to the request. + */ + protected RequestSpecification requestSpecification() { + final String idToken = tokenGenerator.generateToken(getTokenGeneratorConfig("onap_admin")); + + return unauthenticatedRequestSpecification() + .auth() + .preemptive() + .oauth2(idToken) + .header(IdTokenExchangeFilterFunction.X_AUTH_IDENTITY_HEADER, "Bearer " + idToken); + } + + /** + * Object to store common attributes of requests that are going to be made. Adds an Identity + * header for the given role to the request. + * + * @param role the role used for RBAC + * @return the templated request + */ + protected RequestSpecification requestSpecification(String role) { + final String idToken = tokenGenerator.generateToken(getTokenGeneratorConfig(role)); + + return unauthenticatedRequestSpecification() + .auth() + .preemptive() + .oauth2(idToken) + .header(IdTokenExchangeFilterFunction.X_AUTH_IDENTITY_HEADER, "Bearer " + idToken); + } + + /** + * Object to store common attributes of requests that are going to be made. Adds an Identity + * header for the given roles to the request. + * + * @param roles the roles used for RBAC + * @return the templated request + */ + protected RequestSpecification requestSpecification(List roles) { + final String idToken = tokenGenerator.generateToken(getTokenGeneratorConfig(roles)); + + return unauthenticatedRequestSpecification() + .auth() + .preemptive() + .oauth2(idToken) + .header(IdTokenExchangeFilterFunction.X_AUTH_IDENTITY_HEADER, "Bearer " + idToken); + } + + /** Get a RequestSpecification that does not have an Identity header. */ + protected RequestSpecification unauthenticatedRequestSpecification() { + return RestAssured.given().port(port); + } + + /** + * Builds an OAuth2 configuration including the role, port and realm. This config can be used to + * generate OAuth2 access tokens. + * + * @param role the role used for RBAC + * @return the OAuth2 configuration + */ + protected TokenGenerator.TokenGeneratorConfig getTokenGeneratorConfig(String role) { + return TokenGenerator.TokenGeneratorConfig.builder() + .port(port) + .realm(realm) + .roles(Collections.singletonList(role)) + .build(); + } + + /** + * Builds an OAuth2 configuration including the roles, port and realm. This config can be used to + * generate OAuth2 access tokens. + * + * @param roles the roles used for RBAC + * @return the OAuth2 configuration + */ + protected TokenGenerator.TokenGeneratorConfig getTokenGeneratorConfig(List roles) { + return TokenGenerator.TokenGeneratorConfig.builder() + .port(port) + .realm(realm) + .roles(roles) + .build(); + } + + public static OffsetDateTime offsetNow() { + return OffsetDateTime.now(Clock.systemUTC()); + } + + public static String randomUUID() { + return UUID.randomUUID().toString(); + } + + public static String adjustPath( + String basePath, Optional page, Optional pageSize) { + return adjustPath(basePath, page, pageSize, Optional.empty()); + } + + public static String adjustPath( + String basePath, + Optional page, + Optional pageSize, + Optional filter) { + URIBuilder builder; + try { + builder = new URIBuilder(basePath); + if (page.isPresent()) { + builder.addParameter("page", String.valueOf(page.get())); + } + if (pageSize.isPresent()) { + builder.addParameter("pageSize", String.valueOf(pageSize.get())); + } + if (filter.isPresent()) { + builder.addParameter("filter", filter.get()); + } + return builder.build().toString(); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + return basePath; + } +} diff --git a/app/src/test/java/org/onap/portalng/bff/HealthCheckIntegrationTest.java b/app/src/test/java/org/onap/portalng/bff/HealthCheckIntegrationTest.java new file mode 100644 index 0000000..3d3a1cd --- /dev/null +++ b/app/src/test/java/org/onap/portalng/bff/HealthCheckIntegrationTest.java @@ -0,0 +1,48 @@ +/* + * + * Copyright (c) 2022. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + * + */ + +package org.onap.portalng.bff; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.availability.ApplicationAvailability; +import org.springframework.boot.availability.LivenessState; +import org.springframework.boot.availability.ReadinessState; + +class HealthCheckIntegrationTest extends BaseIntegrationTest { + + @Autowired private ApplicationAvailability applicationAvailability; + + @Test + void livenessProbeIsAvailable() { + + assertThat(applicationAvailability.getLivenessState()).isEqualTo(LivenessState.CORRECT); + } + + @Test + void readinessProbeIsAvailable() { + + assertThat(applicationAvailability.getReadinessState()) + .isEqualTo(ReadinessState.ACCEPTING_TRAFFIC); + } +} diff --git a/app/src/test/java/org/onap/portalng/bff/TokenGenerator.java b/app/src/test/java/org/onap/portalng/bff/TokenGenerator.java new file mode 100644 index 0000000..051129f --- /dev/null +++ b/app/src/test/java/org/onap/portalng/bff/TokenGenerator.java @@ -0,0 +1,122 @@ +/* + * + * Copyright (c) 2022. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + * + */ + +package org.onap.portalng.bff; + +import com.nimbusds.jose.JOSEObjectType; +import com.nimbusds.jose.JWSAlgorithm; +import com.nimbusds.jose.JWSHeader; +import com.nimbusds.jose.JWSSigner; +import com.nimbusds.jose.crypto.RSASSASigner; +import com.nimbusds.jose.jwk.JWKSet; +import com.nimbusds.jose.jwk.KeyUse; +import com.nimbusds.jose.jwk.RSAKey; +import com.nimbusds.jose.jwk.gen.RSAKeyGenerator; +import com.nimbusds.jwt.JWTClaimsSet; +import com.nimbusds.jwt.SignedJWT; +import java.time.Clock; +import java.time.Duration; +import java.time.Instant; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.UUID; +import lombok.Builder; +import lombok.Getter; +import lombok.NonNull; +import org.springframework.stereotype.Component; + +@Component +public class TokenGenerator { + + private static final String ROLES_CLAIM = "roles"; + + private final Clock clock; + private final RSAKey jwk; + private final JWKSet jwkSet; + private final JWSSigner signer; + + public TokenGenerator(Clock clock) { + try { + this.clock = clock; + jwk = + new RSAKeyGenerator(2048) + .keyUse(KeyUse.SIGNATURE) + .keyID(UUID.randomUUID().toString()) + .generate(); + jwkSet = new JWKSet(jwk); + signer = new RSASSASigner(jwk); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public JWKSet getJwkSet() { + return jwkSet; + } + + public String generateToken(TokenGeneratorConfig config) { + final Instant iat = clock.instant(); + final Instant exp = iat.plus(config.expireIn); + + final JWTClaimsSet claims = + new JWTClaimsSet.Builder() + .jwtID(UUID.randomUUID().toString()) + .subject(UUID.randomUUID().toString()) + .issuer(config.issuer()) + .issueTime(Date.from(iat)) + .expirationTime(Date.from(exp)) + .claim(ROLES_CLAIM, config.getRoles()) + .build(); + + final SignedJWT jwt = + new SignedJWT( + new JWSHeader.Builder(JWSAlgorithm.RS256) + .keyID(jwk.getKeyID()) + .type(JOSEObjectType.JWT) + .build(), + claims); + + try { + jwt.sign(signer); + } catch (Exception e) { + throw new RuntimeException(e); + } + + return jwt.serialize(); + } + + @Getter + @Builder + public static class TokenGeneratorConfig { + private final int port; + + @NonNull private final String realm; + + @NonNull @Builder.Default private final Duration expireIn = Duration.ofMinutes(5); + + @Builder.Default private final List roles = Collections.emptyList(); + + public String issuer() { + return String.format("http://localhost:%d/auth/realms/%s", port, realm); + } + } +} diff --git a/app/src/test/java/org/onap/portalng/bff/actions/ActionDto.java b/app/src/test/java/org/onap/portalng/bff/actions/ActionDto.java new file mode 100644 index 0000000..a80f7a1 --- /dev/null +++ b/app/src/test/java/org/onap/portalng/bff/actions/ActionDto.java @@ -0,0 +1,39 @@ +/* + * + * Copyright (c) 2022. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + * + */ + +package org.onap.portalng.bff.actions; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class ActionDto { + String type; + String action; + String message; + String downStreamSystem; + String downStreamId; +} diff --git a/app/src/test/java/org/onap/portalng/bff/actions/ActionFixtures.java b/app/src/test/java/org/onap/portalng/bff/actions/ActionFixtures.java new file mode 100644 index 0000000..0acd0eb --- /dev/null +++ b/app/src/test/java/org/onap/portalng/bff/actions/ActionFixtures.java @@ -0,0 +1,106 @@ +/* + * + * Copyright (c) 2022. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + * + */ + +package org.onap.portalng.bff.actions; + +import java.time.OffsetDateTime; +import java.time.temporal.ChronoUnit; +import org.onap.portalng.bff.openapi.client_portal_history.model.ActionResponsePortalHistoryDto; +import org.onap.portalng.bff.openapi.client_portal_history.model.ActionsListResponsePortalHistoryDto; +import org.onap.portalng.bff.openapi.client_portal_history.model.CreateActionRequestPortalHistoryDto; +import org.onap.portalng.bff.openapi.server.model.CreateActionRequestApiDto; + +public class ActionFixtures { + + public static ActionsListResponsePortalHistoryDto generateActionsListResponse( + Integer numberOfActions, Integer totalCount, OffsetDateTime createdAt) { + ActionsListResponsePortalHistoryDto actionsListResponsePortalHistoryDto = + new ActionsListResponsePortalHistoryDto(); + for (Integer i = 0; i < numberOfActions; i++) { + actionsListResponsePortalHistoryDto.addActionsListItem( + generateActionResponse( + "Instantiation", "create", null, i.toString(), "SO", i, createdAt)); + } + actionsListResponsePortalHistoryDto.setTotalCount(totalCount); + return actionsListResponsePortalHistoryDto; + } + + public static ActionResponsePortalHistoryDto generateActionResponse( + String type, + String action, + String message, + String id, + String downStreamSystem, + Integer deltaHours, + OffsetDateTime createdAt) { + ActionDto actionDto = new ActionDto(); + actionDto.setType(type); + actionDto.setAction(action); + actionDto.setMessage(message); + actionDto.setDownStreamSystem(downStreamSystem); + actionDto.setDownStreamId(id); + + return new ActionResponsePortalHistoryDto() + .action(actionDto) + .actionCreatedAt(createdAt.minus(deltaHours, ChronoUnit.HOURS)); + } + + public static CreateActionRequestPortalHistoryDto generateActionRequestPortalHistoryDto( + String type, + String action, + String message, + String id, + String downStreamSystem, + String userId, + OffsetDateTime createdAt) { + ActionDto actionDto = new ActionDto(); + actionDto.setType(type); + actionDto.setAction(action); + actionDto.setMessage(message); + actionDto.setDownStreamSystem(downStreamSystem); + actionDto.setDownStreamId(id); + return new CreateActionRequestPortalHistoryDto() + .action(actionDto) + .actionCreatedAt(createdAt) + .userId(userId); + } + + public static CreateActionRequestApiDto generateCreateActionRequestApiDto( + String type, + String action, + String message, + String id, + String downStreamSystem, + String userId, + OffsetDateTime createdAt) { + ActionDto actionDto = new ActionDto(); + actionDto.setType(type); + actionDto.setAction(action); + actionDto.setMessage(message); + actionDto.setDownStreamSystem(downStreamSystem); + actionDto.setDownStreamId(id); + + return new CreateActionRequestApiDto() + .action(actionDto) + .actionCreatedAt(createdAt) + .userId(userId); + } +} diff --git a/app/src/test/java/org/onap/portalng/bff/actions/ActionsMocks.java b/app/src/test/java/org/onap/portalng/bff/actions/ActionsMocks.java new file mode 100644 index 0000000..aa9e2f3 --- /dev/null +++ b/app/src/test/java/org/onap/portalng/bff/actions/ActionsMocks.java @@ -0,0 +1,228 @@ +/* + * + * Copyright (c) 2022. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + * + */ + +package org.onap.portalng.bff.actions; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.github.tomakehurst.wiremock.client.WireMock; +import com.github.tomakehurst.wiremock.matching.EqualToPattern; +import io.restassured.http.Header; +import org.apache.http.HttpHeaders; +import org.onap.portalng.bff.BaseIntegrationTest; +import org.onap.portalng.bff.openapi.client_portal_history.model.ActionResponsePortalHistoryDto; +import org.onap.portalng.bff.openapi.client_portal_history.model.ActionsListResponsePortalHistoryDto; +import org.onap.portalng.bff.openapi.client_portal_history.model.ProblemPortalHistoryDto; +import org.onap.portalng.bff.openapi.server.model.ActionsListResponseApiDto; +import org.onap.portalng.bff.openapi.server.model.ActionsResponseApiDto; +import org.onap.portalng.bff.openapi.server.model.CreateActionRequestApiDto; +import org.onap.portalng.bff.openapi.server.model.ProblemApiDto; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; + +public class ActionsMocks extends BaseIntegrationTest { + protected static final String X_REQUEST_ID = "addf6005-3075-4c80-b7bc-2c70b7d42b00"; + + // used for test thatActionsListCanBeRetrieved + protected ActionsListResponseApiDto listActions() { + return requestSpecification() + .given() + .accept(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", X_REQUEST_ID)) + .when() + .get("/actions") + .then() + .statusCode(HttpStatus.OK.value()) + .extract() + .body() + .as(ActionsListResponseApiDto.class); + } + + // used for test thatActionsListCanBeRetrieved + protected void mockListActions( + ActionsListResponsePortalHistoryDto actionsListResponsePortalHistoryDto) throws Exception { + WireMock.stubFor( + WireMock.get(WireMock.urlEqualTo("/v1/actions?page=1&pageSize=10")) + .withHeader("X-Request-Id", new EqualToPattern(X_REQUEST_ID)) + .willReturn( + WireMock.aResponse() + .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .withBody( + objectMapper.writeValueAsString(actionsListResponsePortalHistoryDto)))); + } + + // used for test thatActionsListCanNotBeRetrieved + protected ProblemApiDto listActionsProblem() { + return requestSpecification() + .given() + .accept(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", X_REQUEST_ID)) + .when() + .get("/actions") + .then() + .statusCode(HttpStatus.BAD_GATEWAY.value()) + .extract() + .body() + .as(ProblemApiDto.class); + } + + // used for test thatActionsListCanNotBeRetrieved + protected void mockListActionsProblem(ProblemPortalHistoryDto problemPortalHistoryDto) + throws Exception { + WireMock.stubFor( + WireMock.get(WireMock.urlEqualTo("/v1/actions?page=1&pageSize=10")) + .withHeader("X-Request-Id", new EqualToPattern(X_REQUEST_ID)) + .willReturn( + WireMock.aResponse() + .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_PROBLEM_JSON_VALUE) + .withStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()) + .withBody(objectMapper.writeValueAsString(problemPortalHistoryDto)))); + } + + // used for test thatActionCanBeRetrieved + protected void mockGetActions( + ActionsListResponsePortalHistoryDto actionsListResponsePortalHistoryDto, + String userId, + Integer showLastHours) + throws Exception { + WireMock.stubFor( + WireMock.get( + WireMock.urlEqualTo( + "/v1/actions/" + + userId + + "?page=1&pageSize=10" + + "&showLastHours=" + + showLastHours)) + .withHeader("X-Request-Id", new EqualToPattern(X_REQUEST_ID)) + .willReturn( + WireMock.aResponse() + .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .withBody( + objectMapper.writeValueAsString(actionsListResponsePortalHistoryDto)))); + } + // used for test thatActionCanBeRetrieved + protected ActionsListResponseApiDto getActions(String userId) { + return requestSpecification() + .given() + .accept(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", X_REQUEST_ID)) + .when() + .get("/actions/" + userId + "?page=1&pageSize=10&showLastHours=2") + .then() + .statusCode(HttpStatus.OK.value()) + .extract() + .body() + .as(ActionsListResponseApiDto.class); + } + + // used for test thatActionCanBeRetrievedWithoutParameterShowLastHours + protected void mockGetActionsWithoutParameterShowLastHours( + ActionsListResponsePortalHistoryDto actionsListResponsePortalHistoryDto, String userId) + throws Exception { + WireMock.stubFor( + WireMock.get(WireMock.urlEqualTo("/v1/actions/" + userId + "?page=1&pageSize=10")) + .withHeader("X-Request-Id", new EqualToPattern(X_REQUEST_ID)) + .willReturn( + WireMock.aResponse() + .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .withBody( + objectMapper.writeValueAsString(actionsListResponsePortalHistoryDto)))); + } + // used for test thatActionCanBeRetrievedWithoutParameterShowLastHours + protected ActionsListResponseApiDto getActionsWithoutParameterShowLastHours(String userId) { + return requestSpecification() + .given() + .accept(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", X_REQUEST_ID)) + .when() + .get("/actions/" + userId + "?page=1&pageSize=10") + .then() + .statusCode(HttpStatus.OK.value()) + .extract() + .body() + .as(ActionsListResponseApiDto.class); + } + + // Used for thatActionCanBeCreated + protected void mockCreateActions( + String userId, ActionResponsePortalHistoryDto actionResponsePortalHistoryDto) + throws Exception { + WireMock.stubFor( + WireMock.post(WireMock.urlEqualTo("/v1/actions/" + userId)) + .withHeader("X-Request-Id", new EqualToPattern(X_REQUEST_ID)) + .withRequestBody(WireMock.matchingJsonPath("$.action")) + .willReturn( + WireMock.aResponse() + .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .withStatus(200) + .withBody(objectMapper.writeValueAsString(actionResponsePortalHistoryDto)))); + } + + // Used for thatActionCanBeCreated + protected ActionsResponseApiDto createAction( + CreateActionRequestApiDto createActionRequestApiDto, String userId) throws Exception { + return requestSpecification() + .given() + .accept(MediaType.APPLICATION_JSON_VALUE) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", X_REQUEST_ID)) + .body(objectMapper.writeValueAsString(createActionRequestApiDto)) + .when() + .post("/actions/" + userId) + .then() + .statusCode(HttpStatus.OK.value()) + .extract() + .body() + .as(ActionsResponseApiDto.class); + } + + // Used for thatActionCanNotBeCreated + protected void mockCreateActionsProblem( + String userId, ProblemPortalHistoryDto problemPortalHistoryDto) + throws JsonProcessingException { + WireMock.stubFor( + WireMock.post(WireMock.urlEqualTo("/v1/actions/" + userId)) + .withHeader("X-Request-Id", new EqualToPattern(X_REQUEST_ID)) + .withRequestBody(WireMock.matchingJsonPath("$.action")) + .willReturn( + WireMock.aResponse() + .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_PROBLEM_JSON_VALUE) + .withStatus(500) + .withBody(objectMapper.writeValueAsString(problemPortalHistoryDto)))); + } + // Used for thatActionCanNotBeCreated + protected ProblemApiDto createActionProblem( + CreateActionRequestApiDto createActionRequestApiDto, String userId) + throws JsonProcessingException { + return requestSpecification() + .given() + .accept(MediaType.APPLICATION_JSON_VALUE) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", X_REQUEST_ID)) + .body(objectMapper.writeValueAsString(createActionRequestApiDto)) + .when() + .post("/actions/" + userId) + .then() + .statusCode(HttpStatus.BAD_GATEWAY.value()) + .extract() + .body() + .as(ProblemApiDto.class); + } +} diff --git a/app/src/test/java/org/onap/portalng/bff/actions/CreateActionsIntegrationTest.java b/app/src/test/java/org/onap/portalng/bff/actions/CreateActionsIntegrationTest.java new file mode 100644 index 0000000..3508f19 --- /dev/null +++ b/app/src/test/java/org/onap/portalng/bff/actions/CreateActionsIntegrationTest.java @@ -0,0 +1,85 @@ +/* + * + * Copyright (c) 2022. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + * + */ + +package org.onap.portalng.bff.actions; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.OffsetDateTime; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.onap.portalng.bff.openapi.client_portal_history.model.ActionResponsePortalHistoryDto; +import org.onap.portalng.bff.openapi.client_portal_history.model.ProblemPortalHistoryDto; +import org.onap.portalng.bff.openapi.server.model.ActionsResponseApiDto; +import org.onap.portalng.bff.openapi.server.model.CreateActionRequestApiDto; +import org.onap.portalng.bff.openapi.server.model.ProblemApiDto; +import org.springframework.http.HttpStatus; + +class CreateActionsIntegrationTest extends ActionsMocks { + + @Test + void thatActionCanBeCreated() throws Exception { + String userId = "22-33-44-55"; + OffsetDateTime createdAt = OffsetDateTime.now(); + ActionResponsePortalHistoryDto actionResponsePortalHistoryDto = + ActionFixtures.generateActionResponse( + "Instantiation", "create", "no detail message", "223344", "SO", 0, createdAt); + CreateActionRequestApiDto createActionDto = + ActionFixtures.generateCreateActionRequestApiDto( + "Instantiation", "create", "no detail message", "223344", "SO", userId, createdAt); + + mockCreateActions(userId, actionResponsePortalHistoryDto); + + final ActionsResponseApiDto response = createAction(createActionDto, userId); + + assertThat(response.getActionCreatedAt()) + .isEqualTo(actionResponsePortalHistoryDto.getActionCreatedAt()); + Assertions.assertThat(objectMapper.writeValueAsString(response.getAction())) + .isEqualTo(objectMapper.writeValueAsString(actionResponsePortalHistoryDto.getAction())); + } + + @Test + void thatActionCanNotBeCreated() throws Exception { + String userId = "22-33-44-55"; + OffsetDateTime createdAt = OffsetDateTime.now(); + + ProblemPortalHistoryDto problemPortalHistoryDto = + new ProblemPortalHistoryDto() + .status(HttpStatus.INTERNAL_SERVER_ERROR.value()) + .detail("Internal database error") + .title("Internal Server Error") + .instance("portal-history"); + + CreateActionRequestApiDto createActionDto = + ActionFixtures.generateCreateActionRequestApiDto( + "Instantiation", "create", "no detail message", "223344", "SO", userId, createdAt); + + mockCreateActionsProblem(userId, problemPortalHistoryDto); + + final ProblemApiDto response = createActionProblem(createActionDto, userId); + + assertThat(response.getDownstreamSystem()) + .isEqualTo(ProblemApiDto.DownstreamSystemEnum.PORTAL_HISTORY); + + assertThat(response.getDownstreamStatus()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR.value()); + assertThat(response.getDetail()).isEqualTo(problemPortalHistoryDto.getDetail()); + } +} diff --git a/app/src/test/java/org/onap/portalng/bff/actions/GetActionsIntegrationTest.java b/app/src/test/java/org/onap/portalng/bff/actions/GetActionsIntegrationTest.java new file mode 100644 index 0000000..489a8d3 --- /dev/null +++ b/app/src/test/java/org/onap/portalng/bff/actions/GetActionsIntegrationTest.java @@ -0,0 +1,79 @@ +/* + * + * Copyright (c) 2022. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + * + */ + +package org.onap.portalng.bff.actions; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.OffsetDateTime; +import org.junit.jupiter.api.Test; +import org.onap.portalng.bff.openapi.client_portal_history.model.ActionsListResponsePortalHistoryDto; +import org.onap.portalng.bff.openapi.server.model.ActionsListResponseApiDto; + +class GetActionsIntegrationTest extends ActionsMocks { + + @Test + void thatActionCanBeRetrievedWithParameterShowLastHours() throws Exception { + int numberOfActions = 10; + Integer showLastHours = 2; + String userId = "22-33-44-55"; + OffsetDateTime createdAt = OffsetDateTime.now(); + ActionsListResponsePortalHistoryDto actionsListResponsePortalHistoryDto = + ActionFixtures.generateActionsListResponse(numberOfActions, 30, createdAt); + + mockGetActions(actionsListResponsePortalHistoryDto, userId, showLastHours); + + final ActionsListResponseApiDto response = getActions(userId); + + assertThat(response.getTotalCount()).isEqualTo(30); + assertThat(response.getItems()).hasSize(numberOfActions); + assertThat(response.getItems().get(0).getActionCreatedAt()) + .isEqualTo( + actionsListResponsePortalHistoryDto.getActionsList().get(0).getActionCreatedAt()); + assertThat(objectMapper.writeValueAsString(response.getItems().get(0).getAction())) + .isEqualTo( + objectMapper.writeValueAsString( + actionsListResponsePortalHistoryDto.getActionsList().get(0).getAction())); + } + + @Test + void thatActionCanBeRetrievedWithoutParameterShowLastHours() throws Exception { + int numberOfActions = 10; + String userId = "22-33-44-55"; + OffsetDateTime createdAt = OffsetDateTime.now(); + ActionsListResponsePortalHistoryDto actionsListResponsePortalHistoryDto = + ActionFixtures.generateActionsListResponse(numberOfActions, 30, createdAt); + + mockGetActionsWithoutParameterShowLastHours(actionsListResponsePortalHistoryDto, userId); + + final ActionsListResponseApiDto response = getActionsWithoutParameterShowLastHours(userId); + + assertThat(response.getTotalCount()).isEqualTo(30); + assertThat(response.getItems()).hasSize(numberOfActions); + assertThat(response.getItems().get(0).getActionCreatedAt()) + .isEqualTo( + actionsListResponsePortalHistoryDto.getActionsList().get(0).getActionCreatedAt()); + assertThat(objectMapper.writeValueAsString(response.getItems().get(0).getAction())) + .isEqualTo( + objectMapper.writeValueAsString( + actionsListResponsePortalHistoryDto.getActionsList().get(0).getAction())); + } +} diff --git a/app/src/test/java/org/onap/portalng/bff/actions/ListActionsIntegrationTest.java b/app/src/test/java/org/onap/portalng/bff/actions/ListActionsIntegrationTest.java new file mode 100644 index 0000000..8451641 --- /dev/null +++ b/app/src/test/java/org/onap/portalng/bff/actions/ListActionsIntegrationTest.java @@ -0,0 +1,78 @@ +/* + * + * Copyright (c) 2022. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + * + */ + +package org.onap.portalng.bff.actions; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.OffsetDateTime; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.onap.portalng.bff.openapi.client_portal_history.model.ActionsListResponsePortalHistoryDto; +import org.onap.portalng.bff.openapi.client_portal_history.model.ProblemPortalHistoryDto; +import org.onap.portalng.bff.openapi.server.model.ActionsListResponseApiDto; +import org.onap.portalng.bff.openapi.server.model.ProblemApiDto; +import org.springframework.http.HttpStatus; + +class ListActionsIntegrationTest extends ActionsMocks { + + @Test + void thatActionsListCanBeRetrieved() throws Exception { + int numberOfActions = 10; + OffsetDateTime createdAt = OffsetDateTime.now(); + ActionsListResponsePortalHistoryDto actionsListResponsePortalHistoryDto = + ActionFixtures.generateActionsListResponse(numberOfActions, 1000, createdAt); + + mockListActions(actionsListResponsePortalHistoryDto); + + final ActionsListResponseApiDto response = listActions(); + + assertThat(response.getTotalCount()).isEqualTo(1000); + assertThat(response.getItems()).hasSize(numberOfActions); + assertThat(response.getItems().get(0).getActionCreatedAt()) + .isEqualTo( + actionsListResponsePortalHistoryDto.getActionsList().get(0).getActionCreatedAt()); + Assertions.assertThat(objectMapper.writeValueAsString(response.getItems().get(0).getAction())) + .isEqualTo( + objectMapper.writeValueAsString( + actionsListResponsePortalHistoryDto.getActionsList().get(0).getAction())); + } + + @Test + void thatActionsListCanNotBeRetrieved() throws Exception { + + ProblemPortalHistoryDto problemPortalHistoryDto = + new ProblemPortalHistoryDto() + .status(HttpStatus.INTERNAL_SERVER_ERROR.value()) + .detail("Internal database error") + .title("Internal Server Error") + .instance("portal-history"); + + mockListActionsProblem(problemPortalHistoryDto); + + final ProblemApiDto response = listActionsProblem(); + + assertThat(response.getDownstreamSystem()) + .isEqualTo(ProblemApiDto.DownstreamSystemEnum.PORTAL_HISTORY); + assertThat(response.getDownstreamStatus()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR.value()); + assertThat(response.getDetail()).isEqualTo(problemPortalHistoryDto.getDetail()); + } +} diff --git a/app/src/test/java/org/onap/portalng/bff/headers/XRequestIdHeaderTest.java b/app/src/test/java/org/onap/portalng/bff/headers/XRequestIdHeaderTest.java new file mode 100644 index 0000000..6f82308 --- /dev/null +++ b/app/src/test/java/org/onap/portalng/bff/headers/XRequestIdHeaderTest.java @@ -0,0 +1,75 @@ +/* + * + * Copyright (c) 2022. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + * + */ + +package org.onap.portalng.bff.headers; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.github.tomakehurst.wiremock.client.WireMock; +import com.github.tomakehurst.wiremock.matching.EqualToPattern; +import io.restassured.http.Header; +import org.junit.jupiter.api.Test; +import org.onap.portalng.bff.BaseIntegrationTest; +import org.onap.portalng.bff.openapi.client_portal_prefs.model.PreferencesPortalPrefsDto; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; + +class XRequestIdHeaderTest extends BaseIntegrationTest { + protected static final String X_REQUEST_ID = "addf6005-3075-4c80-b7bc-2c70b7d42b57"; + + @Test + void xRequestIdHeaderIsCorrectlySetInResponse() throws Exception { + // use preferences endpoint for testing the header + final PreferencesPortalPrefsDto preferencesPortalPrefsDto = new PreferencesPortalPrefsDto(); + + // mockGetTile(tileDetailResponsePortalServiceDto, X_REQUEST_ID); + mockGetPreferences(preferencesPortalPrefsDto, X_REQUEST_ID); + + final String response = getPreferencesExtractHeader(X_REQUEST_ID); + assertThat(response).isEqualTo(X_REQUEST_ID); + } + + protected void mockGetPreferences( + PreferencesPortalPrefsDto preferencesPortalPrefsDto, String xRequestId) throws Exception { + WireMock.stubFor( + WireMock.get(WireMock.urlEqualTo("/v1/preferences")) + .withHeader("X-Request-Id", new EqualToPattern(X_REQUEST_ID)) + .willReturn( + WireMock.aResponse() + .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .withHeader("X-Request-Id", xRequestId) + .withBody(objectMapper.writeValueAsString(preferencesPortalPrefsDto)))); + } + + protected String getPreferencesExtractHeader(String xRequestId) { + return requestSpecification() + .given() + .accept(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", xRequestId)) + .when() + .get("/preferences") + .then() + .statusCode(HttpStatus.OK.value()) + .extract() + .header("X-Request-Id"); + } +} diff --git a/app/src/test/java/org/onap/portalng/bff/idtoken/IdTokenExchangeFilterFunctionTest.java b/app/src/test/java/org/onap/portalng/bff/idtoken/IdTokenExchangeFilterFunctionTest.java new file mode 100644 index 0000000..cb6694a --- /dev/null +++ b/app/src/test/java/org/onap/portalng/bff/idtoken/IdTokenExchangeFilterFunctionTest.java @@ -0,0 +1,89 @@ +/* + * + * Copyright (c) 2022. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + * + */ + +package org.onap.portalng.bff.idtoken; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.mock; + +import java.net.URI; +import java.util.UUID; +import org.junit.jupiter.api.Test; +import org.onap.portalng.bff.BaseIntegrationTest; +import org.onap.portalng.bff.config.IdTokenExchangeFilterFunction; +import org.springframework.http.HttpMethod; +import org.springframework.mock.http.server.reactive.MockServerHttpRequest; +import org.springframework.mock.web.server.MockServerWebExchange; +import org.springframework.web.reactive.function.client.ClientRequest; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.ExchangeFunction; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +class IdTokenExchangeFilterFunctionTest extends BaseIntegrationTest { + + @Test + void idTokenIsCorrectlyPropagated() { + final IdTokenExchangeFilterFunction filterFunction = new IdTokenExchangeFilterFunction(); + + final String idToken = UUID.randomUUID().toString(); + final ServerWebExchange serverWebExchange = + MockServerWebExchange.builder( + MockServerHttpRequest.get("http://localhost:8000") + .header(IdTokenExchangeFilterFunction.X_AUTH_IDENTITY_HEADER, idToken)) + .build(); + + final ClientRequest request = + ClientRequest.create(HttpMethod.GET, URI.create("http://api-server:9000")) + .attribute(ServerWebExchange.class.getName(), serverWebExchange) + .build(); + final ClientResponse response = mock(ClientResponse.class); + + final ExchangeFunction exchange = + r -> { + assertThat(r.headers().getOrEmpty(IdTokenExchangeFilterFunction.X_AUTH_IDENTITY_HEADER)) + .containsExactly(idToken); + + return Mono.just(response); + }; + + final ClientResponse result = filterFunction.filter(request, exchange).block(); + assertThat(result).isEqualTo(response); + } + + @Test + void exceptionIsThrownWhenIdTokenIsMissingInRequest() { + final IdTokenExchangeFilterFunction filterFunction = new IdTokenExchangeFilterFunction(); + + final ServerWebExchange serverWebExchange = + MockServerWebExchange.builder(MockServerHttpRequest.get("http://localhost:8000")).build(); + + final ClientRequest request = + ClientRequest.create(HttpMethod.GET, URI.create("http://api-server:9000")) + .attribute(ServerWebExchange.class.getName(), serverWebExchange) + .build(); + final ExchangeFunction exchange = r -> Mono.just(mock(ClientResponse.class)); + + assertThatThrownBy(() -> filterFunction.filter(request, exchange).block()) + .hasMessage("Forbidden: ID token is missing"); + } +} diff --git a/app/src/test/java/org/onap/portalng/bff/preferences/CreatePreferencesIntegrationTest.java b/app/src/test/java/org/onap/portalng/bff/preferences/CreatePreferencesIntegrationTest.java new file mode 100644 index 0000000..65a6f19 --- /dev/null +++ b/app/src/test/java/org/onap/portalng/bff/preferences/CreatePreferencesIntegrationTest.java @@ -0,0 +1,115 @@ +/* + * + * Copyright (c) 2022. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + * + */ + +package org.onap.portalng.bff.preferences; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import io.restassured.http.Header; +import org.junit.jupiter.api.Test; +import org.onap.portalng.bff.openapi.client_portal_prefs.model.PreferencesPortalPrefsDto; +import org.onap.portalng.bff.openapi.client_portal_prefs.model.ProblemPortalPrefsDto; +import org.onap.portalng.bff.openapi.server.model.CreatePreferencesRequestApiDto; +import org.onap.portalng.bff.openapi.server.model.PreferencesResponseApiDto; +import org.onap.portalng.bff.openapi.server.model.ProblemApiDto; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; + +class CreatePreferencesIntegrationTest extends PreferencesMocks { + @Test + void thatPreferencesCanBeCreated() throws Exception { + PreferencesPortalPrefsDto preferencesPortalPrefsDto = new PreferencesPortalPrefsDto(); + preferencesPortalPrefsDto.setProperties( + "{\n" + + "\"properties\": {\n" + + "\"appStarter\": \"value1\",\n" + + "\"dashboard\": {\"key1:\" : \"value2\"}\n" + + "}\n" + + "\n" + + "}"); + mockCreatePreferences(preferencesPortalPrefsDto); + + final CreatePreferencesRequestApiDto request = + new CreatePreferencesRequestApiDto() + .properties( + "{\n" + + "\"properties\": {\n" + + "\"appStarter\": \"value1\",\n" + + "\"dashboard\": {\"key1:\" : \"value2\"}\n" + + "}\n" + + "\n" + + "}"); + final PreferencesResponseApiDto response = createPreferences(request); + assertThat(response).isNotNull(); + assertThat(response.getProperties()).isEqualTo(preferencesPortalPrefsDto.getProperties()); + } + + @Test + void thatPreferencesCanNotBeCreated() throws Exception { + final var problemPortalPrefsDto = new ProblemPortalPrefsDto(); + problemPortalPrefsDto.setStatus(HttpStatus.BAD_REQUEST.value()); + problemPortalPrefsDto.setTitle(HttpStatus.BAD_REQUEST.toString()); + problemPortalPrefsDto.setDetail("Some details"); + + final PreferencesPortalPrefsDto preferencesPortalPrefsDto = + new PreferencesPortalPrefsDto() + .properties( + "{\n" + + "\"properties\": {\n" + + "\"appStarter\": \"value1\",\n" + + "\"dashboard\": {\"key1:\" : \"value2\"}\n" + + "}\n" + + "\n" + + "}"); + mockCreatePreferencesError(preferencesPortalPrefsDto, problemPortalPrefsDto); + + CreatePreferencesRequestApiDto responseBody = + new CreatePreferencesRequestApiDto() + .properties( + "{\n" + + "\"properties\": {\n" + + "\"appStarter\": \"value1\",\n" + + "\"dashboard\": {\"key1:\" : \"value2\"}\n" + + "}\n" + + "\n" + + "}"); + final ProblemApiDto response = + requestSpecification() + .given() + .accept(MediaType.APPLICATION_PROBLEM_JSON_VALUE) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", X_REQUEST_ID)) + .body(responseBody) + .when() + .post("/preferences") + .then() + .statusCode(HttpStatus.BAD_GATEWAY.value()) + .extract() + .body() + .as(ProblemApiDto.class); + + assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_GATEWAY.value()); + assertThat(response.getDetail()).isEqualTo(problemPortalPrefsDto.getDetail()); + assertThat(response.getDownstreamSystem()) + .isEqualTo(ProblemApiDto.DownstreamSystemEnum.PORTAL_PREFS); + assertThat(response.getDownstreamStatus()).isEqualTo(HttpStatus.BAD_REQUEST.value()); + } +} diff --git a/app/src/test/java/org/onap/portalng/bff/preferences/GetPreferencesIntegrationTest.java b/app/src/test/java/org/onap/portalng/bff/preferences/GetPreferencesIntegrationTest.java new file mode 100644 index 0000000..06329d4 --- /dev/null +++ b/app/src/test/java/org/onap/portalng/bff/preferences/GetPreferencesIntegrationTest.java @@ -0,0 +1,77 @@ +/* + * + * Copyright (c) 2022. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + * + */ + +package org.onap.portalng.bff.preferences; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.restassured.http.Header; +import org.junit.jupiter.api.Test; +import org.onap.portalng.bff.openapi.client_portal_prefs.model.PreferencesPortalPrefsDto; +import org.onap.portalng.bff.openapi.client_portal_prefs.model.ProblemPortalPrefsDto; +import org.onap.portalng.bff.openapi.server.model.PreferencesResponseApiDto; +import org.onap.portalng.bff.openapi.server.model.ProblemApiDto; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; + +class GetPreferencesIntegrationTest extends PreferencesMocks { + + @Test + void thatPreferencesCanBeRetrieved() throws Exception { + PreferencesPortalPrefsDto preferencesPortalPrefsDto = new PreferencesPortalPrefsDto(); + preferencesPortalPrefsDto.setProperties(getFixture(PREF_PROPERTIES_FILE, Object.class)); + mockGetPreferences(preferencesPortalPrefsDto); + + final PreferencesResponseApiDto response = getPreferences(); + assertThat(response).isNotNull(); + } + + @Test + void thatPreferencesCanNotBeRetrieved() throws Exception { + final ProblemPortalPrefsDto problemResponse = + new ProblemPortalPrefsDto() + .title("Unauthorized") + .status(HttpStatus.UNAUTHORIZED.value()) + .detail("Unauthorized error detail") + .instance("instance") + .type("type"); + + mockGetPreferencesError(problemResponse); + + final ProblemApiDto errorResponse = + requestSpecification() + .given() + .accept(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) + .when() + .get("/preferences") + .then() + .statusCode(HttpStatus.BAD_GATEWAY.value()) + .contentType(MediaType.APPLICATION_PROBLEM_JSON_VALUE) + .extract() + .body() + .as(ProblemApiDto.class); + + assertThat(errorResponse.getStatus()).isEqualTo(HttpStatus.BAD_GATEWAY.value()); + assertThat(errorResponse.getTitle()).isEqualTo(HttpStatus.UNAUTHORIZED.toString()); + assertThat(errorResponse.getDetail()).isEqualTo("Unauthorized error detail"); + } +} diff --git a/app/src/test/java/org/onap/portalng/bff/preferences/PreferencesMocks.java b/app/src/test/java/org/onap/portalng/bff/preferences/PreferencesMocks.java new file mode 100644 index 0000000..0d5b69a --- /dev/null +++ b/app/src/test/java/org/onap/portalng/bff/preferences/PreferencesMocks.java @@ -0,0 +1,182 @@ +/* + * + * Copyright (c) 2022. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + * + */ + +package org.onap.portalng.bff.preferences; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.tomakehurst.wiremock.client.WireMock; +import com.github.tomakehurst.wiremock.matching.EqualToPattern; +import io.restassured.http.Header; +import java.io.File; +import java.io.IOException; +import org.apache.http.HttpHeaders; +import org.onap.portalng.bff.BaseIntegrationTest; +import org.onap.portalng.bff.openapi.client_portal_prefs.model.PreferencesPortalPrefsDto; +import org.onap.portalng.bff.openapi.client_portal_prefs.model.ProblemPortalPrefsDto; +import org.onap.portalng.bff.openapi.server.model.CreatePreferencesRequestApiDto; +import org.onap.portalng.bff.openapi.server.model.PreferencesResponseApiDto; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; + +public class PreferencesMocks extends BaseIntegrationTest { + protected static final String X_REQUEST_ID = "addf6005-3075-4c80-b7bc-2c70b7d42b57"; + + protected static final String PREF_PROPERTIES_FILE = + "src/test/resources/preferences/preferencesProperties.json"; + + protected static final ObjectMapper objectMapper = + new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL); + + protected static T getFixture(final String fileName, Class type) throws IOException { + return objectMapper.readValue(new File(fileName), type); + } + + protected PreferencesResponseApiDto getPreferences() { + + return requestSpecification() + .given() + .accept(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", X_REQUEST_ID)) + .when() + .get("/preferences") + .then() + .statusCode(HttpStatus.OK.value()) + .extract() + .body() + .as(PreferencesResponseApiDto.class); + } + + protected void mockGetPreferences(PreferencesPortalPrefsDto preferencesPortalPrefsDto) + throws Exception { + WireMock.stubFor( + WireMock.get(WireMock.urlEqualTo("/v1/preferences")) + .withHeader("X-Request-Id", new EqualToPattern(X_REQUEST_ID)) + .willReturn( + WireMock.aResponse() + .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .withBody(objectMapper.writeValueAsString(preferencesPortalPrefsDto)))); + } + + protected void mockGetPreferencesError(ProblemPortalPrefsDto problem) throws Exception { + WireMock.stubFor( + WireMock.get(WireMock.urlEqualTo("/v1/preferences")) + .withHeader("X-Request-Id", new EqualToPattern(X_REQUEST_ID)) + .willReturn( + WireMock.aResponse() + .withHeader( + org.springframework.http.HttpHeaders.CONTENT_TYPE, + MediaType.APPLICATION_PROBLEM_JSON_VALUE) + .withBody(objectMapper.writeValueAsString(problem)) + .withStatus(HttpStatus.UNAUTHORIZED.value()))); + } + + protected PreferencesResponseApiDto createPreferences(CreatePreferencesRequestApiDto request) { + return requestSpecification() + .given() + .contentType(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", X_REQUEST_ID)) + .body(request) + .when() + .post("/preferences") + .then() + .statusCode(HttpStatus.OK.value()) + .extract() + .body() + .as(PreferencesResponseApiDto.class); + } + + protected void mockCreatePreferences(PreferencesPortalPrefsDto preferencesPortalPrefsDto) + throws Exception { + WireMock.stubFor( + WireMock.post(WireMock.urlEqualTo("/v1/preferences")) + .withHeader("X-Request-Id", new EqualToPattern(X_REQUEST_ID)) + .withRequestBody( + WireMock.equalToJson( + objectMapper.writeValueAsString(preferencesPortalPrefsDto), true, false)) + .willReturn( + WireMock.aResponse() + .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .withBody(objectMapper.writeValueAsString(preferencesPortalPrefsDto)))); + } + + protected void mockCreatePreferencesError( + PreferencesPortalPrefsDto preferencesPortalPrefsDto, + ProblemPortalPrefsDto problemPortalPrefsDto) + throws Exception { + WireMock.stubFor( + WireMock.post(WireMock.urlEqualTo("/v1/preferences")) + .withHeader("X-Request-Id", new EqualToPattern(X_REQUEST_ID)) + .withRequestBody( + WireMock.equalToJson( + objectMapper.writeValueAsString(preferencesPortalPrefsDto), true, false)) + .willReturn( + WireMock.aResponse() + .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .withStatus(HttpStatus.BAD_REQUEST.value()) + .withBody(objectMapper.writeValueAsString(problemPortalPrefsDto)))); + } + + protected PreferencesResponseApiDto updatePreferences(CreatePreferencesRequestApiDto request) { + return requestSpecification() + .given() + .contentType(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", X_REQUEST_ID)) + .body(request) + .when() + .put("/preferences") + .then() + .statusCode(HttpStatus.OK.value()) + .extract() + .body() + .as(PreferencesResponseApiDto.class); + } + + protected void mockUpdatePreferences(PreferencesPortalPrefsDto preferencesPortalPrefsDto) + throws Exception { + WireMock.stubFor( + WireMock.put(WireMock.urlEqualTo("/v1/preferences")) + .withHeader("X-Request-Id", new EqualToPattern(X_REQUEST_ID)) + .withRequestBody( + WireMock.equalToJson( + objectMapper.writeValueAsString(preferencesPortalPrefsDto), true, false)) + .willReturn( + WireMock.aResponse() + .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .withBody(objectMapper.writeValueAsString(preferencesPortalPrefsDto)))); + } + + protected void mockUpdatePreferencesError( + PreferencesPortalPrefsDto preferencesPortalPrefsDto, + ProblemPortalPrefsDto problemPortalPrefsDto) + throws Exception { + WireMock.stubFor( + WireMock.put(WireMock.urlEqualTo("/v1/preferences")) + .withRequestBody( + WireMock.equalToJson( + objectMapper.writeValueAsString(preferencesPortalPrefsDto), true, false)) + .willReturn( + WireMock.aResponse() + .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .withStatus(HttpStatus.BAD_REQUEST.value()) + .withBody(objectMapper.writeValueAsString(problemPortalPrefsDto)))); + } +} diff --git a/app/src/test/java/org/onap/portalng/bff/preferences/UpdatePreferencesIntegrationTest.java b/app/src/test/java/org/onap/portalng/bff/preferences/UpdatePreferencesIntegrationTest.java new file mode 100644 index 0000000..031726e --- /dev/null +++ b/app/src/test/java/org/onap/portalng/bff/preferences/UpdatePreferencesIntegrationTest.java @@ -0,0 +1,114 @@ +/* + * + * Copyright (c) 2022. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + * + */ + +package org.onap.portalng.bff.preferences; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import io.restassured.http.Header; +import org.junit.jupiter.api.Test; +import org.onap.portalng.bff.openapi.client_portal_prefs.model.PreferencesPortalPrefsDto; +import org.onap.portalng.bff.openapi.client_portal_prefs.model.ProblemPortalPrefsDto; +import org.onap.portalng.bff.openapi.server.model.CreatePreferencesRequestApiDto; +import org.onap.portalng.bff.openapi.server.model.PreferencesResponseApiDto; +import org.onap.portalng.bff.openapi.server.model.ProblemApiDto; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; + +class UpdatePreferencesIntegrationTest extends PreferencesMocks { + @Test + void thatPreferencesCanBeUpdated() throws Exception { + PreferencesPortalPrefsDto preferencesPortalPrefsDto = new PreferencesPortalPrefsDto(); + preferencesPortalPrefsDto.setProperties( + "{\n" + + "\"properties\": {\n" + + "\"appStarter\": \"value1\",\n" + + "\"dashboard\": {\"key1:\" : \"value2\"}\n" + + "}\n" + + "\n" + + "}"); + mockUpdatePreferences(preferencesPortalPrefsDto); + + final CreatePreferencesRequestApiDto requestApiDto = + new CreatePreferencesRequestApiDto() + .properties( + "{\n" + + "\"properties\": {\n" + + "\"appStarter\": \"value1\",\n" + + "\"dashboard\": {\"key1:\" : \"value2\"}\n" + + "}\n" + + "\n" + + "}"); + final PreferencesResponseApiDto response = updatePreferences(requestApiDto); + assertThat(response).isNotNull(); + assertThat(response.getProperties()).isEqualTo(preferencesPortalPrefsDto.getProperties()); + } + + @Test + void thatPreferencesCanNotBeUpdated() throws Exception { + final var problemPortalPrefsDto = new ProblemPortalPrefsDto(); + problemPortalPrefsDto.setStatus(HttpStatus.BAD_REQUEST.value()); + problemPortalPrefsDto.setTitle(HttpStatus.BAD_REQUEST.toString()); + problemPortalPrefsDto.setDetail("Some details"); + + final PreferencesPortalPrefsDto preferencesPortalPrefsDto = + new PreferencesPortalPrefsDto() + .properties( + "{\n" + + "\"properties\": {\n" + + "\"appStarter\": \"value1\",\n" + + "\"dashboard\": {\"key1:\" : \"value2\"}\n" + + "}\n" + + "\n" + + "}"); + mockUpdatePreferencesError(preferencesPortalPrefsDto, problemPortalPrefsDto); + + CreatePreferencesRequestApiDto requestApiDto = + new CreatePreferencesRequestApiDto() + .properties( + "{\n" + + "\"properties\": {\n" + + "\"appStarter\": \"value1\",\n" + + "\"dashboard\": {\"key1:\" : \"value2\"}\n" + + "}\n" + + "\n" + + "}"); + final ProblemApiDto response = + requestSpecification() + .given() + .accept(MediaType.APPLICATION_PROBLEM_JSON_VALUE) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", X_REQUEST_ID)) + .body(requestApiDto) + .when() + .put("/preferences") + .then() + .statusCode(HttpStatus.BAD_GATEWAY.value()) + .extract() + .body() + .as(ProblemApiDto.class); + + assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_GATEWAY.value()); + assertThat(response.getDownstreamSystem()) + .isEqualTo(ProblemApiDto.DownstreamSystemEnum.PORTAL_PREFS); + assertThat(response.getDownstreamStatus()).isEqualTo(HttpStatus.BAD_REQUEST.value()); + } +} diff --git a/app/src/test/java/org/onap/portalng/bff/roles/ListRealmRolesIntegrationTest.java b/app/src/test/java/org/onap/portalng/bff/roles/ListRealmRolesIntegrationTest.java new file mode 100644 index 0000000..df95e2c --- /dev/null +++ b/app/src/test/java/org/onap/portalng/bff/roles/ListRealmRolesIntegrationTest.java @@ -0,0 +1,88 @@ +/* + * + * Copyright (c) 2022. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + * + */ + +package org.onap.portalng.bff.roles; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.github.tomakehurst.wiremock.client.WireMock; +import io.restassured.http.Header; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.onap.portalng.bff.openapi.client_portal_keycloak.model.ErrorResponseKeycloakDto; +import org.onap.portalng.bff.openapi.client_portal_keycloak.model.RoleKeycloakDto; +import org.onap.portalng.bff.openapi.server.model.ProblemApiDto; +import org.onap.portalng.bff.openapi.server.model.RoleApiDto; +import org.onap.portalng.bff.openapi.server.model.RoleListResponseApiDto; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; + +class ListRealmRolesIntegrationTest extends RolesMocks { + + @Test + void thatListOfRealmRolesCanBeProvided() throws Exception { + final RoleKeycloakDto keycloakRole1 = new RoleKeycloakDto().id("1").name("role1"); + final RoleKeycloakDto keycloakRole2 = new RoleKeycloakDto().id("2").name("role2"); + final List keycloakRoles = List.of(keycloakRole1, keycloakRole2); + mockListRealmRoles(keycloakRoles); + + final RoleApiDto role1 = new RoleApiDto().id("1").name("role1"); + final RoleApiDto role2 = new RoleApiDto().id("2").name("role2"); + + final RoleListResponseApiDto response = listRoles(); + assertThat(response).isNotNull(); + assertThat(response.getTotalCount()).isEqualTo(response.getItems().size()); + assertThat(response.getItems()).containsExactly(role1, role2); + } + + @Test + void thatListOfRealmRolesCanNotBeProvided() throws Exception { + final ErrorResponseKeycloakDto keycloakErrorResponse = + new ErrorResponseKeycloakDto().errorMessage("Some error message"); + + WireMock.stubFor( + WireMock.get(WireMock.urlMatching(String.format("/auth/admin/realms/%s/roles", realm))) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withStatus(400) + .withBody(objectMapper.writeValueAsString(keycloakErrorResponse)))); + + final ProblemApiDto response = + requestSpecification() + .given() + .accept(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) + .when() + .get("/roles") + .then() + .statusCode(HttpStatus.BAD_GATEWAY.value()) + .extract() + .body() + .as(ProblemApiDto.class); + + assertThat(response).isNotNull(); + assertThat(response.getTitle()).isEqualTo(HttpStatus.BAD_REQUEST.toString()); + assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_GATEWAY.value()); + assertThat(response.getDownstreamSystem()) + .isEqualTo(ProblemApiDto.DownstreamSystemEnum.KEYCLOAK); + } +} diff --git a/app/src/test/java/org/onap/portalng/bff/roles/RolesMocks.java b/app/src/test/java/org/onap/portalng/bff/roles/RolesMocks.java new file mode 100644 index 0000000..fe065a7 --- /dev/null +++ b/app/src/test/java/org/onap/portalng/bff/roles/RolesMocks.java @@ -0,0 +1,57 @@ +/* + * + * Copyright (c) 2022. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + * + */ + +package org.onap.portalng.bff.roles; + +import com.github.tomakehurst.wiremock.client.WireMock; +import io.restassured.http.Header; +import java.util.List; +import org.onap.portalng.bff.BaseIntegrationTest; +import org.onap.portalng.bff.openapi.client_portal_keycloak.model.RoleKeycloakDto; +import org.onap.portalng.bff.openapi.server.model.RoleListResponseApiDto; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; + +public class RolesMocks extends BaseIntegrationTest { + + protected RoleListResponseApiDto listRoles() { + return requestSpecification() + .given() + .accept(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) + .when() + .get("/roles") + .then() + .statusCode(HttpStatus.OK.value()) + .extract() + .body() + .as(RoleListResponseApiDto.class); + } + + protected void mockListRealmRoles(List roles) throws Exception { + WireMock.stubFor( + WireMock.get(WireMock.urlMatching(String.format("/auth/admin/realms/%s/roles", realm))) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(objectMapper.writeValueAsString(roles)))); + } +} diff --git a/app/src/test/java/org/onap/portalng/bff/users/CreateUserIntegrationTest.java b/app/src/test/java/org/onap/portalng/bff/users/CreateUserIntegrationTest.java new file mode 100644 index 0000000..aa67631 --- /dev/null +++ b/app/src/test/java/org/onap/portalng/bff/users/CreateUserIntegrationTest.java @@ -0,0 +1,307 @@ +/* + * + * Copyright (c) 2022. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + * + */ + +package org.onap.portalng.bff.users; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.github.tomakehurst.wiremock.client.WireMock; +import io.restassured.http.Header; +import java.util.Collections; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.onap.portalng.bff.BaseIntegrationTest; +import org.onap.portalng.bff.openapi.client_portal_keycloak.model.ErrorResponseKeycloakDto; +import org.onap.portalng.bff.openapi.client_portal_keycloak.model.RequiredActionsKeycloakDto; +import org.onap.portalng.bff.openapi.client_portal_keycloak.model.RoleKeycloakDto; +import org.onap.portalng.bff.openapi.client_portal_keycloak.model.UserKeycloakDto; +import org.onap.portalng.bff.openapi.server.model.CreateUserRequestApiDto; +import org.onap.portalng.bff.openapi.server.model.ProblemApiDto; +import org.onap.portalng.bff.openapi.server.model.RoleApiDto; +import org.onap.portalng.bff.openapi.server.model.RoleListResponseApiDto; +import org.onap.portalng.bff.openapi.server.model.UserResponseApiDto; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; + +class CreateUserIntegrationTest extends BaseIntegrationTest { + + @Test + void userCanBeCreated() throws Exception { + String xRequestID = "addf6005-3075-4c80-b7bc-2c70b7d42b57"; + + final UserKeycloakDto keycloakRequest = + new UserKeycloakDto() + .username("user1") + .email("user1@localhost.com") + .enabled(true) + .requiredActions(List.of(RequiredActionsKeycloakDto.UPDATE_PASSWORD)); + final String userId = randomUUID(); + mockCreateUser(keycloakRequest, userId); + + final UserKeycloakDto keycloakResponse = + new UserKeycloakDto() + .id(userId) + .username(keycloakRequest.getUsername()) + .email(keycloakRequest.getEmail()) + .firstName(keycloakRequest.getFirstName()) + .lastName(keycloakRequest.getLastName()) + .enabled(keycloakRequest.getEnabled()); + mockGetUser(userId, keycloakResponse); + + final RoleKeycloakDto onapAdmin = new RoleKeycloakDto().id(randomUUID()).name("onap_admin"); + mockAddRoles(userId, List.of(onapAdmin)); + mockAssignedRoles(userId, List.of(onapAdmin)); + mockListRealmRoles(List.of(onapAdmin)); + + requestSpecification() + .given() + .accept(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", xRequestID)) + .when() + .get("/users/{id}/roles", userId) + .then() + .statusCode(HttpStatus.OK.value()) + .extract() + .body() + .as(RoleListResponseApiDto.class); + mockSendUpdateEmail(userId, List.of(RequiredActionsKeycloakDto.UPDATE_PASSWORD)); + + final CreateUserRequestApiDto request = + new CreateUserRequestApiDto() + .username("user1") + .email("user1@localhost.com") + .firstName(null) + .lastName(null) + .enabled(true) + .addRolesItem(new RoleApiDto().id(onapAdmin.getId()).name("onap_admin")); + + final UserResponseApiDto response = + requestSpecification() + .given() + .accept(MediaType.APPLICATION_JSON_VALUE) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", xRequestID)) + .body(request) + .when() + .post("/users") + .then() + .statusCode(HttpStatus.OK.value()) + .extract() + .body() + .as(UserResponseApiDto.class); + + assertThat(response).isNotNull(); + assertThat(response.getId()).isEqualTo(userId); + assertThat(response.getUsername()).isEqualTo(request.getUsername()); + assertThat(response.getEmail()).isEqualTo(request.getEmail()); + assertThat(response.getFirstName()).isEqualTo(request.getFirstName()); + assertThat(response.getLastName()).isEqualTo(request.getLastName()); + assertThat(response.getEnabled()).isEqualTo(request.getEnabled()); + assertThat(response.getRealmRoles()).containsExactly("onap_admin"); + } + + @Test + void userCanNotBeCreated() throws Exception { + final UserKeycloakDto keycloakRequest = + new UserKeycloakDto() + .username("user1") + .email("user1@localhost.com") + .enabled(true) + .requiredActions(List.of(RequiredActionsKeycloakDto.UPDATE_PASSWORD)); + final String userId = randomUUID(); + mockCreateUser(keycloakRequest, userId); + + final UserKeycloakDto keycloakResponse = + new UserKeycloakDto() + .id(userId) + .username(keycloakRequest.getUsername()) + .email(keycloakRequest.getEmail()) + .firstName(keycloakRequest.getFirstName()) + .lastName(keycloakRequest.getLastName()) + .enabled(keycloakRequest.getEnabled()); + mockGetUser(userId, keycloakResponse); + + final RoleKeycloakDto onapAdmin = new RoleKeycloakDto().id(randomUUID()).name("onap_admin"); + mockAddRoles(userId, List.of(onapAdmin)); + mockListRealmRoles(List.of(onapAdmin)); + + final ErrorResponseKeycloakDto keycloakErrorResponse = + new ErrorResponseKeycloakDto().errorMessage("Some error message"); + + mockSendUpdateEmailWithProblem( + userId, List.of(RequiredActionsKeycloakDto.UPDATE_PASSWORD), keycloakErrorResponse); + + final CreateUserRequestApiDto request = + new CreateUserRequestApiDto() + .username("user1") + .email("user1@localhost.com") + .firstName(null) + .lastName(null) + .enabled(true) + .addRolesItem(new RoleApiDto().id(onapAdmin.getId()).name("onap_admin")); + + final ProblemApiDto response = + requestSpecification() + .given() + .accept(MediaType.APPLICATION_JSON_VALUE) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) + .body(request) + .when() + .post("/users") + .then() + .statusCode(HttpStatus.BAD_GATEWAY.value()) + .extract() + .body() + .as(ProblemApiDto.class); + + assertThat(response).isNotNull(); + assertThat(response.getTitle()).isEqualTo(HttpStatus.BAD_REQUEST.toString()); + assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_GATEWAY.value()); + assertThat(response.getDownstreamSystem()) + .isEqualTo(ProblemApiDto.DownstreamSystemEnum.KEYCLOAK); + } + + @Test + void userCanNotBeCreatedWithNonexistentRoles() throws Exception { + String xRequestID = "addf6005-3075-4c80-b7bc-2c70b7d42b57"; + + mockListRealmRoles(Collections.emptyList()); + + final CreateUserRequestApiDto request = + new CreateUserRequestApiDto() + .username("user1") + .email("user1@localhost.com") + .firstName(null) + .lastName(null) + .enabled(true) + .addRolesItem(new RoleApiDto().id("nonexistent_id").name("nonexistent_role")); + + final ProblemApiDto response = + requestSpecification() + .given() + .accept(MediaType.APPLICATION_JSON_VALUE) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", xRequestID)) + .body(request) + .when() + .post("/users") + .then() + .statusCode(HttpStatus.NOT_FOUND.value()) + .extract() + .body() + .as(ProblemApiDto.class); + + assertThat(response).isNotNull(); + assertThat(response.getTitle()).isEqualTo(HttpStatus.NOT_FOUND.toString()); + assertThat(response.getStatus()).isEqualTo(HttpStatus.NOT_FOUND.value()); + assertThat(response.getDownstreamSystem()) + .isEqualTo(ProblemApiDto.DownstreamSystemEnum.KEYCLOAK); + } + + protected void mockCreateUser(UserKeycloakDto request, String userId) throws Exception { + WireMock.stubFor( + WireMock.post(WireMock.urlMatching(String.format("/auth/admin/realms/%s/users", realm))) + .withRequestBody(WireMock.equalToJson(objectMapper.writeValueAsString(request))) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withHeader( + "location", + String.format("/auth/admin/realms/%s/users/%s", realm, userId)))); + } + + protected void mockGetUser(String userId, UserKeycloakDto response) throws Exception { + WireMock.stubFor( + WireMock.get( + WireMock.urlMatching( + String.format("/auth/admin/realms/%s/users/%s", realm, userId))) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(objectMapper.writeValueAsString(response)))); + } + + protected void mockAddRoles(String userId, List response) throws Exception { + WireMock.stubFor( + WireMock.post( + WireMock.urlMatching( + String.format( + "/auth/admin/realms/%s/users/%s/role-mappings/realm", realm, userId))) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(objectMapper.writeValueAsString(response)))); + } + + protected void mockSendUpdateEmailWithProblem( + String userId, + List request, + ErrorResponseKeycloakDto keycloakErrorResponse) + throws Exception { + WireMock.stubFor( + WireMock.put( + WireMock.urlMatching( + String.format( + "/auth/admin/realms/%s/users/%s/execute-actions-email", realm, userId))) + .withRequestBody(WireMock.equalTo(objectMapper.writeValueAsString(request))) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withStatus(400) + .withBody(objectMapper.writeValueAsString(keycloakErrorResponse)))); + } + + protected void mockAssignedRoles(String userID, List keycloakRoles) + throws JsonProcessingException { + WireMock.stubFor( + WireMock.get( + WireMock.urlMatching( + String.format( + "/auth/admin/realms/%s/users/%s/role-mappings/realm", realm, userID))) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(objectMapper.writeValueAsString(keycloakRoles)))); + } + + protected void mockSendUpdateEmail(String userId, List request) + throws Exception { + WireMock.stubFor( + WireMock.put( + WireMock.urlMatching( + String.format( + "/auth/admin/realms/%s/users/%s/execute-actions-email", realm, userId))) + .withRequestBody(WireMock.equalTo(objectMapper.writeValueAsString(request))) + .willReturn( + WireMock.aResponse().withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE))); + } + + protected void mockListRealmRoles(List roles) throws Exception { + WireMock.stubFor( + WireMock.get(WireMock.urlMatching(String.format("/auth/admin/realms/%s/roles", realm))) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(objectMapper.writeValueAsString(roles)))); + } +} diff --git a/app/src/test/java/org/onap/portalng/bff/users/DeleteUserIntegrationTest.java b/app/src/test/java/org/onap/portalng/bff/users/DeleteUserIntegrationTest.java new file mode 100644 index 0000000..639e5d3 --- /dev/null +++ b/app/src/test/java/org/onap/portalng/bff/users/DeleteUserIntegrationTest.java @@ -0,0 +1,83 @@ +/* + * + * Copyright (c) 2022. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + * + */ + +package org.onap.portalng.bff.users; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.github.tomakehurst.wiremock.client.WireMock; +import io.restassured.http.Header; +import org.junit.jupiter.api.Test; +import org.onap.portalng.bff.BaseIntegrationTest; +import org.onap.portalng.bff.openapi.client_portal_keycloak.model.ErrorResponseKeycloakDto; +import org.onap.portalng.bff.openapi.server.model.ProblemApiDto; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; + +class DeleteUserIntegrationTest extends BaseIntegrationTest { + + @Test + void userCanBeDeleted() { + WireMock.stubFor( + WireMock.delete(WireMock.urlMatching(String.format("/auth/admin/realms/%s/users/1", realm))) + .willReturn(WireMock.aResponse().withStatus(204))); + + requestSpecification() + .given() + .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) + .when() + .delete("/users/1") + .then() + .statusCode(HttpStatus.NO_CONTENT.value()); + } + + @Test + void userCanNotBeDeleted() throws Exception { + final ErrorResponseKeycloakDto keycloakErrorResponse = + new ErrorResponseKeycloakDto().errorMessage("Some error message"); + + WireMock.stubFor( + WireMock.delete(WireMock.urlMatching(String.format("/auth/admin/realms/%s/users/1", realm))) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withStatus(400) + .withBody(objectMapper.writeValueAsString(keycloakErrorResponse)))); + + ProblemApiDto response = + requestSpecification() + .given() + .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) + .when() + .delete("/users/1") + .then() + .statusCode(HttpStatus.BAD_GATEWAY.value()) + .extract() + .body() + .as(ProblemApiDto.class); + + assertThat(response).isNotNull(); + assertThat(response.getTitle()).isEqualTo(HttpStatus.BAD_REQUEST.toString()); + assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_GATEWAY.value()); + assertThat(response.getDownstreamSystem()) + .isEqualTo(ProblemApiDto.DownstreamSystemEnum.KEYCLOAK); + } +} diff --git a/app/src/test/java/org/onap/portalng/bff/users/GetUserDetailIntegrationTest.java b/app/src/test/java/org/onap/portalng/bff/users/GetUserDetailIntegrationTest.java new file mode 100644 index 0000000..6704cbc --- /dev/null +++ b/app/src/test/java/org/onap/portalng/bff/users/GetUserDetailIntegrationTest.java @@ -0,0 +1,126 @@ +/* + * + * Copyright (c) 2022. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + * + */ + +package org.onap.portalng.bff.users; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.github.tomakehurst.wiremock.client.WireMock; +import io.restassured.http.Header; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.onap.portalng.bff.BaseIntegrationTest; +import org.onap.portalng.bff.openapi.client_portal_keycloak.model.ErrorResponseKeycloakDto; +import org.onap.portalng.bff.openapi.client_portal_keycloak.model.RoleKeycloakDto; +import org.onap.portalng.bff.openapi.client_portal_keycloak.model.UserKeycloakDto; +import org.onap.portalng.bff.openapi.server.model.ProblemApiDto; +import org.onap.portalng.bff.openapi.server.model.UserResponseApiDto; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; + +class GetUserDetailIntegrationTest extends BaseIntegrationTest { + + @Test + void detailOfUserCanBeProvided() throws Exception { + final UserKeycloakDto keycloakUser = + new UserKeycloakDto().id("1").username("user1").email("user1@localhost").enabled(true); + + WireMock.stubFor( + WireMock.get(WireMock.urlMatching(String.format("/auth/admin/realms/%s/users/1", realm))) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(objectMapper.writeValueAsString(keycloakUser)))); + + final RoleKeycloakDto keycloackRole = new RoleKeycloakDto().id(randomUUID()).name("onap_admin"); + mockAssignedRoles(keycloakUser.getId(), List.of(keycloackRole)); + + final UserResponseApiDto response = + requestSpecification() + .given() + .accept(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) + .when() + .get("/users/1") + .then() + .statusCode(HttpStatus.OK.value()) + .extract() + .body() + .as(UserResponseApiDto.class); + + assertThat(response).isNotNull(); + assertThat(response.getId()).isEqualTo("1"); + assertThat(response.getUsername()).isEqualTo("user1"); + assertThat(response.getEmail()).isEqualTo("user1@localhost"); + assertThat(response.getFirstName()).isNull(); + assertThat(response.getLastName()).isNull(); + assertThat(response.getRealmRoles()).containsExactly(keycloackRole.getName()); + } + + @Test + void detailOfNonExistentUserCanNotBeProvided() throws Exception { + + ErrorResponseKeycloakDto keycloakErrorResponse = + new ErrorResponseKeycloakDto().errorMessage("Some error message"); + + WireMock.stubFor( + WireMock.get(WireMock.urlMatching(String.format("/auth/admin/realms/%s/users/1", realm))) + .willReturn( + WireMock.aResponse() + .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .withStatus(400) + .withBody(objectMapper.writeValueAsString(keycloakErrorResponse)))); + + final ProblemApiDto response = + requestSpecification() + .given() + .accept(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) + .when() + .get("/users/1") + .then() + .statusCode(HttpStatus.BAD_GATEWAY.value()) + .extract() + .body() + .as(ProblemApiDto.class); + + assertThat(response).isNotNull(); + assertThat(response.getTitle()).isEqualTo(HttpStatus.BAD_REQUEST.toString()); + assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_GATEWAY.value()); + assertThat(response.getDownstreamSystem()) + .isEqualTo(ProblemApiDto.DownstreamSystemEnum.KEYCLOAK); + } + + protected void mockAssignedRoles(String userID, List keycloakRoles) + throws JsonProcessingException { + WireMock.stubFor( + WireMock.get( + WireMock.urlMatching( + String.format( + "/auth/admin/realms/%s/users/%s/role-mappings/realm", realm, userID))) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(objectMapper.writeValueAsString(keycloakRoles)))); + } +} diff --git a/app/src/test/java/org/onap/portalng/bff/users/ListAssignedRolesIntegrationTest.java b/app/src/test/java/org/onap/portalng/bff/users/ListAssignedRolesIntegrationTest.java new file mode 100644 index 0000000..7d05c67 --- /dev/null +++ b/app/src/test/java/org/onap/portalng/bff/users/ListAssignedRolesIntegrationTest.java @@ -0,0 +1,111 @@ +/* + * + * Copyright (c) 2022. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + * + */ + +package org.onap.portalng.bff.users; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.github.tomakehurst.wiremock.client.WireMock; +import io.restassured.http.Header; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.onap.portalng.bff.BaseIntegrationTest; +import org.onap.portalng.bff.openapi.client_portal_keycloak.model.ErrorResponseKeycloakDto; +import org.onap.portalng.bff.openapi.client_portal_keycloak.model.RoleKeycloakDto; +import org.onap.portalng.bff.openapi.server.model.ProblemApiDto; +import org.onap.portalng.bff.openapi.server.model.RoleApiDto; +import org.onap.portalng.bff.openapi.server.model.RoleListResponseApiDto; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; + +class ListAssignedRolesIntegrationTest extends BaseIntegrationTest { + + @Test + void listOfAssignedRolesCanBeProvided() throws Exception { + final RoleKeycloakDto keycloakRole1 = new RoleKeycloakDto().id("1").name("role1"); + final RoleKeycloakDto keycloakRole2 = new RoleKeycloakDto().id("2").name("role2"); + final List keycloakRoles = List.of(keycloakRole1, keycloakRole2); + + WireMock.stubFor( + WireMock.get( + WireMock.urlMatching( + String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(objectMapper.writeValueAsString(keycloakRoles)))); + + final RoleListResponseApiDto response = + requestSpecification() + .given() + .accept(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) + .when() + .get("/users/1/roles") + .then() + .statusCode(HttpStatus.OK.value()) + .extract() + .body() + .as(RoleListResponseApiDto.class); + + final RoleApiDto role1 = new RoleApiDto().id("1").name("role1"); + final RoleApiDto role2 = new RoleApiDto().id("2").name("role2"); + + assertThat(response).isNotNull(); + assertThat(response.getTotalCount()).isEqualTo(response.getItems().size()); + assertThat(response.getItems()).containsExactly(role1, role2); + } + + @Test + void listOfAssignedRolesCanNotBeProvided() throws Exception { + final ErrorResponseKeycloakDto keycloakErrorResponse = + new ErrorResponseKeycloakDto().errorMessage("Some error message"); + + WireMock.stubFor( + WireMock.get( + WireMock.urlMatching( + String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withStatus(400) + .withBody(objectMapper.writeValueAsString(keycloakErrorResponse)))); + + final ProblemApiDto response = + requestSpecification() + .given() + .accept(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) + .when() + .get("/users/1/roles") + .then() + .statusCode(HttpStatus.BAD_GATEWAY.value()) + .extract() + .body() + .as(ProblemApiDto.class); + + assertThat(response).isNotNull(); + assertThat(response.getTitle()).isEqualTo(HttpStatus.BAD_REQUEST.toString()); + assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_GATEWAY.value()); + assertThat(response.getDownstreamSystem()) + .isEqualTo(ProblemApiDto.DownstreamSystemEnum.KEYCLOAK); + } +} diff --git a/app/src/test/java/org/onap/portalng/bff/users/ListAvailableRolesIntegrationTest.java b/app/src/test/java/org/onap/portalng/bff/users/ListAvailableRolesIntegrationTest.java new file mode 100644 index 0000000..86f9ed8 --- /dev/null +++ b/app/src/test/java/org/onap/portalng/bff/users/ListAvailableRolesIntegrationTest.java @@ -0,0 +1,113 @@ +/* + * + * Copyright (c) 2022. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + * + */ + +package org.onap.portalng.bff.users; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.github.tomakehurst.wiremock.client.WireMock; +import io.restassured.http.Header; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.onap.portalng.bff.BaseIntegrationTest; +import org.onap.portalng.bff.openapi.client_portal_keycloak.model.ErrorResponseKeycloakDto; +import org.onap.portalng.bff.openapi.client_portal_keycloak.model.RoleKeycloakDto; +import org.onap.portalng.bff.openapi.server.model.ProblemApiDto; +import org.onap.portalng.bff.openapi.server.model.RoleApiDto; +import org.onap.portalng.bff.openapi.server.model.RoleListResponseApiDto; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; + +class ListAvailableRolesIntegrationTest extends BaseIntegrationTest { + + @Test + void listOfAvailableRolesCanBeProvided() throws Exception { + final RoleKeycloakDto keycloakRole1 = new RoleKeycloakDto().id("1").name("role1"); + final RoleKeycloakDto keycloakRole2 = new RoleKeycloakDto().id("2").name("role2"); + final List keycloakRoles = List.of(keycloakRole1, keycloakRole2); + + WireMock.stubFor( + WireMock.get( + WireMock.urlMatching( + String.format( + "/auth/admin/realms/%s/users/1/role-mappings/realm/available", realm))) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(objectMapper.writeValueAsString(keycloakRoles)))); + + final RoleListResponseApiDto response = + requestSpecification() + .given() + .accept(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) + .when() + .get("/users/1/roles/available") + .then() + .statusCode(HttpStatus.OK.value()) + .extract() + .body() + .as(RoleListResponseApiDto.class); + + final RoleApiDto role1 = new RoleApiDto().id("1").name("role1"); + final RoleApiDto role2 = new RoleApiDto().id("2").name("role2"); + + assertThat(response).isNotNull(); + assertThat(response.getTotalCount()).isEqualTo(response.getItems().size()); + assertThat(response.getItems()).containsExactly(role1, role2); + } + + @Test + void listOfAvailableRolesCanNotBeProvided() throws Exception { + final ErrorResponseKeycloakDto keycloakErrorResponse = + new ErrorResponseKeycloakDto().errorMessage("Some error message"); + + WireMock.stubFor( + WireMock.get( + WireMock.urlMatching( + String.format( + "/auth/admin/realms/%s/users/1/role-mappings/realm/available", realm))) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withStatus(400) + .withBody(objectMapper.writeValueAsString(keycloakErrorResponse)))); + + ProblemApiDto response = + requestSpecification() + .given() + .accept(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) + .when() + .get("/users/1/roles/available") + .then() + .statusCode(HttpStatus.BAD_GATEWAY.value()) + .extract() + .body() + .as(ProblemApiDto.class); + + assertThat(response).isNotNull(); + assertThat(response.getTitle()).isEqualTo(HttpStatus.BAD_REQUEST.toString()); + assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_GATEWAY.value()); + assertThat(response.getDownstreamSystem()) + .isEqualTo(ProblemApiDto.DownstreamSystemEnum.KEYCLOAK); + } +} diff --git a/app/src/test/java/org/onap/portalng/bff/users/ListUsersIntegrationTest.java b/app/src/test/java/org/onap/portalng/bff/users/ListUsersIntegrationTest.java new file mode 100644 index 0000000..27a8ecd --- /dev/null +++ b/app/src/test/java/org/onap/portalng/bff/users/ListUsersIntegrationTest.java @@ -0,0 +1,238 @@ +/* + * + * Copyright (c) 2022. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + * + */ + +package org.onap.portalng.bff.users; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.github.tomakehurst.wiremock.client.WireMock; +import io.restassured.http.Header; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.Test; +import org.onap.portalng.bff.BaseIntegrationTest; +import org.onap.portalng.bff.openapi.client_portal_keycloak.model.ErrorResponseKeycloakDto; +import org.onap.portalng.bff.openapi.client_portal_keycloak.model.RoleKeycloakDto; +import org.onap.portalng.bff.openapi.client_portal_keycloak.model.UserKeycloakDto; +import org.onap.portalng.bff.openapi.server.model.ProblemApiDto; +import org.onap.portalng.bff.openapi.server.model.UserListResponseApiDto; +import org.onap.portalng.bff.openapi.server.model.UserResponseApiDto; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; + +class ListUsersIntegrationTest extends BaseIntegrationTest { + private final RoleKeycloakDto ONAP_ADMIN = + new RoleKeycloakDto().id(randomUUID()).name("onap_admin"); + private final RoleKeycloakDto OFFLINE_ACCESS = + new RoleKeycloakDto().id(randomUUID()).name("offline_access"); + + @Test + void listOfUsersWithDefaultPaginationCanBeProvided() throws Exception { + final UserKeycloakDto tAdmin = + new UserKeycloakDto() + .id("8f05caaf-0e36-4bcd-b9b3-0ae3d531acc2") + .username("t-admin") + .email("t-admin@example.xyz") + .firstName("FirstName4t-admin") + .lastName("LastName4t-admin") + .enabled(true); + + final UserKeycloakDto tDesigner = + new UserKeycloakDto() + .id("04ed5525-740d-42da-bc4c-2d3fcf955ee9") + .username("t-designer") + .email("t-designer@example.xyz") + .firstName("FirstName4t-designer") + .lastName("LastName4t-designer") + .enabled(true); + + mockGetUserCount(2); + mockListUsers(List.of(tAdmin, tDesigner), 0, 10); + mockListRealmRoles(List.of(ONAP_ADMIN, OFFLINE_ACCESS)); + mockListRoleUsers(OFFLINE_ACCESS.getName(), List.of(tAdmin, tDesigner)); + mockListRoleUsers(ONAP_ADMIN.getName(), List.of(tAdmin)); + + final UserResponseApiDto expectedTAdmin = + new UserResponseApiDto() + .id("8f05caaf-0e36-4bcd-b9b3-0ae3d531acc2") + .username("t-admin") + .email("t-admin@example.xyz") + .firstName("FirstName4t-admin") + .lastName("LastName4t-admin") + .enabled(true) + .addRealmRolesItem("onap_admin") + .addRealmRolesItem("offline_access"); + final UserResponseApiDto expectedTDesigner = + new UserResponseApiDto() + .id("04ed5525-740d-42da-bc4c-2d3fcf955ee9") + .username("t-designer") + .email("t-designer@example.xyz") + .firstName("FirstName4t-designer") + .lastName("LastName4t-designer") + .enabled(true) + .addRealmRolesItem("offline_access"); + + final UserListResponseApiDto response = listUsers(); + assertThat(response).isNotNull(); + assertThat(response.getTotalCount()).isEqualTo(2); + assertThat(response.getItems().get(0).getRealmRoles()) + .containsExactlyInAnyOrder( + expectedTAdmin.getRealmRoles().get(0), expectedTAdmin.getRealmRoles().get(1)); + assertThat(response.getItems().get(1).getRealmRoles()) + .containsExactly(expectedTDesigner.getRealmRoles().get(0)); + } + + @Test + void listOfUsersWithSpecifiedPaginationCanBeProvided() throws Exception { + final UserKeycloakDto keycloakUser = + new UserKeycloakDto() + .id("1") + .username("user1") + .email("user1@localhost") + .firstName("User1") + .lastName("Test") + .enabled(true); + + mockGetUserCount(1); + mockListUsers(List.of(keycloakUser), 60, 30); + mockListRealmRoles(Collections.emptyList()); + + final UserListResponseApiDto response = listUsers(Optional.of(3), Optional.of(30)); + assertThat(response).isNotNull(); + assertThat(response.getTotalCount()).isEqualTo(1); + assertThat(response.getItems()) + .containsExactly( + new UserResponseApiDto() + .id("1") + .username("user1") + .enabled(true) + .email("user1@localhost") + .firstName("User1") + .lastName("Test") + .realmRoles(java.util.List.of())); + } + + @Test + void listOfUsersWithSpecifiedPaginationCanNotBeProvided() throws Exception { + final ErrorResponseKeycloakDto keycloakErrorResponse = + new ErrorResponseKeycloakDto().errorMessage("Some error message"); + + mockGetUserCount(55); + mockListUsersWithProblems(keycloakErrorResponse, 60, 30); + mockListRealmRoles(Collections.emptyList()); + + ProblemApiDto response = + requestSpecification() + .given() + .accept(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) + .when() + .get(adjustPath("/users", Optional.of(3), Optional.of(30))) + .then() + .statusCode(HttpStatus.BAD_GATEWAY.value()) + .extract() + .body() + .as(ProblemApiDto.class); + + assertThat(response).isNotNull(); + assertThat(response.getTitle()).isEqualTo(HttpStatus.BAD_REQUEST.toString()); + assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_GATEWAY.value()); + assertThat(response.getDownstreamSystem()) + .isEqualTo(ProblemApiDto.DownstreamSystemEnum.KEYCLOAK); + } + + protected void mockGetUserCount(Integer userCount) { + WireMock.stubFor( + WireMock.get( + WireMock.urlMatching(String.format("/auth/admin/realms/%s/users/count", realm))) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(userCount.toString()))); + } + + protected void mockListUsers(List keycloakUsers, Integer first, Integer max) + throws Exception { + WireMock.stubFor( + WireMock.get( + WireMock.urlMatching( + String.format( + "/auth/admin/realms/%s/users\\?first=%s&max=%s", realm, first, max))) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(objectMapper.writeValueAsString(keycloakUsers)))); + } + + protected void mockListRealmRoles(List roles) throws Exception { + WireMock.stubFor( + WireMock.get(WireMock.urlMatching(String.format("/auth/admin/realms/%s/roles", realm))) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(objectMapper.writeValueAsString(roles)))); + } + + protected void mockListRoleUsers(String roleName, List response) + throws Exception { + WireMock.stubFor( + WireMock.get( + WireMock.urlMatching( + String.format("/auth/admin/realms/%s/roles/%s/users", realm, roleName))) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(objectMapper.writeValueAsString(response)))); + } + + protected UserListResponseApiDto listUsers() { + return listUsers(Optional.empty(), Optional.empty()); + } + + protected UserListResponseApiDto listUsers(Optional page, Optional pageSize) { + return requestSpecification() + .given() + .accept(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) + .when() + .get(adjustPath("/users", page, pageSize)) + .then() + .statusCode(HttpStatus.OK.value()) + .extract() + .body() + .as(UserListResponseApiDto.class); + } + + protected void mockListUsersWithProblems( + ErrorResponseKeycloakDto keycloakErrorResponse, Integer first, Integer max) throws Exception { + WireMock.stubFor( + WireMock.get( + WireMock.urlMatching( + String.format( + "/auth/admin/realms/%s/users\\?first=%s&max=%s", realm, first, max))) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withStatus(400) + .withBody(objectMapper.writeValueAsString(keycloakErrorResponse)))); + } +} diff --git a/app/src/test/java/org/onap/portalng/bff/users/UpdateAssignedRolesIntegrationTest.java b/app/src/test/java/org/onap/portalng/bff/users/UpdateAssignedRolesIntegrationTest.java new file mode 100644 index 0000000..a1a5ee3 --- /dev/null +++ b/app/src/test/java/org/onap/portalng/bff/users/UpdateAssignedRolesIntegrationTest.java @@ -0,0 +1,453 @@ +/* + * + * Copyright (c) 2022. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + * + */ + +package org.onap.portalng.bff.users; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.github.tomakehurst.wiremock.client.WireMock; +import com.github.tomakehurst.wiremock.stubbing.Scenario; +import io.restassured.http.Header; +import java.util.Collections; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.onap.portalng.bff.BaseIntegrationTest; +import org.onap.portalng.bff.openapi.client_portal_keycloak.model.ErrorResponseKeycloakDto; +import org.onap.portalng.bff.openapi.client_portal_keycloak.model.RoleKeycloakDto; +import org.onap.portalng.bff.openapi.server.model.ProblemApiDto; +import org.onap.portalng.bff.openapi.server.model.RoleApiDto; +import org.onap.portalng.bff.openapi.server.model.RoleListResponseApiDto; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; + +class UpdateAssignedRolesIntegrationTest extends BaseIntegrationTest { + + @Test + void listOfAssignedRolesCanBeUpdatedWhenPreviousAssignedRolesAreEmpty() throws Exception { + final RoleKeycloakDto keycloakRole1 = new RoleKeycloakDto().id("1").name("role1"); + final RoleKeycloakDto keycloakRole2 = new RoleKeycloakDto().id("2").name("role2"); + + final List keycloakAvailableRoles = List.of(keycloakRole1, keycloakRole2); + final List keycloakInitialAssignedRoles = List.of(); + final List keycloakUpdatedAssignedRoles = List.of(keycloakRole1); + + final List keycloakRolesToAdd = List.of(keycloakRole1); + + WireMock.stubFor( + WireMock.get( + WireMock.urlMatching( + String.format( + "/auth/admin/realms/%s/users/1/role-mappings/realm/available", realm))) + .inScenario("test") + .whenScenarioStateIs(Scenario.STARTED) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(objectMapper.writeValueAsString(keycloakAvailableRoles)))); + + WireMock.stubFor( + WireMock.get( + WireMock.urlMatching( + String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) + .inScenario("test") + .whenScenarioStateIs(Scenario.STARTED) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(objectMapper.writeValueAsString(keycloakInitialAssignedRoles)))); + + WireMock.stubFor( + WireMock.post( + WireMock.urlMatching( + String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) + .inScenario("test") + .whenScenarioStateIs(Scenario.STARTED) + .withRequestBody(WireMock.equalTo(objectMapper.writeValueAsString(keycloakRolesToAdd))) + .willReturn(WireMock.aResponse().withStatus(HttpStatus.NO_CONTENT.value())) + .willSetStateTo("rolesUpdated")); + + WireMock.stubFor( + WireMock.get( + WireMock.urlMatching( + String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) + .inScenario("test") + .whenScenarioStateIs("rolesUpdated") + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(objectMapper.writeValueAsString(keycloakUpdatedAssignedRoles)))); + + final RoleApiDto roleToAssign = new RoleApiDto().id("1").name("role1"); + final List rolesToAssign = List.of(roleToAssign); + + final RoleListResponseApiDto response = + requestSpecification() + .given() + .accept(MediaType.APPLICATION_JSON_VALUE) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) + .body(rolesToAssign) + .when() + .put("/users/1/roles") + .then() + .statusCode(HttpStatus.OK.value()) + .extract() + .body() + .as(RoleListResponseApiDto.class); + + final RoleApiDto role = new RoleApiDto().id("1").name("role1"); + + assertThat(response).isNotNull(); + assertThat(response.getTotalCount()).isEqualTo(response.getItems().size()); + assertThat(response.getItems()).containsExactly(role); + } + + @Test + void listOfAssignedRolesCanBeUpdatedWhenPreviousAssignedRolesAreNotEmpty() throws Exception { + final RoleKeycloakDto keycloakRole1 = new RoleKeycloakDto().id("1").name("role1"); + final RoleKeycloakDto keycloakRole2 = new RoleKeycloakDto().id("2").name("role2"); + final RoleKeycloakDto keycloakRole3 = new RoleKeycloakDto().id("3").name("role3"); + + final List keycloakAvailableRoles = + List.of(keycloakRole1, keycloakRole2, keycloakRole3); + final List keycloakInitialAssignedRoles = + List.of(keycloakRole1, keycloakRole2); + final List keycloakUpdatedAssignedRoles = List.of(keycloakRole1); + + final List keycloakRolesToRemove = List.of(keycloakRole1, keycloakRole2); + final List keycloakRolesToAdd = List.of(keycloakRole1); + + WireMock.stubFor( + WireMock.get( + WireMock.urlMatching( + String.format( + "/auth/admin/realms/%s/users/1/role-mappings/realm/available", realm))) + .inScenario("test") + .whenScenarioStateIs(Scenario.STARTED) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(objectMapper.writeValueAsString(keycloakAvailableRoles)))); + + WireMock.stubFor( + WireMock.get( + WireMock.urlMatching( + String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) + .inScenario("test") + .whenScenarioStateIs(Scenario.STARTED) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(objectMapper.writeValueAsString(keycloakInitialAssignedRoles)))); + + WireMock.stubFor( + WireMock.delete( + WireMock.urlMatching( + String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) + .inScenario("test") + .whenScenarioStateIs(Scenario.STARTED) + .withRequestBody( + WireMock.equalTo(objectMapper.writeValueAsString(keycloakRolesToRemove))) + .willReturn(WireMock.aResponse().withStatus(HttpStatus.NO_CONTENT.value()))); + + WireMock.stubFor( + WireMock.post( + WireMock.urlMatching( + String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) + .inScenario("test") + .whenScenarioStateIs(Scenario.STARTED) + .withRequestBody(WireMock.equalTo(objectMapper.writeValueAsString(keycloakRolesToAdd))) + .willReturn(WireMock.aResponse().withStatus(HttpStatus.NO_CONTENT.value())) + .willSetStateTo("rolesUpdated")); + + WireMock.stubFor( + WireMock.get( + WireMock.urlMatching( + String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) + .inScenario("test") + .whenScenarioStateIs("rolesUpdated") + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(objectMapper.writeValueAsString(keycloakUpdatedAssignedRoles)))); + + final RoleApiDto roleToAssign = new RoleApiDto().id("1").name("role1"); + final List rolesToAssign = List.of(roleToAssign); + + final RoleListResponseApiDto response = + requestSpecification() + .given() + .accept(MediaType.APPLICATION_JSON_VALUE) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) + .body(rolesToAssign) + .when() + .put("/users/1/roles") + .then() + .statusCode(HttpStatus.OK.value()) + .extract() + .body() + .as(RoleListResponseApiDto.class); + + final RoleApiDto role = new RoleApiDto().id("1").name("role1"); + + assertThat(response).isNotNull(); + assertThat(response.getTotalCount()).isEqualTo(response.getItems().size()); + assertThat(response.getItems()).containsExactly(role); + } + + @Test + void listOfAssignedRolesCanBeCleared() throws Exception { + final RoleKeycloakDto keycloakRole1 = new RoleKeycloakDto().id("1").name("role1"); + final RoleKeycloakDto keycloakRole2 = new RoleKeycloakDto().id("2").name("role2"); + + final List keycloakAvailableRoles = List.of(keycloakRole1, keycloakRole2); + final List keycloakAssignedRoles = Collections.emptyList(); + final List keycloakRolesToRemove = List.of(keycloakRole1, keycloakRole2); + + WireMock.stubFor( + WireMock.get( + WireMock.urlMatching( + String.format( + "/auth/admin/realms/%s/users/1/role-mappings/realm/available", realm))) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(objectMapper.writeValueAsString(keycloakAvailableRoles)))); + + WireMock.stubFor( + WireMock.delete( + WireMock.urlMatching( + String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) + .withRequestBody( + WireMock.equalTo(objectMapper.writeValueAsString(keycloakRolesToRemove))) + .willReturn(WireMock.aResponse().withStatus(HttpStatus.NO_CONTENT.value()))); + + WireMock.stubFor( + WireMock.get( + WireMock.urlMatching( + String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(objectMapper.writeValueAsString(keycloakAssignedRoles)))); + + final List rolesToAssign = Collections.emptyList(); + + final RoleListResponseApiDto response = + requestSpecification() + .given() + .accept(MediaType.APPLICATION_JSON_VALUE) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) + .body(rolesToAssign) + .when() + .put("/users/1/roles") + .then() + .statusCode(HttpStatus.OK.value()) + .extract() + .body() + .as(RoleListResponseApiDto.class); + + assertThat(response).isNotNull(); + assertThat(response.getTotalCount()).isEqualTo(response.getItems().size()); + assertThat(response.getItems()).isEmpty(); + } + + @Test + void listOfAssignedRolesCanNotBeUpdatedWhenPreviousAssignedRolesAreEmpty() throws Exception { + final ErrorResponseKeycloakDto keycloakErrorResponse = + new ErrorResponseKeycloakDto().errorMessage("Some error message"); + + final RoleKeycloakDto keycloakRole1 = new RoleKeycloakDto().id("1").name("role1"); + final RoleKeycloakDto keycloakRole2 = new RoleKeycloakDto().id("2").name("role2"); + + final List keycloakAvailableRoles = List.of(keycloakRole1, keycloakRole2); + final List keycloakInitialAssignedRoles = List.of(); + + final List keycloakRolesToAdd = List.of(keycloakRole1); + + WireMock.stubFor( + WireMock.get( + WireMock.urlMatching( + String.format( + "/auth/admin/realms/%s/users/1/role-mappings/realm/available", realm))) + .inScenario("test") + .whenScenarioStateIs(Scenario.STARTED) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(objectMapper.writeValueAsString(keycloakAvailableRoles)))); + + WireMock.stubFor( + WireMock.get( + WireMock.urlMatching( + String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) + .inScenario("test") + .whenScenarioStateIs(Scenario.STARTED) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(objectMapper.writeValueAsString(keycloakInitialAssignedRoles)))); + + WireMock.stubFor( + WireMock.post( + WireMock.urlMatching( + String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) + .inScenario("test") + .whenScenarioStateIs(Scenario.STARTED) + .withRequestBody(WireMock.equalTo(objectMapper.writeValueAsString(keycloakRolesToAdd))) + .willReturn(WireMock.aResponse().withStatus(HttpStatus.NO_CONTENT.value())) + .willSetStateTo("rolesUpdated")); + + WireMock.stubFor( + WireMock.get( + WireMock.urlMatching( + String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) + .inScenario("test") + .whenScenarioStateIs("rolesUpdated") + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withStatus(400) + .withBody(objectMapper.writeValueAsString(keycloakErrorResponse)))); + + final RoleApiDto roleToAssign = new RoleApiDto().id("1").name("role1"); + final List rolesToAssign = List.of(roleToAssign); + + ProblemApiDto response = + requestSpecification() + .given() + .accept(MediaType.APPLICATION_JSON_VALUE) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) + .body(rolesToAssign) + .when() + .put("/users/1/roles") + .then() + .statusCode(HttpStatus.BAD_GATEWAY.value()) + .extract() + .body() + .as(ProblemApiDto.class); + + assertThat(response).isNotNull(); + assertThat(response.getTitle()).isEqualTo(HttpStatus.BAD_REQUEST.toString()); + assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_GATEWAY.value()); + assertThat(response.getDownstreamSystem()) + .isEqualTo(ProblemApiDto.DownstreamSystemEnum.KEYCLOAK); + } + + @Test + void listOfAssignedRolesCanNotBeUpdatedWhenPreviousAssignedRolesAreNotEmpty() throws Exception { + final ErrorResponseKeycloakDto keycloakErrorResponse = + new ErrorResponseKeycloakDto().errorMessage("Some error message"); + + final RoleKeycloakDto keycloakRole1 = new RoleKeycloakDto().id("1").name("role1"); + final RoleKeycloakDto keycloakRole2 = new RoleKeycloakDto().id("2").name("role2"); + final RoleKeycloakDto keycloakRole3 = new RoleKeycloakDto().id("3").name("role3"); + + final List keycloakAvailableRoles = + List.of(keycloakRole1, keycloakRole2, keycloakRole3); + final List keycloakUpdatedAssignedRoles = List.of(keycloakRole1); + + final List keycloakRolesToRemove = List.of(keycloakRole1, keycloakRole2); + final List keycloakRolesToAdd = List.of(keycloakRole1); + + WireMock.stubFor( + WireMock.get( + WireMock.urlMatching( + String.format( + "/auth/admin/realms/%s/users/1/role-mappings/realm/available", realm))) + .inScenario("test") + .whenScenarioStateIs(Scenario.STARTED) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(objectMapper.writeValueAsString(keycloakAvailableRoles)))); + + WireMock.stubFor( + WireMock.get( + WireMock.urlMatching( + String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) + .inScenario("test") + .whenScenarioStateIs(Scenario.STARTED) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withStatus(400) + .withBody(objectMapper.writeValueAsString(keycloakErrorResponse)))); + + WireMock.stubFor( + WireMock.delete( + WireMock.urlMatching( + String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) + .inScenario("test") + .whenScenarioStateIs(Scenario.STARTED) + .withRequestBody( + WireMock.equalTo(objectMapper.writeValueAsString(keycloakRolesToRemove))) + .willReturn(WireMock.aResponse().withStatus(HttpStatus.NO_CONTENT.value()))); + + WireMock.stubFor( + WireMock.post( + WireMock.urlMatching( + String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) + .inScenario("test") + .whenScenarioStateIs(Scenario.STARTED) + .withRequestBody(WireMock.equalTo(objectMapper.writeValueAsString(keycloakRolesToAdd))) + .willReturn(WireMock.aResponse().withStatus(HttpStatus.NO_CONTENT.value())) + .willSetStateTo("rolesUpdated")); + + WireMock.stubFor( + WireMock.get( + WireMock.urlMatching( + String.format("/auth/admin/realms/%s/users/1/role-mappings/realm", realm))) + .inScenario("test") + .whenScenarioStateIs("rolesUpdated") + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(objectMapper.writeValueAsString(keycloakUpdatedAssignedRoles)))); + + final RoleApiDto roleToAssign = new RoleApiDto().id("1").name("role1"); + final List rolesToAssign = List.of(roleToAssign); + + final ProblemApiDto response = + requestSpecification() + .given() + .accept(MediaType.APPLICATION_JSON_VALUE) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) + .body(rolesToAssign) + .when() + .put("/users/1/roles") + .then() + .statusCode(HttpStatus.BAD_GATEWAY.value()) + .extract() + .body() + .as(ProblemApiDto.class); + + assertThat(response).isNotNull(); + assertThat(response.getTitle()).isEqualTo(HttpStatus.BAD_REQUEST.toString()); + assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_GATEWAY.value()); + assertThat(response.getDownstreamSystem()) + .isEqualTo(ProblemApiDto.DownstreamSystemEnum.KEYCLOAK); + } +} diff --git a/app/src/test/java/org/onap/portalng/bff/users/UpdateUserIntegrationTest.java b/app/src/test/java/org/onap/portalng/bff/users/UpdateUserIntegrationTest.java new file mode 100644 index 0000000..f181c5e --- /dev/null +++ b/app/src/test/java/org/onap/portalng/bff/users/UpdateUserIntegrationTest.java @@ -0,0 +1,134 @@ +/* + * + * Copyright (c) 2022. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + * + */ + +package org.onap.portalng.bff.users; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.github.tomakehurst.wiremock.client.WireMock; +import io.restassured.http.Header; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.onap.portalng.bff.BaseIntegrationTest; +import org.onap.portalng.bff.openapi.client_portal_keycloak.model.ErrorResponseKeycloakDto; +import org.onap.portalng.bff.openapi.client_portal_keycloak.model.RoleKeycloakDto; +import org.onap.portalng.bff.openapi.client_portal_keycloak.model.UserKeycloakDto; +import org.onap.portalng.bff.openapi.server.model.ProblemApiDto; +import org.onap.portalng.bff.openapi.server.model.UpdateUserRequestApiDto; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; + +class UpdateUserIntegrationTest extends BaseIntegrationTest { + + @Test + void userCanBeUpdated() throws Exception { + final UserKeycloakDto keycloakRequest = new UserKeycloakDto().firstName("User1").enabled(false); + mockUpdateUser(keycloakRequest, "1"); + + final UpdateUserRequestApiDto request = + new UpdateUserRequestApiDto().email(null).firstName("User1").lastName(null).enabled(false); + + requestSpecification() + .given() + .contentType(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) + .body(request) + .when() + .put("/users/1") + .then() + .statusCode(HttpStatus.OK.value()); + } + + @Test + void userCanNotBeUpdated() throws Exception { + final ErrorResponseKeycloakDto keycloakErrorResponse = + new ErrorResponseKeycloakDto().errorMessage("Some error message"); + + final UserKeycloakDto keycloakRequest = new UserKeycloakDto().firstName("User1").enabled(false); + + WireMock.stubFor( + WireMock.put(WireMock.urlMatching(String.format("/auth/admin/realms/%s/users/1", realm))) + .withRequestBody(WireMock.equalTo(objectMapper.writeValueAsString(keycloakRequest))) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withStatus(400) + .withBody(objectMapper.writeValueAsString(keycloakErrorResponse)))); + + final UpdateUserRequestApiDto request = + new UpdateUserRequestApiDto().email(null).firstName("User1").lastName(null).enabled(false); + + final ProblemApiDto response = + requestSpecification() + .given() + .contentType(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) + .body(request) + .when() + .put("/users/1") + .then() + .statusCode(HttpStatus.BAD_GATEWAY.value()) + .extract() + .body() + .as(ProblemApiDto.class); + + assertThat(response).isNotNull(); + assertThat(response.getTitle()).isEqualTo(HttpStatus.BAD_REQUEST.toString()); + assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_GATEWAY.value()); + assertThat(response.getDownstreamSystem()) + .isEqualTo(ProblemApiDto.DownstreamSystemEnum.KEYCLOAK); + } + + protected void mockUpdateUser(UserKeycloakDto request, String userId) throws Exception { + WireMock.stubFor( + WireMock.put( + WireMock.urlMatching( + String.format("/auth/admin/realms/%s/users/%s", realm, userId))) + .withRequestBody(WireMock.equalTo(objectMapper.writeValueAsString(request))) + .willReturn( + WireMock.aResponse().withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE))); + } + + protected void mockGetUser(String userId, UserKeycloakDto response) throws Exception { + WireMock.stubFor( + WireMock.get( + WireMock.urlMatching( + String.format("/auth/admin/realms/%s/users/%s", realm, userId))) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(objectMapper.writeValueAsString(response)))); + } + + protected void mockAssignedRoles(String userID, List keycloakRoles) + throws JsonProcessingException { + WireMock.stubFor( + WireMock.get( + WireMock.urlMatching( + String.format( + "/auth/admin/realms/%s/users/%s/role-mappings/realm", realm, userID))) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(objectMapper.writeValueAsString(keycloakRoles)))); + } +} diff --git a/app/src/test/java/org/onap/portalng/bff/users/UpdateUserPasswordIntegrationTest.java b/app/src/test/java/org/onap/portalng/bff/users/UpdateUserPasswordIntegrationTest.java new file mode 100644 index 0000000..0bdaaa9 --- /dev/null +++ b/app/src/test/java/org/onap/portalng/bff/users/UpdateUserPasswordIntegrationTest.java @@ -0,0 +1,107 @@ +/* + * + * Copyright (c) 2022. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + * + */ + +package org.onap.portalng.bff.users; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.github.tomakehurst.wiremock.client.WireMock; +import io.restassured.http.Header; +import org.junit.jupiter.api.Test; +import org.onap.portalng.bff.BaseIntegrationTest; +import org.onap.portalng.bff.openapi.client_portal_keycloak.model.CredentialKeycloakDto; +import org.onap.portalng.bff.openapi.client_portal_keycloak.model.ErrorResponseKeycloakDto; +import org.onap.portalng.bff.openapi.server.model.ProblemApiDto; +import org.onap.portalng.bff.openapi.server.model.UpdateUserPasswordRequestApiDto; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; + +class UpdateUserPasswordIntegrationTest extends BaseIntegrationTest { + + @Test + void userPasswordCanBeUpdated() throws Exception { + final CredentialKeycloakDto keycloakRequest = + new CredentialKeycloakDto().temporary(true).value("pswd"); + + WireMock.stubFor( + WireMock.put( + WireMock.urlMatching( + String.format("/auth/admin/realms/%s/users/1/reset-password", realm))) + .withRequestBody(WireMock.equalTo(objectMapper.writeValueAsString(keycloakRequest))) + .willReturn(WireMock.aResponse().withStatus(204))); + + final UpdateUserPasswordRequestApiDto request = + new UpdateUserPasswordRequestApiDto().temporary(true).value("pswd"); + + requestSpecification() + .given() + .contentType(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) + .body(request) + .when() + .put("/users/1/password") + .then() + .statusCode(HttpStatus.NO_CONTENT.value()); + } + + @Test + void userPasswordCanNotBeUpdated() throws Exception { + final ErrorResponseKeycloakDto keycloakErrorResponse = + new ErrorResponseKeycloakDto().errorMessage("Some error message"); + + final CredentialKeycloakDto keycloakRequest = + new CredentialKeycloakDto().temporary(true).value("pswd"); + + WireMock.stubFor( + WireMock.put( + WireMock.urlMatching( + String.format("/auth/admin/realms/%s/users/1/reset-password", realm))) + .withRequestBody(WireMock.equalTo(objectMapper.writeValueAsString(keycloakRequest))) + .willReturn( + WireMock.aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withStatus(400) + .withBody(objectMapper.writeValueAsString(keycloakErrorResponse)))); + + final UpdateUserPasswordRequestApiDto request = + new UpdateUserPasswordRequestApiDto().temporary(true).value("pswd"); + + final ProblemApiDto response = + requestSpecification() + .given() + .contentType(MediaType.APPLICATION_JSON_VALUE) + .header(new Header("X-Request-Id", "addf6005-3075-4c80-b7bc-2c70b7d42b57")) + .body(request) + .when() + .put("/users/1/password") + .then() + .statusCode(HttpStatus.BAD_GATEWAY.value()) + .extract() + .body() + .as(ProblemApiDto.class); + + assertThat(response).isNotNull(); + assertThat(response.getTitle()).isEqualTo(HttpStatus.BAD_REQUEST.toString()); + assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_GATEWAY.value()); + assertThat(response.getDownstreamSystem()) + .isEqualTo(ProblemApiDto.DownstreamSystemEnum.KEYCLOAK); + } +} diff --git a/app/src/test/resources/application-access-control.yml b/app/src/test/resources/application-access-control.yml index 5454a15..1eb37b8 100644 --- a/app/src/test/resources/application-access-control.yml +++ b/app/src/test/resources/application-access-control.yml @@ -1,4 +1,4 @@ -portal-bff.access-control: +bff.access-control: ACTIONS_CREATE: [ onap_admin, onap_designer, onap_operator ] ACTIONS_GET: [ onap_admin, onap_designer, onap_operator ] ACTIONS_LIST: [ onap_admin, onap_designer, onap_operator ] diff --git a/app/src/test/resources/application-development.yml b/app/src/test/resources/application-development.yml index 8e97b45..2f408fe 100644 --- a/app/src/test/resources/application-development.yml +++ b/app/src/test/resources/application-development.yml @@ -25,7 +25,7 @@ spring: serialization: FAIL_ON_EMPTY_BEANS: false -portal-bff: +bff: realm: ONAP portal-prefs-url: http://localhost:${wiremock.server.port} portal-history-url: http://localhost:${wiremock.server.port} diff --git a/app/src/test/resources/application.yml b/app/src/test/resources/application.yml index f9a82d8..b26e5d4 100644 --- a/app/src/test/resources/application.yml +++ b/app/src/test/resources/application.yml @@ -26,7 +26,7 @@ spring: serialization: FAIL_ON_EMPTY_BEANS: false -portal-bff: +bff: realm: ONAP portal-prefs-url: http://localhost:${wiremock.server.port} portal-history-url: http://localhost:${wiremock.server.port} -- cgit 1.2.3-korg