2026-03-11 11:53:31 +01:00
|
|
|
package com.cameleer3.server.app;
|
|
|
|
|
|
|
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
|
import org.springframework.boot.test.context.SpringBootTest;
|
|
|
|
|
import org.springframework.jdbc.core.JdbcTemplate;
|
|
|
|
|
import org.springframework.test.context.ActiveProfiles;
|
|
|
|
|
import org.springframework.test.context.DynamicPropertyRegistry;
|
|
|
|
|
import org.springframework.test.context.DynamicPropertySource;
|
|
|
|
|
import org.testcontainers.clickhouse.ClickHouseContainer;
|
|
|
|
|
|
|
|
|
|
import org.junit.jupiter.api.BeforeAll;
|
|
|
|
|
|
|
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
|
|
import java.nio.file.Files;
|
|
|
|
|
import java.nio.file.Path;
|
|
|
|
|
import java.sql.Connection;
|
|
|
|
|
import java.sql.DriverManager;
|
|
|
|
|
import java.sql.Statement;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Base class for integration tests requiring a ClickHouse instance.
|
|
|
|
|
* <p>
|
|
|
|
|
* Uses Testcontainers to spin up a ClickHouse server and initializes the schema
|
|
|
|
|
* from {@code clickhouse/init/01-schema.sql} before the first test runs.
|
|
|
|
|
* Subclasses get a {@link JdbcTemplate} for direct database assertions.
|
test(01-03): add integration tests for health, OpenAPI, protocol version, forward compat, and TTL
- HealthControllerIT: health returns 200, no protocol header needed, TTL verified
- OpenApiIT: api-docs returns OpenAPI spec, swagger UI accessible
- ProtocolVersionIT: missing/wrong header returns 400, correct header passes, excluded paths work
- ForwardCompatIT: unknown JSON fields do not cause deserialization errors
- Fix testcontainers version to 2.0.3 (docker-java 3.7.0 for Docker Desktop 29.x compat)
- Fix ClickHouse schema: TTL with toDateTime() cast, non-nullable error columns for tokenbf_v1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 12:03:00 +01:00
|
|
|
* <p>
|
|
|
|
|
* Container lifecycle is managed manually (started once, shared across all test classes).
|
2026-03-11 11:53:31 +01:00
|
|
|
*/
|
|
|
|
|
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
|
|
|
|
@ActiveProfiles("test")
|
|
|
|
|
public abstract class AbstractClickHouseIT {
|
|
|
|
|
|
test(01-03): add integration tests for health, OpenAPI, protocol version, forward compat, and TTL
- HealthControllerIT: health returns 200, no protocol header needed, TTL verified
- OpenApiIT: api-docs returns OpenAPI spec, swagger UI accessible
- ProtocolVersionIT: missing/wrong header returns 400, correct header passes, excluded paths work
- ForwardCompatIT: unknown JSON fields do not cause deserialization errors
- Fix testcontainers version to 2.0.3 (docker-java 3.7.0 for Docker Desktop 29.x compat)
- Fix ClickHouse schema: TTL with toDateTime() cast, non-nullable error columns for tokenbf_v1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 12:03:00 +01:00
|
|
|
protected static final ClickHouseContainer CLICKHOUSE;
|
|
|
|
|
|
|
|
|
|
static {
|
|
|
|
|
CLICKHOUSE = new ClickHouseContainer("clickhouse/clickhouse-server:25.3");
|
|
|
|
|
CLICKHOUSE.start();
|
|
|
|
|
}
|
2026-03-11 11:53:31 +01:00
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
|
protected JdbcTemplate jdbcTemplate;
|
|
|
|
|
|
|
|
|
|
@DynamicPropertySource
|
|
|
|
|
static void overrideProperties(DynamicPropertyRegistry registry) {
|
|
|
|
|
registry.add("spring.datasource.url", CLICKHOUSE::getJdbcUrl);
|
|
|
|
|
registry.add("spring.datasource.username", CLICKHOUSE::getUsername);
|
|
|
|
|
registry.add("spring.datasource.password", CLICKHOUSE::getPassword);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@BeforeAll
|
|
|
|
|
static void initSchema() throws Exception {
|
test(01-03): add integration tests for health, OpenAPI, protocol version, forward compat, and TTL
- HealthControllerIT: health returns 200, no protocol header needed, TTL verified
- OpenApiIT: api-docs returns OpenAPI spec, swagger UI accessible
- ProtocolVersionIT: missing/wrong header returns 400, correct header passes, excluded paths work
- ForwardCompatIT: unknown JSON fields do not cause deserialization errors
- Fix testcontainers version to 2.0.3 (docker-java 3.7.0 for Docker Desktop 29.x compat)
- Fix ClickHouse schema: TTL with toDateTime() cast, non-nullable error columns for tokenbf_v1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 12:03:00 +01:00
|
|
|
// Surefire runs from the module directory; schema is in the project root
|
2026-03-11 16:09:45 +01:00
|
|
|
Path baseDir = Path.of("clickhouse/init");
|
|
|
|
|
if (!Files.exists(baseDir)) {
|
|
|
|
|
baseDir = Path.of("../clickhouse/init");
|
test(01-03): add integration tests for health, OpenAPI, protocol version, forward compat, and TTL
- HealthControllerIT: health returns 200, no protocol header needed, TTL verified
- OpenApiIT: api-docs returns OpenAPI spec, swagger UI accessible
- ProtocolVersionIT: missing/wrong header returns 400, correct header passes, excluded paths work
- ForwardCompatIT: unknown JSON fields do not cause deserialization errors
- Fix testcontainers version to 2.0.3 (docker-java 3.7.0 for Docker Desktop 29.x compat)
- Fix ClickHouse schema: TTL with toDateTime() cast, non-nullable error columns for tokenbf_v1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 12:03:00 +01:00
|
|
|
}
|
2026-03-11 16:09:45 +01:00
|
|
|
|
|
|
|
|
// Load all schema files in order
|
|
|
|
|
String[] schemaFiles = {"01-schema.sql", "02-search-columns.sql"};
|
2026-03-11 11:53:31 +01:00
|
|
|
|
|
|
|
|
try (Connection conn = DriverManager.getConnection(
|
|
|
|
|
CLICKHOUSE.getJdbcUrl(),
|
|
|
|
|
CLICKHOUSE.getUsername(),
|
|
|
|
|
CLICKHOUSE.getPassword());
|
|
|
|
|
Statement stmt = conn.createStatement()) {
|
2026-03-11 16:09:45 +01:00
|
|
|
|
|
|
|
|
for (String schemaFile : schemaFiles) {
|
|
|
|
|
Path schemaPath = baseDir.resolve(schemaFile);
|
|
|
|
|
if (Files.exists(schemaPath)) {
|
|
|
|
|
String sql = Files.readString(schemaPath, StandardCharsets.UTF_8);
|
|
|
|
|
// Execute each statement separately (separated by semicolons)
|
|
|
|
|
for (String statement : sql.split(";")) {
|
|
|
|
|
String trimmed = statement.trim();
|
|
|
|
|
if (!trimmed.isEmpty()) {
|
|
|
|
|
stmt.execute(trimmed);
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-03-11 11:53:31 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|