You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

85 lines
4.7 KiB

package com.mydreamjob.integration;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashSet;
import java.util.Set;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.data.redis.core.RedisTemplate;
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.springframework.test.web.servlet.MockMvc;
import org.testcontainers.containers.MySQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/** 合并后的真实 MySQL 迁移、实体校验及运行时接口集合门禁。 */
@Testcontainers(disabledWithoutDocker = false)
@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("mysql-it")
class LxqModulesMySqlIntegrationTest {
@Container static final MySQLContainer<?> MYSQL = new MySQLContainer<>("mysql:8.4")
.withDatabaseName("lxq_module_integration")
.withUsername("module_test").withPassword("module-test-only");
@DynamicPropertySource static void properties(DynamicPropertyRegistry r) {
r.add("spring.datasource.url", MYSQL::getJdbcUrl);
r.add("spring.datasource.username", MYSQL::getUsername);
r.add("spring.datasource.password", MYSQL::getPassword);
}
@MockBean RedisTemplate<String, Object> redis;
@Autowired JdbcTemplate jdbc;
@Autowired MockMvc mvc;
@Autowired ObjectMapper mapper;
@Test void migrationsAndSeedsAreRealAndComplete() {
assertThat(jdbc.queryForObject("select count(*) from flyway_schema_history where success=0", Long.class)).isZero();
assertThat(jdbc.queryForObject("select count(*) from flyway_schema_history where version in ('47','48','49','50','51','52','53') and success=1", Long.class)).isEqualTo(7);
for (String table : Set.of("skills", "skill_industries", "skill_occupations", "occupation_skills",
"onboarding_checklist_items", "salary_city_policy")) {
assertThat(jdbc.queryForObject("select count(*) from " + table, Long.class)).as(table).isPositive();
}
for (String table : Set.of("student_onboarding_progress", "company_knowledge", "salary_calculation_history")) {
assertThat(jdbc.queryForObject("select count(*) from " + table, Long.class)).as(table).isZero();
}
}
@Test void runtimeAndStaticOperationsAreIdentical() throws Exception {
JsonNode runtime = mapper.readTree(mvc.perform(get("/v3/api-docs"))
.andExpect(status().isOk()).andReturn().getResponse().getContentAsByteArray());
JsonNode contract = mapper.readTree(Files.readString(Path.of("../docs/openapi-rc.json")));
assertThat(operations(runtime)).hasSize(259).isEqualTo(operations(contract));
assertThat(runtime.path("paths").size()).isEqualTo(211);
assertThat(runtime.path("paths").path("/conversations/{id}/events"))
.isEqualTo(contract.path("paths").path("/conversations/{id}/events"));
for (String field : Set.of("clientMessageId", "version")) {
String pointer = "/components/schemas/MessageResponse/properties/" + field;
assertThat(runtime.at(pointer).isMissingNode()).as(pointer).isFalse();
assertThat(contract.at(pointer)).as(pointer).isEqualTo(runtime.at(pointer));
}
String requestField = "/components/schemas/SendMessageRequest/properties/clientMessageId";
assertThat(runtime.at(requestField).isMissingNode()).isFalse();
assertThat(contract.at(requestField)).isEqualTo(runtime.at(requestField));
}
private Set<String> operations(JsonNode document) {
Set<String> result = new HashSet<>();
document.path("paths").fields().forEachRemaining(path ->
path.getValue().fieldNames().forEachRemaining(method -> {
if (Set.of("get", "post", "put", "patch", "delete", "head", "options", "trace").contains(method))
result.add(method + " " + path.getKey());
}));
return result;
}
}