diff --git a/licensing-service-sdk/pom.xml b/licensing-service-sdk/pom.xml
index 752dd5d..bac77d5 100644
--- a/licensing-service-sdk/pom.xml
+++ b/licensing-service-sdk/pom.xml
@@ -109,6 +109,20 @@
+
+ org.apache.maven.plugins
+ maven-failsafe-plugin
+ ${maven-failsafe-plugin.version}
+
+
+
+ integration-test
+ verify
+
+
+
+
+
org.jacoco
jacoco-maven-plugin
@@ -120,6 +134,14 @@
prepare-agent
+
+
+ prepare-agent-integration
+
+ prepare-agent-integration
+
+
+
report
verify
@@ -127,9 +149,16 @@
report
+
+
+ report-integration
+ verify
+
+ report-integration
+
+
-
diff --git a/licensing-service-sdk/src/test/java/io/github/bsayli/licensing/sdk/api/controller/LicenseControllerIT.java b/licensing-service-sdk/src/test/java/io/github/bsayli/licensing/sdk/api/controller/LicenseControllerIT.java
new file mode 100644
index 0000000..7563f0d
--- /dev/null
+++ b/licensing-service-sdk/src/test/java/io/github/bsayli/licensing/sdk/api/controller/LicenseControllerIT.java
@@ -0,0 +1,94 @@
+package io.github.bsayli.licensing.sdk.api.controller;
+
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.github.bsayli.licensing.sdk.api.dto.LicenseAccessRequest;
+import io.github.bsayli.licensing.sdk.api.dto.LicenseToken;
+import io.github.bsayli.licensing.sdk.api.exception.LicenseControllerAdvice;
+import io.github.bsayli.licensing.sdk.common.i18n.LocalizedMessageResolver;
+import io.github.bsayli.licensing.sdk.service.LicenseOrchestrationService;
+import io.github.bsayli.licensing.sdk.testconfig.TestControllerMocksConfig;
+import io.github.bsayli.licensing.sdk.testconfig.TestRestClientConfig;
+import io.github.bsayli.licensing.sdk.testconfig.TestWebMvcSecurityConfig;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.FilterType;
+import org.springframework.context.annotation.Import;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MockMvc;
+
+@WebMvcTest(
+ controllers = LicenseController.class,
+ excludeFilters = {
+ @ComponentScan.Filter(
+ type = FilterType.ASSIGNABLE_TYPE,
+ classes = io.github.bsayli.licensing.sdk.config.security.SecurityConfig.class),
+ @ComponentScan.Filter(
+ type = FilterType.REGEX,
+ pattern = "io\\.github\\.bsayli\\.licensing\\.client\\..*")
+ })
+@Import({
+ LicenseControllerAdvice.class,
+ TestWebMvcSecurityConfig.class,
+ TestControllerMocksConfig.class,
+ TestRestClientConfig.class
+})
+@Tag("integration")
+class LicenseControllerIT {
+
+ @Autowired private MockMvc mvc;
+ @Autowired private ObjectMapper om;
+ @Autowired private LicenseOrchestrationService service;
+ @Autowired private LocalizedMessageResolver messageResolver;
+
+ @Test
+ @DisplayName("POST /v1/licenses/access -> 200 returns token")
+ void obtainToken_ok() throws Exception {
+ var req =
+ new LicenseAccessRequest(
+ "L".repeat(100) + "~rnd~" + "A".repeat(64),
+ "licensing-service~demo~00:11:22:33:44:55",
+ "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8a5",
+ "crm",
+ "1.5.0");
+
+ Mockito.when(service.getLicenseToken(req)).thenReturn(new LicenseToken("jwt-token"));
+ Mockito.when(messageResolver.getMessage("license.validation.success"))
+ .thenReturn("License is valid");
+
+ mvc.perform(
+ post("/v1/licenses/access")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(om.writeValueAsBytes(req)))
+ .andExpect(status().isOk())
+ .andExpect(content().contentType(MediaType.APPLICATION_JSON))
+ .andExpect(jsonPath("$.status").value(200))
+ .andExpect(jsonPath("$.message").value("License is valid"))
+ .andExpect(jsonPath("$.data.licenseToken").value("jwt-token"));
+ }
+
+ @Test
+ @DisplayName("POST /v1/licenses/access -> 400 validation error")
+ void obtainToken_validationError() throws Exception {
+ var bad = new LicenseAccessRequest("x", "short", null, "c", "1");
+
+ Mockito.when(messageResolver.getMessage("request.validation.failed"))
+ .thenReturn("Request validation failed");
+
+ mvc.perform(
+ post("/v1/licenses/access")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(om.writeValueAsBytes(bad)))
+ .andExpect(status().isBadRequest())
+ .andExpect(content().contentType(MediaType.APPLICATION_JSON))
+ .andExpect(jsonPath("$.message").value("Request validation failed"))
+ .andExpect(jsonPath("$.errors").isArray());
+ }
+}
diff --git a/licensing-service-sdk/src/test/java/io/github/bsayli/licensing/sdk/testconfig/TestControllerMocksConfig.java b/licensing-service-sdk/src/test/java/io/github/bsayli/licensing/sdk/testconfig/TestControllerMocksConfig.java
new file mode 100644
index 0000000..fb3c76b
--- /dev/null
+++ b/licensing-service-sdk/src/test/java/io/github/bsayli/licensing/sdk/testconfig/TestControllerMocksConfig.java
@@ -0,0 +1,30 @@
+package io.github.bsayli.licensing.sdk.testconfig;
+
+import io.github.bsayli.licensing.sdk.common.i18n.LocalizedMessageResolver;
+import io.github.bsayli.licensing.sdk.service.LicenseOrchestrationService;
+import org.mockito.Mockito;
+import org.springframework.boot.test.context.TestConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Primary;
+
+@TestConfiguration
+public class TestControllerMocksConfig {
+
+ @Bean
+ @Primary
+ public LicenseOrchestrationService licenseOrchestrationService() {
+ return Mockito.mock(LicenseOrchestrationService.class);
+ }
+
+ @Bean
+ @Primary
+ public LocalizedMessageResolver messageResolver() {
+ var mr = Mockito.mock(LocalizedMessageResolver.class);
+ Mockito.when(mr.getMessage("license.validation.success")).thenReturn("License is valid");
+ Mockito.when(mr.getMessage("request.validation.failed"))
+ .thenReturn("Request validation failed");
+ Mockito.when(mr.getMessage("license.validation.error"))
+ .thenReturn("An unexpected error occurred");
+ return mr;
+ }
+}
diff --git a/licensing-service-sdk/src/test/java/io/github/bsayli/licensing/sdk/testconfig/TestRestClientConfig.java b/licensing-service-sdk/src/test/java/io/github/bsayli/licensing/sdk/testconfig/TestRestClientConfig.java
new file mode 100644
index 0000000..5fc6f39
--- /dev/null
+++ b/licensing-service-sdk/src/test/java/io/github/bsayli/licensing/sdk/testconfig/TestRestClientConfig.java
@@ -0,0 +1,16 @@
+package io.github.bsayli.licensing.sdk.testconfig;
+
+import org.springframework.boot.test.context.TestConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Primary;
+import org.springframework.web.client.RestClient;
+
+@TestConfiguration
+public class TestRestClientConfig {
+
+ @Bean
+ @Primary
+ public RestClient.Builder restClientBuilder() {
+ return RestClient.builder();
+ }
+}
diff --git a/licensing-service-sdk/src/test/java/io/github/bsayli/licensing/sdk/testconfig/TestWebMvcSecurityConfig.java b/licensing-service-sdk/src/test/java/io/github/bsayli/licensing/sdk/testconfig/TestWebMvcSecurityConfig.java
new file mode 100644
index 0000000..d494a45
--- /dev/null
+++ b/licensing-service-sdk/src/test/java/io/github/bsayli/licensing/sdk/testconfig/TestWebMvcSecurityConfig.java
@@ -0,0 +1,22 @@
+package io.github.bsayli.licensing.sdk.testconfig;
+
+import org.springframework.boot.test.context.TestConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
+import org.springframework.security.web.SecurityFilterChain;
+
+@TestConfiguration
+public class TestWebMvcSecurityConfig {
+
+ @Bean
+ @Order(Ordered.HIGHEST_PRECEDENCE)
+ SecurityFilterChain testSecurity(HttpSecurity http) throws Exception {
+ return http.securityMatcher("/v1/**")
+ .csrf(AbstractHttpConfigurer::disable)
+ .authorizeHttpRequests(reg -> reg.anyRequest().permitAll())
+ .build();
+ }
+}
diff --git a/licensing-service-sdk/src/test/resources/application-test.yml b/licensing-service-sdk/src/test/resources/application-test.yml
new file mode 100644
index 0000000..8bd1a75
--- /dev/null
+++ b/licensing-service-sdk/src/test/resources/application-test.yml
@@ -0,0 +1,65 @@
+spring:
+ config:
+ activate:
+ on-profile: test
+
+ main:
+ allow-bean-definition-overriding: true
+ autoconfigure:
+ exclude:
+ - org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
+ - org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration
+
+ messages:
+ basename: messages
+ encoding: UTF-8
+ fallback-to-system-locale: false
+
+server:
+ port: 0
+ servlet:
+ context-path: /licensing-service-sdk
+ error:
+ include-message: always
+ include-binding-errors: always
+ include-stacktrace: never
+ include-exception: false
+
+logging:
+ level:
+ root: INFO
+ org.springframework: WARN
+ org.hibernate: WARN
+ org.springframework.security: OFF
+ io.github.bsayli.licensing: DEBUG
+
+app:
+ openapi:
+ base-url: "http://localhost:${server.port}${server.servlet.context-path:}"
+
+caching:
+ spring:
+ licenseTokenTTL: 30m
+
+licensing:
+ sdk:
+ api:
+ basic:
+ username: "testSdkUser"
+ password: "testSdkPass"
+ realm: "LicensingServiceSDK-Test"
+
+licensing-service-api:
+ base-url: "http://localhost:8081/licensing-service"
+ basic:
+ username: "licensingUser"
+ password: "licensingPass"
+ connect-timeout-seconds: 5
+ connection-request-timeout-seconds: 5
+ read-timeout-seconds: 8
+ max-connections-total: 16
+ max-connections-per-route: 8
+
+signature:
+ private:
+ key: "MC4CAQAwBQYDK2VwBCIEIG265cW0Yrh583IXT/Hmfd2A1hFnHXViCZHpJu83OBFj"
\ No newline at end of file
diff --git a/licensing-service/src/test/java/io/github/bsayli/licensing/testconfig/TestSecurityConfig.java b/licensing-service/src/test/java/io/github/bsayli/licensing/testconfig/TestSecurityConfig.java
index 6fa1c0a..8ff770f 100644
--- a/licensing-service/src/test/java/io/github/bsayli/licensing/testconfig/TestSecurityConfig.java
+++ b/licensing-service/src/test/java/io/github/bsayli/licensing/testconfig/TestSecurityConfig.java
@@ -13,11 +13,10 @@
@Profile("test")
public class TestSecurityConfig {
- @Bean
- SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
- return http
- .csrf(AbstractHttpConfigurer::disable)
- .authorizeHttpRequests(reg -> reg.anyRequest().permitAll())
- .build();
- }
-}
\ No newline at end of file
+ @Bean
+ SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
+ return http.csrf(AbstractHttpConfigurer::disable)
+ .authorizeHttpRequests(reg -> reg.anyRequest().permitAll())
+ .build();
+ }
+}