diff --git a/pom.xml b/pom.xml index 671267d..3ae722e 100644 --- a/pom.xml +++ b/pom.xml @@ -36,7 +36,7 @@ tkit-quarkus-rest - io.github.onecx.quarkus onecx-tenant @@ -48,7 +48,7 @@ org.tkit.quarkus.lib tkit-quarkus-rest-context - --> + @@ -100,11 +100,6 @@ quarkus-opentelemetry - - org.tkit.quarkus.lib - tkit-quarkus-rest-context - - org.projectlombok diff --git a/src/main/java/io/github/onecx/user/profile/domain/models/Image.java b/src/main/java/io/github/onecx/user/profile/domain/models/Image.java index 82d72db..53cb75f 100644 --- a/src/main/java/io/github/onecx/user/profile/domain/models/Image.java +++ b/src/main/java/io/github/onecx/user/profile/domain/models/Image.java @@ -2,6 +2,7 @@ import jakarta.persistence.*; +import org.hibernate.annotations.TenantId; import org.tkit.quarkus.jpa.models.TraceableEntity; import lombok.Getter; @@ -13,6 +14,7 @@ @Setter public class Image extends TraceableEntity { + @TenantId @Column(name = "TENANT_ID") private String tenantId; diff --git a/src/main/java/io/github/onecx/user/profile/domain/models/Preference.java b/src/main/java/io/github/onecx/user/profile/domain/models/Preference.java index c23db96..d255c85 100644 --- a/src/main/java/io/github/onecx/user/profile/domain/models/Preference.java +++ b/src/main/java/io/github/onecx/user/profile/domain/models/Preference.java @@ -2,6 +2,7 @@ import jakarta.persistence.*; +import org.hibernate.annotations.TenantId; import org.tkit.quarkus.jpa.models.TraceableEntity; import lombok.Getter; @@ -25,6 +26,7 @@ public class Preference extends TraceableEntity { @Column(name = "APPLICATION_ID") private String applicationId; + @TenantId @Column(name = "TENANT_ID") private String tenantId; diff --git a/src/main/java/io/github/onecx/user/profile/domain/models/UserProfile.java b/src/main/java/io/github/onecx/user/profile/domain/models/UserProfile.java index 4ce46b4..1a4ed1e 100644 --- a/src/main/java/io/github/onecx/user/profile/domain/models/UserProfile.java +++ b/src/main/java/io/github/onecx/user/profile/domain/models/UserProfile.java @@ -2,6 +2,7 @@ import jakarta.persistence.*; +import org.hibernate.annotations.TenantId; import org.tkit.quarkus.jpa.models.TraceableEntity; import lombok.Getter; @@ -41,6 +42,7 @@ public class UserProfile extends TraceableEntity { @Column(name = "USER_ID") private String userId; + @TenantId @Column(name = "TENANT_ID") private String tenantId; diff --git a/src/main/java/io/github/onecx/user/profile/rs/external/v1/controllers/AvatarV1RestController.java b/src/main/java/io/github/onecx/user/profile/rs/external/v1/controllers/AvatarV1RestController.java index d2cda53..75a1f08 100644 --- a/src/main/java/io/github/onecx/user/profile/rs/external/v1/controllers/AvatarV1RestController.java +++ b/src/main/java/io/github/onecx/user/profile/rs/external/v1/controllers/AvatarV1RestController.java @@ -116,6 +116,10 @@ public Response uploadAvatar(File body) { var userProfile = userProfileDAO.getUserProfileByUserId(ApplicationContext.get().getPrincipal(), UserProfile.ENTITY_GRAPH_LOAD_ALL); + if (userProfile == null) { + return Response.status(Response.Status.NOT_FOUND).build(); + } + try { byte[] avatarBytes = Files.readAllBytes(body.toPath()); InputStream avatarIs = new ByteArrayInputStream(avatarBytes); diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index ff69b79..1e0da24 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -5,13 +5,13 @@ quarkus.datasource.jdbc.min-size=10 quarkus.banner.enabled=false quarkus.hibernate-orm.database.generation=validate -#quarkus.hibernate-orm.multitenant=DISCRIMINATOR +quarkus.hibernate-orm.multitenant=DISCRIMINATOR quarkus.liquibase.migrate-at-start=true quarkus.liquibase.validate-on-migrate=true tkit.log.json.enabled=true # enable or disable multi-tenancy support -#tkit.rs.context.tenant-id.enabled=true +tkit.rs.context.tenant-id.enabled=true # DEV %dev.tkit.log.json.enabled=false @@ -19,26 +19,26 @@ tkit.log.json.enabled=true # TEST %test.tkit.log.json.enabled=false # Enable mocking for tenant service -#%test.tkit.jpa.tenant.default=tenant-100 -#%test.tkit.rs.context.tenant-id.mock.enabled=true -#%test.tkit.rs.context.tenant-id.mock.default-tenant=tenant-100 +%test.tkit.jpa.tenant.default=tenant-100 +%test.tkit.rs.context.tenant-id.mock.enabled=true +%test.tkit.rs.context.tenant-id.mock.default-tenant=tenant-100 %test.tkit.rs.context.tenant-id.mock.claim-org-id=orgId %test.tkit.rs.context.tenant-id.mock.token-header-param=apm-principal-token -#%test.tkit.rs.context.tenant-id.mock.data.org1=tenant-100 -#%test.tkit.rs.context.tenant-id.mock.data.org2=tenant-200 -#%test.tkit.rs.context.tenant-id.mock.data.org3=tenant-300 +%test.tkit.rs.context.tenant-id.mock.data.org1=tenant-100 +%test.tkit.rs.context.tenant-id.mock.data.org2=tenant-200 +%test.tkit.rs.context.tenant-id.mock.data.org3=tenant-300 # TEST-IT (integration tests) -#quarkus.test.integration-test-profile=test-it -#%test-it.tkit.log.json.enabled=false -#%test-it.tkit.jpa.tenant.default=tenant-100 -#%test-it.tkit.rs.context.tenant-id.mock.enabled=true -#%test-it.tkit.rs.context.tenant-id.mock.default-tenant=tenant-100 +quarkus.test.integration-test-profile=test-it +%test-it.tkit.log.json.enabled=false +%test-it.tkit.jpa.tenant.default=tenant-100 +%test-it.tkit.rs.context.tenant-id.mock.enabled=true +%test-it.tkit.rs.context.tenant-id.mock.default-tenant=tenant-100 %test-it.tkit.rs.context.tenant-id.mock.claim-org-id=orgId %test-it.tkit.rs.context.tenant-id.mock.token-header-param=apm-principal-token -#%test-it.tkit.rs.context.tenant-id.mock.data.org1=tenant-100 -#%test-it.tkit.rs.context.tenant-id.mock.data.org2=tenant-200 -#%test-it.tkit.rs.context.tenant-id.mock.data.org3=tenant-300 +%test-it.tkit.rs.context.tenant-id.mock.data.org1=tenant-100 +%test-it.tkit.rs.context.tenant-id.mock.data.org2=tenant-200 +%test-it.tkit.rs.context.tenant-id.mock.data.org3=tenant-300 # PROD diff --git a/src/test/java/io/github/onecx/user/profile/domain/daos/UserProfileDAOTest.java b/src/test/java/io/github/onecx/user/profile/domain/daos/UserProfileDAOTest.java index dd61bca..8e7319f 100644 --- a/src/test/java/io/github/onecx/user/profile/domain/daos/UserProfileDAOTest.java +++ b/src/test/java/io/github/onecx/user/profile/domain/daos/UserProfileDAOTest.java @@ -24,6 +24,6 @@ void testWithoutEntityGraph() { var resultList = dao.findBySearchCriteria(null, 0, 10); assertThat(resultList).isNotNull(); - assertThat(resultList.getTotalElements()).isEqualTo(4); + assertThat(resultList.getTotalElements()).isEqualTo(2); } } diff --git a/src/test/java/io/github/onecx/user/profile/rs/external/v1/controllers/AvatarV1RestControllerTenantIT.java b/src/test/java/io/github/onecx/user/profile/rs/external/v1/controllers/AvatarV1RestControllerTenantIT.java new file mode 100644 index 0000000..44f7cbe --- /dev/null +++ b/src/test/java/io/github/onecx/user/profile/rs/external/v1/controllers/AvatarV1RestControllerTenantIT.java @@ -0,0 +1,7 @@ +package io.github.onecx.user.profile.rs.external.v1.controllers; + +import io.quarkus.test.junit.QuarkusIntegrationTest; + +@QuarkusIntegrationTest +public class AvatarV1RestControllerTenantIT extends AvatarV1RestControllerTenantTest { +} diff --git a/src/test/java/io/github/onecx/user/profile/rs/external/v1/controllers/AvatarV1RestControllerTenantTest.java b/src/test/java/io/github/onecx/user/profile/rs/external/v1/controllers/AvatarV1RestControllerTenantTest.java new file mode 100644 index 0000000..2e8dd24 --- /dev/null +++ b/src/test/java/io/github/onecx/user/profile/rs/external/v1/controllers/AvatarV1RestControllerTenantTest.java @@ -0,0 +1,130 @@ +package io.github.onecx.user.profile.rs.external.v1.controllers; + +import static io.restassured.RestAssured.given; +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +import static jakarta.ws.rs.core.Response.Status.*; +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; + +import org.junit.jupiter.api.Test; +import org.tkit.quarkus.test.WithDBData; + +import gen.io.github.onecx.user.profile.rs.external.v1.model.ImageInfoDTO; +import io.github.onecx.user.profile.test.AbstractTest; +import io.quarkus.test.common.http.TestHTTPEndpoint; +import io.quarkus.test.junit.QuarkusTest; + +@QuarkusTest +@TestHTTPEndpoint(AvatarV1RestController.class) +@WithDBData(value = "data/testdata.xml", deleteBeforeInsert = true, deleteAfterTest = true, rinseAndRepeat = true) +public class AvatarV1RestControllerTenantTest extends AbstractTest { + + @Test + void testAvatarRestControler() throws URISyntaxException, IOException { + // add avatar + File avatar = new File("src/test/resources/data/avatar_test.jpg"); + + // wrong tenant + given() + .when() + .contentType("image/jpg") + .body(avatar) + .header(APM_HEADER_PARAM, createToken("user1", "org2")) + .put() + .then() + .statusCode(NOT_FOUND.getStatusCode()); + + // good tenant + var imageInfo = given() + .when() + .contentType("image/jpg") + .body(avatar) + .header(APM_HEADER_PARAM, createToken("user1", "org1")) + .put() + .then() + .statusCode(OK.getStatusCode()) + .extract().as(ImageInfoDTO.class); + + // wrong tenant get small avatar + given() + .when() + .pathParam("id", imageInfo.getSmallImageUrl().substring(imageInfo.getSmallImageUrl().lastIndexOf("/") + 1)) + .header(APM_HEADER_PARAM, createToken("user1", "org3")) + .get("{id}") + .then() + .statusCode(NOT_FOUND.getStatusCode()); + + // good tenant get small avatar + var smallAvatarByteArray = given() + .when() + .pathParam("id", imageInfo.getSmallImageUrl().substring(imageInfo.getSmallImageUrl().lastIndexOf("/") + 1)) + .header(APM_HEADER_PARAM, createToken("user1", "org1")) + .get("{id}") + .then() + .contentType("image/png") + .statusCode(OK.getStatusCode()) + .extract().asByteArray(); + + assertThat(smallAvatarByteArray).isNotNull(); + + // get avatar info with wrong tenant + given() + .when() + .contentType(APPLICATION_JSON) + .header(APM_HEADER_PARAM, createToken("user1", "org3")) + .get() + .then() + .statusCode(NOT_FOUND.getStatusCode()); + + // get avatar info with good tenant + var avatarInfo = given() + .when() + .contentType(APPLICATION_JSON) + .header(APM_HEADER_PARAM, createToken("user1", "org1")) + .get() + .then() + .statusCode(OK.getStatusCode()) + .extract().as(ImageInfoDTO.class); + + assertThat(avatarInfo).isNotNull(); + assertThat(avatarInfo.getImageUrl()).isNotNull().isEqualTo(imageInfo.getImageUrl()); + assertThat(avatarInfo.getSmallImageUrl()).isNotNull().isEqualTo(imageInfo.getSmallImageUrl()); + + // delete with wrong tenant + given() + .when() + .contentType(APPLICATION_JSON) + .header(APM_HEADER_PARAM, createToken("user1", "org2")) + .delete() + .then() + .statusCode(NO_CONTENT.getStatusCode()); + + given() + .when() + .contentType(APPLICATION_JSON) + .header(APM_HEADER_PARAM, createToken("user1", "org1")) + .get() + .then() + .statusCode(OK.getStatusCode()); + + // delete with good tenant + given() + .when() + .contentType(APPLICATION_JSON) + .header(APM_HEADER_PARAM, createToken("user1", "org1")) + .delete() + .then() + .statusCode(NO_CONTENT.getStatusCode()); + + given() + .when() + .contentType(APPLICATION_JSON) + .header(APM_HEADER_PARAM, createToken("user1", "org1")) + .get() + .then() + .statusCode(NOT_FOUND.getStatusCode()); + } +} diff --git a/src/test/java/io/github/onecx/user/profile/rs/external/v1/controllers/AvatarV1RestExceptionTest.java b/src/test/java/io/github/onecx/user/profile/rs/external/v1/controllers/AvatarV1RestExceptionTest.java deleted file mode 100644 index 8b42fba..0000000 --- a/src/test/java/io/github/onecx/user/profile/rs/external/v1/controllers/AvatarV1RestExceptionTest.java +++ /dev/null @@ -1,68 +0,0 @@ -package io.github.onecx.user.profile.rs.external.v1.controllers; - -import static jakarta.ws.rs.core.Response.Status.*; - -import java.io.IOException; -import java.net.URISyntaxException; - -import org.junit.jupiter.api.Test; -import org.tkit.quarkus.test.WithDBData; - -import io.github.onecx.user.profile.test.AbstractTest; -import io.quarkus.test.common.http.TestHTTPEndpoint; -import io.quarkus.test.junit.QuarkusTest; - -@QuarkusTest -@TestHTTPEndpoint(AvatarV1RestController.class) -@WithDBData(value = "data/testdata.xml", deleteBeforeInsert = true, deleteAfterTest = true, rinseAndRepeat = true) -public class AvatarV1RestExceptionTest extends AbstractTest { - - @Test - void testAvatarRestControler() throws URISyntaxException, IOException { - - // Mockito.when(ImageIO.read((InputStream) any())).thenThrow(IOException.class); - // File avatar = new File("src/test/resources/data/avatar_test.jpg"); - // - // var imageInfo = given() - // .when() - // .contentType("image/jpg") - // .body(avatar) - // .header(APM_HEADER_PARAM, createToken("user1", null)) - // .put() - // .then() - // .statusCode(OK.getStatusCode()) - // .extract().as(ImageInfoDTO.class); - // - // assertThat(imageInfo).isNotNull(); - // assertThat(imageInfo.getSmallImageUrl()).isNotNull(); - // assertThat(imageInfo.getImageUrl()).isNotNull(); - // - // var avatarInfo = given() - // .when() - // .contentType(APPLICATION_JSON) - // .header(APM_HEADER_PARAM, createToken("user1", null)) - // .get() - // .then() - // .statusCode(OK.getStatusCode()) - // .extract().as(ImageInfoDTO.class); - // - // assertThat(avatarInfo).isNotNull(); - // assertThat(avatarInfo.getImageUrl()).isNotNull().isEqualTo(imageInfo.getImageUrl()); - // assertThat(avatarInfo.getSmallImageUrl()).isNotNull().isEqualTo(imageInfo.getSmallImageUrl()); - // - // Mock filesMock = new Mock(Files.class); - // Mockito.when(Files.readAllBytes(any())).thenThrow(IOException.class); - // var error = given() - // .when() - // .contentType("image/jpg") - // .body(avatar) - // .header(APM_HEADER_PARAM, createToken("user1", null)) - // .put() - // .then() - // .statusCode(BAD_REQUEST.getStatusCode()) - // .extract().as(ProblemDetailResponseDTO.class); - // - // assertThat(error).isNotNull(); - // assertThat(error.getErrorCode()).isEqualTo("IO_EXCEPTION"); - } -} diff --git a/src/test/java/io/github/onecx/user/profile/rs/external/v1/controllers/UserProfileV1RestControllerTenantIT.java b/src/test/java/io/github/onecx/user/profile/rs/external/v1/controllers/UserProfileV1RestControllerTenantIT.java new file mode 100644 index 0000000..3bb34b0 --- /dev/null +++ b/src/test/java/io/github/onecx/user/profile/rs/external/v1/controllers/UserProfileV1RestControllerTenantIT.java @@ -0,0 +1,7 @@ +package io.github.onecx.user.profile.rs.external.v1.controllers; + +import io.quarkus.test.junit.QuarkusIntegrationTest; + +@QuarkusIntegrationTest +public class UserProfileV1RestControllerTenantIT extends UserProfileV1RestControllerTenantTest { +} diff --git a/src/test/java/io/github/onecx/user/profile/rs/external/v1/controllers/UserProfileV1RestControllerTenantTest.java b/src/test/java/io/github/onecx/user/profile/rs/external/v1/controllers/UserProfileV1RestControllerTenantTest.java new file mode 100644 index 0000000..84d81dc --- /dev/null +++ b/src/test/java/io/github/onecx/user/profile/rs/external/v1/controllers/UserProfileV1RestControllerTenantTest.java @@ -0,0 +1,293 @@ +package io.github.onecx.user.profile.rs.external.v1.controllers; + +import static io.restassured.RestAssured.given; +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +import static jakarta.ws.rs.core.Response.Status.*; +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; +import org.tkit.quarkus.test.WithDBData; + +import gen.io.github.onecx.user.profile.rs.external.v1.model.*; +import io.github.onecx.user.profile.test.AbstractTest; +import io.quarkus.test.common.http.TestHTTPEndpoint; +import io.quarkus.test.junit.QuarkusTest; + +@QuarkusTest +@TestHTTPEndpoint(UserProfileV1RestController.class) +@WithDBData(value = "data/testdata.xml", deleteBeforeInsert = true, deleteAfterTest = true, rinseAndRepeat = true) +public class UserProfileV1RestControllerTenantTest extends AbstractTest { + + @Test + void createUserPreferenceTest() { + CreateUserPreferenceDTO createUserPreferenceDTO = new CreateUserPreferenceDTO(); + createUserPreferenceDTO.setValue("test"); + createUserPreferenceDTO.setDescription("Test preference"); + createUserPreferenceDTO.setName("TestPreference"); + createUserPreferenceDTO.setApplicationId("TestApp"); + + // create preference with wrong tenant + var error = given() + .when() + .contentType(APPLICATION_JSON) + .body(createUserPreferenceDTO) + .header(APM_HEADER_PARAM, createToken("user1", "org2")) + .post("preferences") + .then() + .statusCode(BAD_REQUEST.getStatusCode()) + .extract().as(ProblemDetailResponseDTO.class); + + assertThat(error).isNotNull(); + assertThat(error.getErrorCode()).isEqualTo("USER_PROFILE_DOES_NOT_EXIST"); + + // create preference with existing user profile + var preferenceDto = given() + .when() + .contentType(APPLICATION_JSON) + .body(createUserPreferenceDTO) + .header(APM_HEADER_PARAM, createToken("user1", "org1")) + .post("preferences") + .then() + .statusCode(CREATED.getStatusCode()) + .extract().as(UserPreferenceDTO.class); + + assertThat(preferenceDto).isNotNull(); + assertThat(preferenceDto.getValue()).isEqualTo(createUserPreferenceDTO.getValue()); + } + + @Test + void deleteUserPreferenceTest() { + // delete preference for the current logged in user with wrong tenant + given() + .when() + .contentType(APPLICATION_JSON) + .pathParam("id", "11-111") + .header(APM_HEADER_PARAM, createToken("user1", "org2")) + .delete("preferences/{id}") + .then() + .statusCode(NO_CONTENT.getStatusCode()); + + var result = given() + .when() + .contentType(APPLICATION_JSON) + .header(APM_HEADER_PARAM, createToken("user1", "org1")) + .get("preferences") + .then() + .statusCode(OK.getStatusCode()) + .extract().as(UserPreferencesDTO.class); + assertThat(result).isNotNull(); + assertThat(result.getPreferences()).isNotEmpty().hasSize(4); + + // delete preference for the current logged in user with correct tenant + given() + .when() + .contentType(APPLICATION_JSON) + .pathParam("id", "11-111") + .header(APM_HEADER_PARAM, createToken("user1", "org1")) + .delete("preferences/{id}") + .then() + .statusCode(NO_CONTENT.getStatusCode()); + + result = given() + .when() + .contentType(APPLICATION_JSON) + .header(APM_HEADER_PARAM, createToken("user1", "org1")) + .get("preferences") + .then() + .statusCode(OK.getStatusCode()) + .extract().as(UserPreferencesDTO.class); + assertThat(result).isNotNull(); + assertThat(result.getPreferences()).isNotEmpty().hasSize(3); + } + + @Test + void deleteUserProfileTest() { + // delete user profile with wrong tenant + given() + .when() + .contentType(APPLICATION_JSON) + .header(APM_HEADER_PARAM, createToken("user3", "org1")) + .delete() + .then() + .statusCode(NO_CONTENT.getStatusCode()); + + var userPofile = given() + .when() + .contentType(APPLICATION_JSON) + .header(APM_HEADER_PARAM, createToken("user3", "org2")) + .get() + .then() + .statusCode(OK.getStatusCode()) + .extract().as(UserProfileDTO.class); + + assertThat(userPofile).isNotNull(); + assertThat(userPofile.getUserId()).isEqualTo("user3"); + + // delete user profile with correct tenant + given() + .when() + .contentType(APPLICATION_JSON) + .header(APM_HEADER_PARAM, createToken("user3", "org2")) + .delete() + .then() + .statusCode(NO_CONTENT.getStatusCode()); + + given() + .when() + .contentType(APPLICATION_JSON) + .header(APM_HEADER_PARAM, createToken("user3", "org2")) + .get() + .then() + .statusCode(NOT_FOUND.getStatusCode()); + + } + + @Test + void getUserPersonTest() { + // retrieve user person dto wit wrong tenant. NOT_FOUND as result + given() + .when() + .contentType(APPLICATION_JSON) + .header(APM_HEADER_PARAM, createToken("user2", "org2")) + .get("person") + .then() + .statusCode(NOT_FOUND.getStatusCode()); + + // retrieve user person dto + var result = given() + .when() + .contentType(APPLICATION_JSON) + .header(APM_HEADER_PARAM, createToken("user2", "org1")) + .get("person") + .then() + .statusCode(OK.getStatusCode()) + .extract().as(UserPersonDTO.class); + + assertThat(result).isNotNull(); + assertThat(result.getDisplayName()).isEqualTo("User Two"); + } + + @Test + void getUserPreferenceTest() { + // get user preference with wrong tenant + var result = given() + .when() + .contentType(APPLICATION_JSON) + .header(APM_HEADER_PARAM, createToken("user1", "org3")) + .get("preferences") + .then() + .statusCode(OK.getStatusCode()) + .extract().as(UserPreferencesDTO.class); + assertThat(result).isNotNull(); + assertThat(result.getPreferences()).isNullOrEmpty(); + + // user 1 has 4 preferences + result = given() + .when() + .contentType(APPLICATION_JSON) + .header(APM_HEADER_PARAM, createToken("user1", "org1")) + .get("preferences") + .then() + .statusCode(OK.getStatusCode()) + .extract().as(UserPreferencesDTO.class); + assertThat(result).isNotNull(); + assertThat(result.getPreferences()).isNotEmpty().hasSize(4); + } + + @Test + void getUserProfileTest() { + // load existing user profile with wrong tenant - NOT_FOUND as result + given() + .when() + .contentType(APPLICATION_JSON) + .header(APM_HEADER_PARAM, createToken("user3", "org1")) + .get() + .then() + .statusCode(NOT_FOUND.getStatusCode()); + + } + + @Test + void getUserSettingsTest() { + // load existing user settings with wrong tenant - NOT_FOUND as result + given() + .when() + .contentType(APPLICATION_JSON) + .header(APM_HEADER_PARAM, createToken("user3", "org1")) + .get("settings") + .then() + .statusCode(NOT_FOUND.getStatusCode()); + + } + + @Test + void updateUserPersonTest() { + var userPersonDTO4 = given() + .when() + .contentType(APPLICATION_JSON) + .header(APM_HEADER_PARAM, createToken("user4", "org3")) + .get("person") + .then() + .statusCode(OK.getStatusCode()) + .extract().as(UserPersonDTO.class); + UpdateUserPersonDTO request = new UpdateUserPersonDTO(); + request.setEmail("new_email@capgemini.com"); + request.setLastName(userPersonDTO4.getLastName()); + request.setFirstName(userPersonDTO4.getFirstName()); + request.setDisplayName(userPersonDTO4.getDisplayName()); + request.setAddress(userPersonDTO4.getAddress()); + request.setPhone(userPersonDTO4.getPhone()); + + // update email with wrong tenant + given() + .when() + .contentType(APPLICATION_JSON) + .body(request) + .header(APM_HEADER_PARAM, createToken("user4", "org1")) + .put("person") + .then() + .statusCode(NOT_FOUND.getStatusCode()); + } + + @Test + void updateUserPreferenceTest() { + // update preference with wrong tenant + given() + .when() + .contentType(APPLICATION_JSON) + .body("changedTestValue") + .header(APM_HEADER_PARAM, createToken("user1", "org2")) + .pathParam("id", "11-111") + .patch("preferences/{id}") + .then() + .statusCode(NOT_FOUND.getStatusCode()); + } + + @Test + void updateUserSettingsTest() { + var userSettings = given() + .when() + .contentType(APPLICATION_JSON) + .header(APM_HEADER_PARAM, createToken("user3", "org2")) + .get("settings") + .then() + .statusCode(OK.getStatusCode()) + .extract().as(UserProfileAccountSettingsDTO.class); + UpdateUserSettingsDTO request = new UpdateUserSettingsDTO(); + request.setColorScheme(userSettings.getColorScheme()); + request.setLocale(userSettings.getLocale()); + request.setHideMyProfile(userSettings.getHideMyProfile()); + request.setTimezone(userSettings.getTimezone()); + request.setMenuMode(MenuModeDTO.SLIMPLUS); + + // update user settings with wrong tenant + given() + .when() + .contentType(APPLICATION_JSON) + .body(request) + .header(APM_HEADER_PARAM, createToken("user3", "org3")) + .put("settings") + .then() + .statusCode(NOT_FOUND.getStatusCode()); + } +} diff --git a/src/test/java/io/github/onecx/user/profile/rs/external/v1/controllers/UserProfileV1RestControllerTest.java b/src/test/java/io/github/onecx/user/profile/rs/external/v1/controllers/UserProfileV1RestControllerTest.java index 4efeecc..a53d6ea 100644 --- a/src/test/java/io/github/onecx/user/profile/rs/external/v1/controllers/UserProfileV1RestControllerTest.java +++ b/src/test/java/io/github/onecx/user/profile/rs/external/v1/controllers/UserProfileV1RestControllerTest.java @@ -10,7 +10,6 @@ import org.tkit.quarkus.test.WithDBData; import gen.io.github.onecx.user.profile.rs.external.v1.model.*; -import gen.io.github.onecx.user.profile.rs.internal.model.ProblemDetailResponseDTO; import io.github.onecx.user.profile.test.AbstractTest; import io.quarkus.test.common.http.TestHTTPEndpoint; import io.quarkus.test.junit.QuarkusTest; @@ -142,7 +141,7 @@ void getUserPersonTest() { var result = given() .when() .contentType(APPLICATION_JSON) - .header(APM_HEADER_PARAM, createToken("user2", null)) + .header(APM_HEADER_PARAM, createToken("user2", "org1")) .get("person") .then() .statusCode(OK.getStatusCode()) @@ -158,7 +157,7 @@ void getUserPreferenceTest() { var result = given() .when() .contentType(APPLICATION_JSON) - .header(APM_HEADER_PARAM, createToken("user2", null)) + .header(APM_HEADER_PARAM, createToken("user2", "org1")) .get("preferences") .then() .statusCode(OK.getStatusCode()) @@ -170,7 +169,7 @@ void getUserPreferenceTest() { result = given() .when() .contentType(APPLICATION_JSON) - .header(APM_HEADER_PARAM, createToken("user1", null)) + .header(APM_HEADER_PARAM, createToken("user1", "org1")) .get("preferences") .then() .statusCode(OK.getStatusCode()) @@ -194,7 +193,7 @@ void getUserProfileTest() { var userPofile = given() .when() .contentType(APPLICATION_JSON) - .header(APM_HEADER_PARAM, createToken("user3", null)) + .header(APM_HEADER_PARAM, createToken("user3", "org2")) .get() .then() .statusCode(OK.getStatusCode()) @@ -220,7 +219,7 @@ void getUserSettingsTest() { var userSettings = given() .when() .contentType(APPLICATION_JSON) - .header(APM_HEADER_PARAM, createToken("user3", null)) + .header(APM_HEADER_PARAM, createToken("user3", "org2")) .get("settings") .then() .statusCode(OK.getStatusCode()) @@ -237,7 +236,7 @@ void updateUserPersonTest() { var error = given() .when() .contentType(APPLICATION_JSON) - .header(APM_HEADER_PARAM, createToken("user1", null)) + .header(APM_HEADER_PARAM, createToken("user1", "org1")) .put("person") .then() .statusCode(BAD_REQUEST.getStatusCode()) @@ -249,7 +248,7 @@ void updateUserPersonTest() { var userPersonDTO4 = given() .when() .contentType(APPLICATION_JSON) - .header(APM_HEADER_PARAM, createToken("user4", null)) + .header(APM_HEADER_PARAM, createToken("user4", "org3")) .get("person") .then() .statusCode(OK.getStatusCode()) @@ -277,7 +276,7 @@ void updateUserPersonTest() { .when() .contentType(APPLICATION_JSON) .body(request) - .header(APM_HEADER_PARAM, createToken("user1", null)) + .header(APM_HEADER_PARAM, createToken("user4", "org3")) .put("person") .then() .statusCode(OK.getStatusCode()) @@ -366,7 +365,7 @@ void updateUserSettingsTest() { var userSettings = given() .when() .contentType(APPLICATION_JSON) - .header(APM_HEADER_PARAM, createToken("user3", null)) + .header(APM_HEADER_PARAM, createToken("user3", "org2")) .get("settings") .then() .statusCode(OK.getStatusCode()) @@ -394,7 +393,7 @@ void updateUserSettingsTest() { .when() .contentType(APPLICATION_JSON) .body(request) - .header(APM_HEADER_PARAM, createToken("user3", null)) + .header(APM_HEADER_PARAM, createToken("user3", "org2")) .put("settings") .then() .statusCode(OK.getStatusCode()) diff --git a/src/test/java/io/github/onecx/user/profile/rs/internal/controllers/UserProfileInternalRestControllerTenantIT.java b/src/test/java/io/github/onecx/user/profile/rs/internal/controllers/UserProfileInternalRestControllerTenantIT.java new file mode 100644 index 0000000..92f9d32 --- /dev/null +++ b/src/test/java/io/github/onecx/user/profile/rs/internal/controllers/UserProfileInternalRestControllerTenantIT.java @@ -0,0 +1,7 @@ +package io.github.onecx.user.profile.rs.internal.controllers; + +import io.quarkus.test.junit.QuarkusIntegrationTest; + +@QuarkusIntegrationTest +public class UserProfileInternalRestControllerTenantIT extends UserProfileInternalRestControllerTenantTest { +} diff --git a/src/test/java/io/github/onecx/user/profile/rs/internal/controllers/UserProfileInternalRestControllerTenantTest.java b/src/test/java/io/github/onecx/user/profile/rs/internal/controllers/UserProfileInternalRestControllerTenantTest.java new file mode 100644 index 0000000..2ae7ae2 --- /dev/null +++ b/src/test/java/io/github/onecx/user/profile/rs/internal/controllers/UserProfileInternalRestControllerTenantTest.java @@ -0,0 +1,236 @@ +package io.github.onecx.user.profile.rs.internal.controllers; + +import static io.restassured.RestAssured.given; +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +import static jakarta.ws.rs.core.Response.Status.*; +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; +import org.tkit.quarkus.test.WithDBData; + +import gen.io.github.onecx.user.profile.rs.internal.model.*; +import io.github.onecx.user.profile.test.AbstractTest; +import io.quarkus.test.common.http.TestHTTPEndpoint; +import io.quarkus.test.junit.QuarkusTest; + +@QuarkusTest +@TestHTTPEndpoint(UserProfileInternalRestController.class) +@WithDBData(value = "data/testdata.xml", deleteBeforeInsert = true, deleteAfterTest = true, rinseAndRepeat = true) +public class UserProfileInternalRestControllerTenantTest extends AbstractTest { + + @Test + void createUserProfileTest() { + // create user profile with content + CreateUserProfileRequestDTO request = new CreateUserProfileRequestDTO(); + request.setUserId("cap"); + request.setOrganization("capgemini"); + request.setIdentityProvider("database"); + request.setIdentityProviderId("db"); + var person = new CreateUserPersonDTO(); + request.setPerson(person); + person.setDisplayName("Capgemini super user"); + person.setEmail("cap@capgemini.com"); + person.setFirstName("Superuser"); + person.setLastName("Capgeminius"); + + var result = given() + .when() + .contentType(APPLICATION_JSON) + .header(APM_HEADER_PARAM, createToken("user4", "org3")) + .body(request) + .post() + .then() + .statusCode(CREATED.getStatusCode()) + .extract().as(UserProfileDTO.class); + + assertThat(result).isNotNull(); + assertThat(result.getUserId()).isEqualTo(request.getUserId()); + assertThat(result.getModificationDate()).isNotNull(); + assertThat(result.getPerson().getPhone()).isNull(); + + given() + .when() + .pathParam("id", "cap") + .header(APM_HEADER_PARAM, createToken("user4", "org2")) + .get("{id}") + .then() + .statusCode(NOT_FOUND.getStatusCode()); + + result = given() + .when() + .pathParam("id", "cap") + .header(APM_HEADER_PARAM, createToken("user4", "org3")) + .get("{id}") + .then() + .statusCode(OK.getStatusCode()) + .extract().as(UserProfileDTO.class); + + assertThat(result).isNotNull(); + assertThat(result.getUserId()).isEqualTo(request.getUserId()); + assertThat(result.getModificationDate()).isNotNull(); + assertThat(result.getPerson().getPhone()).isNull(); + + } + + @Test + void deleteUserProfileTest() { + // delete existing profile with wrong tenant + given() + .when() + .header(APM_HEADER_PARAM, createToken("user4", "org3")) + .pathParam("id", "user1") + .delete("{id}") + .then() + .statusCode(NO_CONTENT.getStatusCode()); + + // load deleted profile still found as deleted with wrong tenant + given() + .when() + .header(APM_HEADER_PARAM, createToken("user4", "org1")) + .pathParam("id", "user1") + .get("{id}") + .then() + .statusCode(OK.getStatusCode()); + + // delete existing profile with correct tenant + given() + .when() + .header(APM_HEADER_PARAM, createToken("user4", "org1")) + .pathParam("id", "user1") + .delete("{id}") + .then() + .statusCode(NO_CONTENT.getStatusCode()); + + // load deleted profile returns not found + given() + .when() + .header(APM_HEADER_PARAM, createToken("user4", "org1")) + .pathParam("id", "user1") + .get("{id}") + .then() + .statusCode(NOT_FOUND.getStatusCode()); + } + + @Test + void getUserProfileTest() { + // get with different tenant + given() + .when() + .header(APM_HEADER_PARAM, createToken("user4", "org2")) + .pathParam("id", "user1") + .get("{id}") + .then() + .statusCode(NOT_FOUND.getStatusCode()); + + // get existing profile with correct tenant + var result = given() + .when() + .header(APM_HEADER_PARAM, createToken("user4", "org1")) + .pathParam("id", "user1") + .get("{id}") + .then() + .statusCode(OK.getStatusCode()) + .extract().as(UserProfileDTO.class); + + assertThat(result).isNotNull(); + assertThat(result.getUserId()).isEqualTo("user1"); + assertThat(result.getAccountSettings().getColorScheme().name()) + .isEqualTo(ColorSchemeDTO.AUTO.name()); + assertThat(result.getPerson().getAddress().getStreet()).isEqualTo("userstreet1"); + } + + @Test + void searchUserProfileTest() { + // search with criteria + // org1 + UserPersonCriteriaDTO criteriaDTO = new UserPersonCriteriaDTO(); + criteriaDTO.setEmail("*cap.de"); + var result = given() + .when() + .header(APM_HEADER_PARAM, createToken("user4", "org1")) + .body(criteriaDTO) + .contentType(APPLICATION_JSON) + .post("search") + .then() + .statusCode(OK.getStatusCode()) + .extract().as(UserProfilePageResultDTO.class); + + assertThat(result).isNotNull(); + assertThat(result.getTotalElements()).isEqualTo(2); + var resultList = result.getStream(); + assertThat(resultList.get(0).getPerson().getLastName()).isEqualTo("One"); + + // org2 + result = given() + .when() + .header(APM_HEADER_PARAM, createToken("user4", "org2")) + .body(criteriaDTO) + .contentType(APPLICATION_JSON) + .post("search") + .then() + .statusCode(OK.getStatusCode()) + .extract().as(UserProfilePageResultDTO.class); + + assertThat(result).isNotNull(); + assertThat(result.getTotalElements()).isEqualTo(1); + resultList = result.getStream(); + assertThat(resultList.get(0).getPerson().getLastName()).isEqualTo("Three"); + + } + + @Test + void updateUserProfileTest() { + var userProfileDTO = given() + .when() + .header(APM_HEADER_PARAM, createToken("user4", "org1")) + .pathParam("id", "user1") + .get("{id}") + .then() + .statusCode(OK.getStatusCode()) + .extract().as(UserProfileDTO.class); + + UpdateUserPersonRequestDTO requestDTO = new UpdateUserPersonRequestDTO(); + requestDTO.setEmail(userProfileDTO.getPerson().getEmail()); + requestDTO.setDisplayName(userProfileDTO.getPerson().getDisplayName()); + requestDTO.setFirstName(userProfileDTO.getPerson().getFirstName()); + requestDTO.setLastName(userProfileDTO.getPerson().getLastName()); + requestDTO.setAddress(userProfileDTO.getPerson().getAddress()); + requestDTO.setPhone(userProfileDTO.getPerson().getPhone()); + requestDTO.getPhone().setNumber("123456789"); + requestDTO.getPhone().setType(PhoneTypeDTO.LANDLINE); + + // update existing profile with wrong tenant + given() + .when() + .header(APM_HEADER_PARAM, createToken("user4", "org2")) + .contentType(APPLICATION_JSON) + .body(requestDTO) + .pathParam("id", "user1") + .put("{id}") + .then() + .statusCode(NOT_FOUND.getStatusCode()); + + // update existing profile with correct tenant + given() + .when() + .header(APM_HEADER_PARAM, createToken("user4", "org1")) + .contentType(APPLICATION_JSON) + .body(requestDTO) + .pathParam("id", "user1") + .put("{id}") + .then() + .statusCode(NO_CONTENT.getStatusCode()); + + userProfileDTO = given() + .when() + .header(APM_HEADER_PARAM, createToken("user4", "org1")) + .pathParam("id", "user1") + .get("{id}") + .then() + .statusCode(OK.getStatusCode()) + .extract().as(UserProfileDTO.class); + + assertThat(userProfileDTO.getPerson().getPhone().getType()).isEqualTo(requestDTO.getPhone().getType()); + assertThat(userProfileDTO.getPerson().getPhone().getNumber()).isEqualTo(requestDTO.getPhone().getNumber()); + } +} diff --git a/src/test/java/io/github/onecx/user/profile/rs/internal/controllers/UserProfileInternalRestControllerTest.java b/src/test/java/io/github/onecx/user/profile/rs/internal/controllers/UserProfileInternalRestControllerTest.java index 5fce3ee..dbfbdba 100644 --- a/src/test/java/io/github/onecx/user/profile/rs/internal/controllers/UserProfileInternalRestControllerTest.java +++ b/src/test/java/io/github/onecx/user/profile/rs/internal/controllers/UserProfileInternalRestControllerTest.java @@ -50,6 +50,7 @@ void createUserProfileTest() { var result = given() .when() .contentType(APPLICATION_JSON) + .header(APM_HEADER_PARAM, createToken("user3", "org2")) .body(request) .post() .then() @@ -61,15 +62,31 @@ void createUserProfileTest() { assertThat(result.getModificationDate()).isNotNull(); assertThat(result.getPerson().getPhone()).isNull(); + result = given() + .when() + .header(APM_HEADER_PARAM, createToken("user3", "org2")) + .pathParam("id", "cap") + .get("{id}") + .then() + .statusCode(OK.getStatusCode()) + .extract().as(UserProfileDTO.class); + + assertThat(result).isNotNull(); + assertThat(result.getUserId()).isEqualTo(request.getUserId()); + assertThat(result.getModificationDate()).isNotNull(); + assertThat(result.getPerson().getPhone()).isNull(); + error = given() .when() .contentType(APPLICATION_JSON) + .header(APM_HEADER_PARAM, createToken("user3", "org2")) .body(request) .post() .then() .statusCode(BAD_REQUEST.getStatusCode()) .extract().as(ProblemDetailResponseDTO.class); + assertThat(error).isNotNull(); assertThat(error.getErrorCode()).isEqualTo("PERSIST_ENTITY_FAILED"); assertThat(error.getDetail()).isEqualTo( "could not execute statement [ERROR: duplicate key value violates unique constraint 'ukm9nl9w7ih2pti88rq0xf31c5y' Detail: Key (user_id)=(cap) already exists.]"); @@ -96,7 +113,7 @@ void deleteUserProfileTest() { // load deleted profile given() .when() - .pathParam("id", "11-111") + .pathParam("id", "user1") .get("{id}") .then() .statusCode(NOT_FOUND.getStatusCode()); @@ -104,14 +121,6 @@ void deleteUserProfileTest() { @Test void getUserProfileTest() { - // get not existing profile - given() - .when() - .pathParam("id", "not-existing") - .get("{id}") - .then() - .statusCode(NOT_FOUND.getStatusCode()); - // get existing profile var result = given() .when() @@ -156,7 +165,7 @@ void searchUserProfileTest() { .extract().as(UserProfilePageResultDTO.class); assertThat(result).isNotNull(); - assertThat(result.getTotalElements()).isEqualTo(4); + assertThat(result.getTotalElements()).isEqualTo(2); var resultList = result.getStream(); assertThat(resultList.get(0).getPerson().getLastName()).isEqualTo("One"); @@ -172,7 +181,7 @@ void searchUserProfileTest() { .extract().as(UserProfilePageResultDTO.class); assertThat(result).isNotNull(); - assertThat(result.getTotalElements()).isEqualTo(4); + assertThat(result.getTotalElements()).isEqualTo(2); resultList = result.getStream(); assertThat(resultList.get(0).getPerson().getLastName()).isEqualTo("One"); @@ -210,7 +219,7 @@ void searchUserProfileTest() { .extract().as(UserProfilePageResultDTO.class); assertThat(result).isNotNull(); - assertThat(result.getTotalElements()).isEqualTo(3); + assertThat(result.getTotalElements()).isEqualTo(2); } @Test