From 9954600650c3e7cd40a5f4fa55bc38595973f214 Mon Sep 17 00:00:00 2001 From: Zhang Shun Date: Fri, 18 Sep 2026 10:09:05 +0800 Subject: [PATCH] test: isolate review controller authentication fixtures --- .../review/AdminReviewControllerTest.java | 19 +++- ...CompanyReviewManagementControllerTest.java | 31 ++++++- .../ReviewControllerFixtureIsolationTest.java | 91 +++++++++++++++++++ .../review/ReviewControllerFixtureUsers.java | 24 +++++ 4 files changed, 159 insertions(+), 6 deletions(-) create mode 100644 mydreamjob-server/src/test/java/com/mydreamjob/review/ReviewControllerFixtureIsolationTest.java create mode 100644 mydreamjob-server/src/test/java/com/mydreamjob/review/ReviewControllerFixtureUsers.java diff --git a/mydreamjob-server/src/test/java/com/mydreamjob/review/AdminReviewControllerTest.java b/mydreamjob-server/src/test/java/com/mydreamjob/review/AdminReviewControllerTest.java index 5756220..f93fa99 100644 --- a/mydreamjob-server/src/test/java/com/mydreamjob/review/AdminReviewControllerTest.java +++ b/mydreamjob-server/src/test/java/com/mydreamjob/review/AdminReviewControllerTest.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.mydreamjob.common.exception.BusinessException; import com.mydreamjob.common.exception.ErrorCode; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; @@ -16,6 +17,7 @@ import org.springframework.data.domain.PageRequest; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ValueOperations; import org.springframework.http.MediaType; +import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.web.servlet.MockMvc; @@ -41,23 +43,36 @@ class AdminReviewControllerTest { @Autowired private MockMvc mockMvc; @Autowired private com.mydreamjob.auth.JwtTokenProvider jwtTokenProvider; + @Autowired private JdbcTemplate jdbcTemplate; @MockBean private JobReviewService reviewService; @MockBean private RedisTemplate redisTemplate; private final ObjectMapper mapper = new ObjectMapper(); - private static final Long ADMIN_ID = 1L; - private static final Long STUDENT_ID = 100L; + static final Long ADMIN_ID = 9_320_001L; + static final Long STUDENT_ID = 9_320_002L; private static final Long REVIEW_ID = 1L; @BeforeEach @SuppressWarnings("unchecked") void setUp() { + removeFixtureUsers(); + ReviewControllerFixtureUsers.provision(jdbcTemplate, ADMIN_ID, "r01b-ar-admin", "ADMIN"); + ReviewControllerFixtureUsers.provision(jdbcTemplate, STUDENT_ID, "r01b-ar-student", "STUDENT"); ValueOperations ops = mock(ValueOperations.class); when(redisTemplate.opsForValue()).thenReturn(ops); when(redisTemplate.hasKey(any())).thenReturn(false); } + @AfterEach + void tearDown() { + removeFixtureUsers(); + } + + private void removeFixtureUsers() { + ReviewControllerFixtureUsers.remove(jdbcTemplate, ADMIN_ID, STUDENT_ID); + } + private String adminToken() { return com.mydreamjob.auth.support.TestAuthTokens.bearer(ADMIN_ID, "ADMIN"); } diff --git a/mydreamjob-server/src/test/java/com/mydreamjob/review/CompanyReviewManagementControllerTest.java b/mydreamjob-server/src/test/java/com/mydreamjob/review/CompanyReviewManagementControllerTest.java index 83bb7ba..9f1aaad 100644 --- a/mydreamjob-server/src/test/java/com/mydreamjob/review/CompanyReviewManagementControllerTest.java +++ b/mydreamjob-server/src/test/java/com/mydreamjob/review/CompanyReviewManagementControllerTest.java @@ -5,11 +5,14 @@ import com.mydreamjob.common.exception.ErrorCode; import com.mydreamjob.auth.JwtTokenProvider; import com.mydreamjob.review.dto.ReviewReplyPageResponse; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.AfterEach; 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.web.servlet.MockMvc; @@ -28,10 +31,30 @@ class CompanyReviewManagementControllerTest { @Autowired private MockMvc mockMvc; @Autowired private JwtTokenProvider jwtTokenProvider; + @Autowired private JdbcTemplate jdbcTemplate; @MockBean private CompanyReviewManagementService managementService; @MockBean private CompanyReviewReplyService replyService; @MockBean private RedisTemplate redisTemplate; + static final long COMPANY_USER_ID = 9_320_011L; + static final long STUDENT_USER_ID = 9_320_012L; + + @BeforeEach + void setUpFixtureUsers() { + removeFixtureUsers(); + ReviewControllerFixtureUsers.provision(jdbcTemplate, COMPANY_USER_ID, "r01b-cr-company", "COMPANY"); + ReviewControllerFixtureUsers.provision(jdbcTemplate, STUDENT_USER_ID, "r01b-cr-student", "STUDENT"); + } + + @AfterEach + void tearDownFixtureUsers() { + removeFixtureUsers(); + } + + private void removeFixtureUsers() { + ReviewControllerFixtureUsers.remove(jdbcTemplate, COMPANY_USER_ID, STUDENT_USER_ID); + } + private String token(long id, String role) { return com.mydreamjob.auth.support.TestAuthTokens.bearer(id, role); } @@ -44,18 +67,18 @@ class CompanyReviewManagementControllerTest { @Test void studentCannotAccessCompanyReviews() throws Exception { - when(managementService.listMine(eq(2L), any(), any(), any(), any(), any(), any(), eq(0), eq(20))) + when(managementService.listMine(eq(STUDENT_USER_ID), any(), any(), any(), any(), any(), any(), eq(0), eq(20))) .thenThrow(new BusinessException(ErrorCode.FORBIDDEN)); - mockMvc.perform(get("/companies/me/job-reviews").header("Authorization", token(2L, "STUDENT"))) + mockMvc.perform(get("/companies/me/job-reviews").header("Authorization", token(STUDENT_USER_ID, "STUDENT"))) .andExpect(status().isForbidden()); } @Test void companyCanListItsReviews() throws Exception { - when(managementService.listMine(eq(1L), any(), any(), any(), any(), any(), any(), eq(0), eq(20))) + when(managementService.listMine(eq(COMPANY_USER_ID), any(), any(), any(), any(), any(), any(), eq(0), eq(20))) .thenReturn(ReviewReplyPageResponse.builder().items(java.util.List.of()).total(0) .page(0).size(20).totalPages(0).build()); - mockMvc.perform(get("/companies/me/job-reviews").header("Authorization", token(1L, "COMPANY"))) + mockMvc.perform(get("/companies/me/job-reviews").header("Authorization", token(COMPANY_USER_ID, "COMPANY"))) .andExpect(status().isOk()); } } diff --git a/mydreamjob-server/src/test/java/com/mydreamjob/review/ReviewControllerFixtureIsolationTest.java b/mydreamjob-server/src/test/java/com/mydreamjob/review/ReviewControllerFixtureIsolationTest.java new file mode 100644 index 0000000..ea070b9 --- /dev/null +++ b/mydreamjob-server/src/test/java/com/mydreamjob/review/ReviewControllerFixtureIsolationTest.java @@ -0,0 +1,91 @@ +package com.mydreamjob.review; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +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 java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest +@ActiveProfiles("integration-test") +class ReviewControllerFixtureIsolationTest { + + private static final long SENTINEL_ID = 9_320_099L; + private static final long PROBE_ID = 9_320_098L; + + @Autowired private JdbcTemplate jdbcTemplate; + @MockBean private RedisTemplate redisTemplate; + + @AfterEach + void cleanup() { + ReviewControllerFixtureUsers.remove(jdbcTemplate, + AdminReviewControllerTest.ADMIN_ID, + AdminReviewControllerTest.STUDENT_ID, + CompanyReviewManagementControllerTest.COMPANY_USER_ID, + CompanyReviewManagementControllerTest.STUDENT_USER_ID, + SENTINEL_ID, PROBE_ID); + } + + @Test + void fixtureIdsAreOutsideLegacySeedRangeAndMutuallyDistinct() { + List ids = List.of( + AdminReviewControllerTest.ADMIN_ID, + AdminReviewControllerTest.STUDENT_ID, + CompanyReviewManagementControllerTest.COMPANY_USER_ID, + CompanyReviewManagementControllerTest.STUDENT_USER_ID); + + assertThat(ids).doesNotContain(1L, 2L, 3L).doesNotHaveDuplicates(); + } + + @Test + void provisionCreatesAnActiveVerifiedUserAndCanBeRepeated() { + for (int round = 0; round < 3; round++) { + ReviewControllerFixtureUsers.provision(jdbcTemplate, PROBE_ID, "r01b-review-probe", "ADMIN"); + } + + Map row = jdbcTemplate.queryForMap( + "SELECT id, role, is_active, is_verified FROM users WHERE id = ?", PROBE_ID); + assertThat(((Number) row.get("id")).longValue()).isEqualTo(PROBE_ID); + assertThat(row.get("role")).isEqualTo("ADMIN"); + assertThat(((Number) row.get("is_active")).intValue()).isEqualTo(1); + assertThat(((Number) row.get("is_verified")).intValue()).isEqualTo(1); + } + + @Test + void cleanupRemovesOnlyOwnedRows() { + ReviewControllerFixtureUsers.provision(jdbcTemplate, PROBE_ID, "r01b-review-probe", "ADMIN"); + ReviewControllerFixtureUsers.provision(jdbcTemplate, SENTINEL_ID, "r01b-review-sentinel", "STUDENT"); + + ReviewControllerFixtureUsers.remove(jdbcTemplate, PROBE_ID); + + assertThat(countUser(PROBE_ID)).isZero(); + assertThat(countUser(SENTINEL_ID)).isEqualTo(1); + } + + @Test + void fixtureCycleLeavesLegacySeedRowsUnchanged() { + List> before = seedRows(); + + ReviewControllerFixtureUsers.provision(jdbcTemplate, PROBE_ID, "r01b-review-probe", "ADMIN"); + ReviewControllerFixtureUsers.remove(jdbcTemplate, PROBE_ID); + + assertThat(seedRows()).isEqualTo(before); + } + + private int countUser(long id) { + return jdbcTemplate.queryForObject("SELECT COUNT(*) FROM users WHERE id = ?", Integer.class, id); + } + + private List> seedRows() { + return jdbcTemplate.queryForList( + "SELECT id, phone, role, is_active, is_verified FROM users WHERE id IN (1, 2, 3) ORDER BY id"); + } +} diff --git a/mydreamjob-server/src/test/java/com/mydreamjob/review/ReviewControllerFixtureUsers.java b/mydreamjob-server/src/test/java/com/mydreamjob/review/ReviewControllerFixtureUsers.java new file mode 100644 index 0000000..868bd01 --- /dev/null +++ b/mydreamjob-server/src/test/java/com/mydreamjob/review/ReviewControllerFixtureUsers.java @@ -0,0 +1,24 @@ +package com.mydreamjob.review; + +import org.springframework.jdbc.core.JdbcTemplate; + +/** Test-only fixture helper that creates and removes only explicitly owned users. */ +final class ReviewControllerFixtureUsers { + + private ReviewControllerFixtureUsers() { + } + + static void provision(JdbcTemplate jdbcTemplate, long id, String phone, String role) { + remove(jdbcTemplate, id); + jdbcTemplate.update("INSERT INTO users (id, phone, nickname, role, is_active, is_verified) " + + "VALUES (?, ?, ?, ?, 1, 1)", id, phone, "r01b-review-fixture-" + role, role); + } + + static void remove(JdbcTemplate jdbcTemplate, long... ids) { + for (long id : ids) { + jdbcTemplate.update("DELETE FROM auth_tokens WHERE user_id = ?", id); + jdbcTemplate.update("DELETE FROM user_roles WHERE user_id = ?", id); + jdbcTemplate.update("DELETE FROM users WHERE id = ?", id); + } + } +}