From 219eeb40edaf060c5cfe38eb8a9ea137ec846b24 Mon Sep 17 00:00:00 2001 From: barissayli Date: Sun, 14 Sep 2025 15:09:17 -0600 Subject: [PATCH] test: add integration tests for LicenseController and CacheConfig - Introduced LicenseControllerIT with mocked service and i18n resolver - Added CacheConfigIT verifying Redis cache round-trip and TTL behavior - Enabled embedded Redis and test-specific security overrides --- license-generator/pom.xml | 26 ++-- .../license/signature/SignatureDemo.java | 6 +- licensing-service-sdk-cli/README.md | 4 +- licensing-service/pom.xml | 38 +++++ .../api/controller/LicenseControllerIT.java | 142 ++++++++++++++++++ .../bsayli/licensing/cache/CacheConfigIT.java | 118 +++++++++++++++ .../service/jwt/impl/JwtServiceImplTest.java | 4 +- .../testconfig/EmbeddedRedisConfig.java | 51 +++++++ .../licensing/testconfig/RedisProperties.java | 26 ++++ .../testconfig/TestControllerMocksConfig.java | 28 ++++ .../testconfig/TestSecurityConfig.java | 23 +++ .../testconfig/TestWebMvcSecurityConfig.java | 18 +++ .../src/test/resources/application-test.yml | 134 +++++++++++++++++ 13 files changed, 600 insertions(+), 18 deletions(-) create mode 100644 licensing-service/src/test/java/io/github/bsayli/licensing/api/controller/LicenseControllerIT.java create mode 100644 licensing-service/src/test/java/io/github/bsayli/licensing/cache/CacheConfigIT.java create mode 100644 licensing-service/src/test/java/io/github/bsayli/licensing/testconfig/EmbeddedRedisConfig.java create mode 100644 licensing-service/src/test/java/io/github/bsayli/licensing/testconfig/RedisProperties.java create mode 100644 licensing-service/src/test/java/io/github/bsayli/licensing/testconfig/TestControllerMocksConfig.java create mode 100644 licensing-service/src/test/java/io/github/bsayli/licensing/testconfig/TestSecurityConfig.java create mode 100644 licensing-service/src/test/java/io/github/bsayli/licensing/testconfig/TestWebMvcSecurityConfig.java create mode 100644 licensing-service/src/test/resources/application-test.yml diff --git a/license-generator/pom.xml b/license-generator/pom.xml index c9a6481..ea5d2f9 100644 --- a/license-generator/pom.xml +++ b/license-generator/pom.xml @@ -12,19 +12,17 @@ 21 UTF-8 UTF-8 - 0.12.7 1.81 2.19.2 1.5.18 2.0.17 - - 3.14.0 - 5.13.4 - 3.5.3 0.8.13 1.2.1 + 3.14.0 + 3.5.4 + 3.5.4 @@ -111,22 +109,30 @@ prepare-agent - prepare-agent + + prepare-agent + report verify - report + + report + prepare-agent-integration - prepare-agent-integration + + prepare-agent-integration + report-integration verify - report-integration + + report-integration + @@ -141,7 +147,7 @@ maven-failsafe-plugin - ${maven-surefire-plugin.version} + ${maven-failsafe-plugin.version} diff --git a/license-generator/src/main/java/io/github/bsayli/license/signature/SignatureDemo.java b/license-generator/src/main/java/io/github/bsayli/license/signature/SignatureDemo.java index e36e592..9249eb4 100644 --- a/license-generator/src/main/java/io/github/bsayli/license/signature/SignatureDemo.java +++ b/license-generator/src/main/java/io/github/bsayli/license/signature/SignatureDemo.java @@ -68,17 +68,17 @@ static Optional readOpt(String[] argv, String name) { private static void printUsage() { log.info( - """ + """ Usage: # Sign sample payload (encrypted license key variant) java -cp license-generator.jar io.github.bsayli.license.signature.SignatureDemo \\ --mode sign-sample-key \\ --privateKey - + # Sign sample payload (license token variant) java -cp license-generator.jar io.github.bsayli.license.signature.SignatureDemo \\ --mode sign-sample-token \\ --privateKey """); } -} \ No newline at end of file +} diff --git a/licensing-service-sdk-cli/README.md b/licensing-service-sdk-cli/README.md index 79b0dad..67b0833 100644 --- a/licensing-service-sdk-cli/README.md +++ b/licensing-service-sdk-cli/README.md @@ -45,7 +45,7 @@ java -jar target/licensing-service-sdk-cli-.jar \ ### Options | Flag | Long Option | Description | Required | -| ---- | ------------------- | ---------------------------------------------------------------------------- | -------- | +|------|---------------------|------------------------------------------------------------------------------|----------| | `-k` | `--key` | License key string (`PREFIX~RANDOM~ENCRYPTED_USER_ID`) | Yes | | `-s` | `--service-id` | Service identifier (e.g. `crm`) | Yes | | `-v` | `--service-version` | Service version (e.g. `1.5.0`) | Yes | @@ -122,7 +122,7 @@ LICENSE_SERVICE_SDK_API_PATH=/v1/licenses/access ## Exit Codes | Code | Meaning | -| ---- | ----------------------------------------------- | +|------|-------------------------------------------------| | `0` | License validated successfully | | `1` | License validation failed (client/server error) | | `2` | CLI usage error | diff --git a/licensing-service/pom.xml b/licensing-service/pom.xml index 5fe8500..2c746d5 100644 --- a/licensing-service/pom.xml +++ b/licensing-service/pom.xml @@ -126,6 +126,14 @@ test + + com.github.codemonstur + embedded-redis + 1.4.3 + test + + + @@ -150,6 +158,20 @@ + + org.apache.maven.plugins + maven-failsafe-plugin + ${maven-failsafe-plugin.version} + + + + integration-test + verify + + + + + org.jacoco jacoco-maven-plugin @@ -161,6 +183,14 @@ prepare-agent + + + prepare-agent-integration + + prepare-agent-integration + + + report verify @@ -168,6 +198,14 @@ report + + + report-integration + verify + + report-integration + + diff --git a/licensing-service/src/test/java/io/github/bsayli/licensing/api/controller/LicenseControllerIT.java b/licensing-service/src/test/java/io/github/bsayli/licensing/api/controller/LicenseControllerIT.java new file mode 100644 index 0000000..875942e --- /dev/null +++ b/licensing-service/src/test/java/io/github/bsayli/licensing/api/controller/LicenseControllerIT.java @@ -0,0 +1,142 @@ +package io.github.bsayli.licensing.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.api.dto.IssueAccessRequest; +import io.github.bsayli.licensing.api.dto.LicenseAccessResponse; +import io.github.bsayli.licensing.api.dto.ValidateAccessRequest; +import io.github.bsayli.licensing.api.exception.LicenseControllerAdvice; +import io.github.bsayli.licensing.common.i18n.LocalizedMessageResolver; +import io.github.bsayli.licensing.service.LicenseOrchestrationService; +import io.github.bsayli.licensing.testconfig.TestControllerMocksConfig; +import io.github.bsayli.licensing.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.Import; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; + +@WebMvcTest(controllers = LicenseController.class) +@Import({ + LicenseControllerAdvice.class, + TestWebMvcSecurityConfig.class, + TestControllerMocksConfig.class +}) +@Tag("integration") +class LicenseControllerIT { + + @Autowired private MockMvc mvc; + @Autowired private ObjectMapper om; + @Autowired private LicenseOrchestrationService service; + @Autowired private LocalizedMessageResolver messageResolver; + + private static String fakeJwt() { + String p1 = "A".repeat(80); + String p2 = "b".repeat(80); + String p3 = "C".repeat(80); + return p1 + "." + p2 + "." + p3; + } + + @Test + @DisplayName("POST /v1/licenses/access -> 200 returns token") + void createAccess_ok() throws Exception { + var req = + new IssueAccessRequest( + "L".repeat(100) + "~rnd~" + "A".repeat(64), + "licensing-service~demo~00:11:22:33:44:55", + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8a5", + "crm", + "1.5.0", + "Q".repeat(60)); + + Mockito.when(service.issueAccess(req)).thenReturn(LicenseAccessResponse.created("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 createAccess_validationError() throws Exception { + var bad = new IssueAccessRequest("x", "short", null, "c", "1", "y"); + + 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()); + } + + @Test + @DisplayName("POST /v1/licenses/access/validate -> 200 returns refreshed token") + void validateAccess_ok_refreshed() throws Exception { + var req = + new ValidateAccessRequest( + "licensing-service~demo~00:11:22:33:44:55", + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8a5", + "crm", + "1.5.0", + "Q".repeat(60)); + + String jwt = fakeJwt(); + + Mockito.when(service.validateAccess(req, jwt)) + .thenReturn(LicenseAccessResponse.refreshed("new-jwt")); + Mockito.when(messageResolver.getMessage("license.validation.success")) + .thenReturn("License is valid"); + + mvc.perform( + post("/v1/licenses/access/validate") + .contentType(MediaType.APPLICATION_JSON) + .header("License-Token", jwt) + .content(om.writeValueAsBytes(req))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data.licenseToken").value("new-jwt")); + } + + @Test + @DisplayName("POST /v1/licenses/access/validate -> 400 invalid or missing header JWT") + void validateAccess_badHeader() throws Exception { + var req = + new ValidateAccessRequest( + "licensing-service~demo~00:11:22:33:44:55", null, "crm", "1.5.0", "Q".repeat(60)); + + // Missing header + mvc.perform( + post("/v1/licenses/access/validate") + .contentType(MediaType.APPLICATION_JSON) + .content(om.writeValueAsBytes(req))) + .andExpect(status().isBadRequest()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$.message").exists()) + .andExpect(jsonPath("$.errors").isArray()); + + // Not 3-part JWT + mvc.perform( + post("/v1/licenses/access/validate") + .contentType(MediaType.APPLICATION_JSON) + .header("License-Token", "abc.def") + .content(om.writeValueAsBytes(req))) + .andExpect(status().isBadRequest()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$.errors").isArray()); + } +} diff --git a/licensing-service/src/test/java/io/github/bsayli/licensing/cache/CacheConfigIT.java b/licensing-service/src/test/java/io/github/bsayli/licensing/cache/CacheConfigIT.java new file mode 100644 index 0000000..daa174e --- /dev/null +++ b/licensing-service/src/test/java/io/github/bsayli/licensing/cache/CacheConfigIT.java @@ -0,0 +1,118 @@ +package io.github.bsayli.licensing.cache; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.github.bsayli.licensing.LicensingServiceApplication; +import io.github.bsayli.licensing.testconfig.EmbeddedRedisConfig; +import java.time.Duration; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.TimeUnit; +import org.assertj.core.api.Assumptions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ActiveProfiles; + +@SpringBootTest( + classes = {LicensingServiceApplication.class, EmbeddedRedisConfig.class}, + webEnvironment = SpringBootTest.WebEnvironment.MOCK) +@ActiveProfiles("test") +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +@Tag("integration") +class CacheConfigIT { + + private static final String KEY_PREFIX = "it-key-"; + + @Autowired CacheManager cacheManager; + @Autowired StringRedisTemplate stringRedisTemplate; + @Autowired CacheProperties cacheProperties; + + @Test + @DisplayName("Configured caches are registered and usable with Redis TTL applied") + void cachesRegisteredAndWorkingWithTtl() throws Exception { + assertConfiguredCachesRegistered(); + + for (Map.Entry e : cacheProperties.caches().entrySet()) { + final String cacheName = e.getKey(); + final CacheProperties.CacheSpec spec = e.getValue(); + + Cache cache = cacheManager.getCache(cacheName); + assertThat(cache).as("cache bean should exist: %s", cacheName).isNotNull(); + + Optional sample = sampleInstance(spec.type()); + if (sample.isEmpty()) { + Assumptions.assumeThat(false) + .as( + "skip round-trip for cache %s (no suitable no-args type: %s)", + cacheName, spec.type()) + .isTrue(); + continue; + } + + String key = KEY_PREFIX + cacheName; + cache.put(key, sample.get()); + + Object readBack = cache.get(key, () -> null); + assertThat(readBack).as("value should be readable from cache %s", cacheName).isNotNull(); + + String redisKey = cacheName + "::" + key; + TimeUnit.MILLISECONDS.sleep(50); + + Long ttlSeconds = stringRedisTemplate.getExpire(redisKey); + assertThat(ttlSeconds) + .as("TTL should be set for key %s (cache %s)", redisKey, cacheName) + .isNotNull() + .isGreaterThan(0); + + long expectedUpperBound = expectedTtlSeconds(spec); + if (expectedUpperBound > 0) { + assertThat(ttlSeconds) + .as("TTL should not exceed configured TTL for cache %s", cacheName) + .isLessThanOrEqualTo(expectedUpperBound); + } + } + } + + private void assertConfiguredCachesRegistered() { + var expectedNames = cacheProperties.caches().keySet(); + assertThat(expectedNames).isNotEmpty(); + assertThat(cacheManager.getCacheNames()).containsExactlyInAnyOrderElementsOf(expectedNames); + } + + private Optional sampleInstance(String fqcn) { + try { + if (fqcn == null || fqcn.isBlank()) { + return Optional.of(new Object()); + } + Class type = Class.forName(fqcn); + var ctor = type.getDeclaredConstructor(); + ctor.setAccessible(true); + return Optional.of(ctor.newInstance()); + } catch (Throwable ignore) { + return Optional.empty(); + } + } + + private long expectedTtlSeconds(CacheProperties.CacheSpec spec) { + Duration ttl = null; + if (spec != null) { + if (spec.ttlMinutes() != null) ttl = Duration.ofMinutes(spec.ttlMinutes()); + else if (spec.ttlHours() != null) ttl = Duration.ofHours(spec.ttlHours()); + } + if (ttl == null && cacheProperties.defaultSpec() != null) { + var def = cacheProperties.defaultSpec(); + if (def.ttlMinutes() != null) ttl = Duration.ofMinutes(def.ttlMinutes()); + else if (def.ttlHours() != null) ttl = Duration.ofHours(def.ttlHours()); + } + return ttl == null ? -1 : ttl.getSeconds(); + } +} diff --git a/licensing-service/src/test/java/io/github/bsayli/licensing/service/jwt/impl/JwtServiceImplTest.java b/licensing-service/src/test/java/io/github/bsayli/licensing/service/jwt/impl/JwtServiceImplTest.java index efaf4a5..c05475e 100644 --- a/licensing-service/src/test/java/io/github/bsayli/licensing/service/jwt/impl/JwtServiceImplTest.java +++ b/licensing-service/src/test/java/io/github/bsayli/licensing/service/jwt/impl/JwtServiceImplTest.java @@ -34,7 +34,6 @@ private static String b64(byte[] in) { return Base64.getEncoder().encodeToString(in); } - /** Basit bir resolver: verilen anahtar için "msg-" + key döndürür. */ private static LocalizedMessageResolver dummyResolver() { return new LocalizedMessageResolver() { @Override @@ -67,7 +66,7 @@ private static JwtServiceImpl svc( b64(kp.getPublic().getEncoded()), ttl, jitterMax, - dummyResolver(), // <-- yeni parametre + dummyResolver(), clock, jitter::get, KeyFactory.getInstance("Ed25519")); @@ -90,7 +89,6 @@ void generate_and_verify_now() throws Exception { assertEquals("PRO", c.get("licenseTier")); assertEquals("ACTIVE", c.get("licenseStatus")); - // message claim: resolver "msg-license.message.active" döndürür assertEquals("msg-license.message.active", c.get("message")); assertEquals(now.getEpochSecond(), c.getIssuedAt().toInstant().getEpochSecond()); diff --git a/licensing-service/src/test/java/io/github/bsayli/licensing/testconfig/EmbeddedRedisConfig.java b/licensing-service/src/test/java/io/github/bsayli/licensing/testconfig/EmbeddedRedisConfig.java new file mode 100644 index 0000000..c8a6e27 --- /dev/null +++ b/licensing-service/src/test/java/io/github/bsayli/licensing/testconfig/EmbeddedRedisConfig.java @@ -0,0 +1,51 @@ +package io.github.bsayli.licensing.testconfig; + +import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; +import java.io.IOException; +import java.net.ServerSocket; +import org.springframework.context.annotation.Configuration; +import redis.embedded.RedisServer; + +@Configuration +public class EmbeddedRedisConfig { + + private final RedisProperties redisProperties; + private RedisServer redisServer; + + public EmbeddedRedisConfig(RedisProperties redisProperties) { + this.redisProperties = redisProperties; + } + + @PostConstruct + public void startRedis() throws IOException { + if (isPortAvailable(redisProperties.getRedisPort())) { + redisServer = new RedisServer(redisProperties.getRedisPort()); + redisServer.start(); + } else { + System.err.printf( + "Port %d is already in use. Skipping Redis start.%n", redisProperties.getRedisPort()); + } + } + + @PreDestroy + public void stopRedis() { + if (redisServer != null && redisServer.isActive()) { + try { + redisServer.stop(); + } catch (Exception e) { + System.err.printf("Embedded Redis shutdown failed: %s%n", e.getMessage()); + } finally { + redisServer = null; + } + } + } + + private boolean isPortAvailable(int port) { + try (ServerSocket ignored = new ServerSocket(port)) { + return true; + } catch (IOException e) { + return false; + } + } +} diff --git a/licensing-service/src/test/java/io/github/bsayli/licensing/testconfig/RedisProperties.java b/licensing-service/src/test/java/io/github/bsayli/licensing/testconfig/RedisProperties.java new file mode 100644 index 0000000..3cedfeb --- /dev/null +++ b/licensing-service/src/test/java/io/github/bsayli/licensing/testconfig/RedisProperties.java @@ -0,0 +1,26 @@ +package io.github.bsayli.licensing.testconfig; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class RedisProperties { + + private final int redisPort; + private final String redisHost; + + public RedisProperties( + @Value("${spring.data.redis.port}") int redisPort, + @Value("${spring.data.redis.host}") String redisHost) { + this.redisPort = redisPort; + this.redisHost = redisHost; + } + + public int getRedisPort() { + return redisPort; + } + + public String getRedisHost() { + return redisHost; + } +} diff --git a/licensing-service/src/test/java/io/github/bsayli/licensing/testconfig/TestControllerMocksConfig.java b/licensing-service/src/test/java/io/github/bsayli/licensing/testconfig/TestControllerMocksConfig.java new file mode 100644 index 0000000..bfe7e43 --- /dev/null +++ b/licensing-service/src/test/java/io/github/bsayli/licensing/testconfig/TestControllerMocksConfig.java @@ -0,0 +1,28 @@ +package io.github.bsayli.licensing.testconfig; + +import io.github.bsayli.licensing.common.i18n.LocalizedMessageResolver; +import io.github.bsayli.licensing.service.LicenseOrchestrationService; +import org.mockito.Mockito; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; + +@TestConfiguration +public class TestControllerMocksConfig { + + @Bean + public LicenseOrchestrationService licenseOrchestrationService() { + return Mockito.mock(LicenseOrchestrationService.class); + } + + @Bean + 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("Unexpected error"); + Mockito.when(mr.getMessage("request.header.missing", "License-Token")) + .thenReturn("Header 'License-Token' is missing"); + return mr; + } +} 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 new file mode 100644 index 0000000..6fa1c0a --- /dev/null +++ b/licensing-service/src/test/java/io/github/bsayli/licensing/testconfig/TestSecurityConfig.java @@ -0,0 +1,23 @@ +package io.github.bsayli.licensing.testconfig; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.web.SecurityFilterChain; + +@Configuration +@EnableWebSecurity +@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 diff --git a/licensing-service/src/test/java/io/github/bsayli/licensing/testconfig/TestWebMvcSecurityConfig.java b/licensing-service/src/test/java/io/github/bsayli/licensing/testconfig/TestWebMvcSecurityConfig.java new file mode 100644 index 0000000..9b01578 --- /dev/null +++ b/licensing-service/src/test/java/io/github/bsayli/licensing/testconfig/TestWebMvcSecurityConfig.java @@ -0,0 +1,18 @@ +package io.github.bsayli.licensing.testconfig; + +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +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 + SecurityFilterChain testSecurity(HttpSecurity http) throws Exception { + return http.csrf(AbstractHttpConfigurer::disable) + .authorizeHttpRequests(reg -> reg.anyRequest().permitAll()) + .build(); + } +} diff --git a/licensing-service/src/test/resources/application-test.yml b/licensing-service/src/test/resources/application-test.yml new file mode 100644 index 0000000..d4029af --- /dev/null +++ b/licensing-service/src/test/resources/application-test.yml @@ -0,0 +1,134 @@ +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 + + data: + redis: + host: localhost + port: 6370 + password: + timeout: 2s + client-type: lettuce + lettuce: + pool: + enabled: true + max-active: 2 + max-idle: 2 + min-idle: 0 + shutdown-timeout: 2s + +server: + port: 8085 + servlet: + context-path: /licensing-service + 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 + +management: + prometheus: + metrics: + export: + enabled: false + endpoints: + web: + exposure: + include: "health,info" + tracing: + enabled: false + +app: + openapi: + base-url: "http://localhost:${server.port}${server.servlet.context-path:}" + +cache: + default-spec: + ttl-minutes: 5 + caches: + userInfo: + ttl-minutes: 10 + type: io.github.bsayli.licensing.domain.model.LicenseInfo + userOfflineInfo: + ttl-minutes: 30 + type: io.github.bsayli.licensing.domain.model.LicenseInfo + activeClients: + ttl-minutes: 10 + type: io.github.bsayli.licensing.domain.model.ClientSessionSnapshot + +licensing: + api: + basic: + username: "testUser" + password: "testPass" + realm: "LicensingService-Test" + +license: + jwt: + private: + key: 'MFECAQEwBQYDK2VwBCIEIJa52B/FN/sjW/nlB9Id+Na2B8rI2+5ZPhXTIQSzH+3BgSEA6lNvY1+qsRSYgo66OFxWZxQymd2wC6LYNr1+q2gHHMo=' + public: + key: 'MCowBQYDK2VwAyEA6lNvY1+qsRSYgo66OFxWZxQymd2wC6LYNr1+q2gHHMo=' + service: + ids: [ crm, billing, reporting ] + checksum-required: [ crm, billing, reporting ] + +userid: + secret: + key: 's/PUyV6Ym/v0A+HehYFZ9GTpatSL1MkcVW1zBLf3cX4=' + +signature: + public: + key: 'MCowBQYDK2VwAyEAl/bnQXUbWqDOZYxCBd0mQ2JejBUWNteKhfC2zPS+GME=' + +keycloak: + server-url: http://localhost:8180 + realm: licensing-realm + client-id: licensing-service-client + client-secret: 'test-secret' + timeout: 5 + pool: + max-total: 5 + max-per-route: 2 + +retry: + user-service: + max-attempts: 1 + initial-delay: 200 + multiplier: 2 + max-delay: 1 + +jwt: + token: + expiration: 15m + max: + jitter: 1m + +async: + pool: + core: 2 + max: 4 + queue: 50 + threadNamePrefix: "LicenseService-Test-" \ No newline at end of file