Skip to content

Commit

Permalink
feat: enable multitenancy
Browse files Browse the repository at this point in the history
  • Loading branch information
milan.horvath committed Jan 9, 2024
1 parent d6201f2 commit 5a4cf52
Show file tree
Hide file tree
Showing 16 changed files with 740 additions and 115 deletions.
9 changes: 2 additions & 7 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
<artifactId>tkit-quarkus-rest</artifactId>
</dependency>

<!-- TENANT
<!-- TENANT -->
<dependency>
<groupId>io.github.onecx.quarkus</groupId>
<artifactId>onecx-tenant</artifactId>
Expand All @@ -48,7 +48,7 @@
<dependency>
<groupId>org.tkit.quarkus.lib</groupId>
<artifactId>tkit-quarkus-rest-context</artifactId>
</dependency>-->
</dependency>

<!-- QUARKUS -->
<dependency>
Expand Down Expand Up @@ -100,11 +100,6 @@
<artifactId>quarkus-opentelemetry</artifactId>
</dependency>

<dependency>
<groupId>org.tkit.quarkus.lib</groupId>
<artifactId>tkit-quarkus-rest-context</artifactId>
</dependency>

<!-- OTHER -->
<dependency>
<groupId>org.projectlombok</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import jakarta.persistence.*;

import org.hibernate.annotations.TenantId;
import org.tkit.quarkus.jpa.models.TraceableEntity;

import lombok.Getter;
Expand All @@ -13,6 +14,7 @@
@Setter
public class Image extends TraceableEntity {

@TenantId
@Column(name = "TENANT_ID")
private String tenantId;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import jakarta.persistence.*;

import org.hibernate.annotations.TenantId;
import org.tkit.quarkus.jpa.models.TraceableEntity;

import lombok.Getter;
Expand All @@ -25,6 +26,7 @@ public class Preference extends TraceableEntity {
@Column(name = "APPLICATION_ID")
private String applicationId;

@TenantId
@Column(name = "TENANT_ID")
private String tenantId;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import jakarta.persistence.*;

import org.hibernate.annotations.TenantId;
import org.tkit.quarkus.jpa.models.TraceableEntity;

import lombok.Getter;
Expand Down Expand Up @@ -41,6 +42,7 @@ public class UserProfile extends TraceableEntity {
@Column(name = "USER_ID")
private String userId;

@TenantId
@Column(name = "TENANT_ID")
private String tenantId;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
32 changes: 16 additions & 16 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,40 @@ 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

# 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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 {
}
Original file line number Diff line number Diff line change
@@ -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());
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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 {
}
Loading

0 comments on commit 5a4cf52

Please sign in to comment.