File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
package kr.itn.itnhub.memo;
import kr.itn.itnhub.AbstractDbTest;
import kr.itn.itnhub.org.Organization;
import kr.itn.itnhub.org.OrganizationMapper;
import org.junit.jupiter.api.BeforeEach;
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.http.MediaType;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.test.context.support.WithAnonymousUser;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.web.servlet.MockMvc;
import static org.hamcrest.Matchers.containsString;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@AutoConfigureMockMvc
@WithMockUser(username = "admin", roles = "ADMIN")
class WorkMemoControllerTest extends AbstractDbTest {
@Autowired
MockMvc mvc;
@Autowired
OrganizationMapper orgMapper;
@Autowired
WorkMemoMapper memoMapper;
@Autowired
JdbcTemplate jdbc;
private Long orgId;
@BeforeEach
void setUp() {
jdbc.update("delete from work_memo");
jdbc.update("delete from organization");
Organization org = new Organization();
org.setOrgNo("001");
org.setOrgName("국제방송교류재단");
org.setChannelSlug("001");
orgMapper.upsertBySeed(org);
orgId = orgMapper.findAll().get(0).getId();
}
@Test
void 메모를_등록하면_생성된_메모를_돌려주고_목록에도_보인다() throws Exception {
mvc.perform(post("/api/orgs/{id}/memos", orgId)
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content("""
{
"body": "채널 생성 일정 문의"
}
"""))
.andExpect(status().isOk())
// 작성자는 요청 본문이 아니라 로그인 사용자에서 온다
.andExpect(jsonPath("$.contactName").value("admin"))
.andExpect(jsonPath("$.body").value("채널 생성 일정 문의"))
.andExpect(jsonPath("$.createdAt").isNumber());
mvc.perform(get("/api/orgs/{id}/memos", orgId))
.andExpect(status().isOk())
.andExpect(jsonPath("$[0].contactName").value("admin"))
.andExpect(jsonPath("$[0].body").value("채널 생성 일정 문의"));
}
@Test
void 목록은_최신순이다() throws Exception {
mvc.perform(post("/api/orgs/{id}/memos", orgId)
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content("""
{"body": "첫번째 통화"}
"""))
.andExpect(status().isOk());
mvc.perform(post("/api/orgs/{id}/memos", orgId)
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content("""
{"body": "두번째 통화"}
"""))
.andExpect(status().isOk());
mvc.perform(get("/api/orgs/{id}/memos", orgId))
.andExpect(status().isOk())
.andExpect(jsonPath("$[0].body").value("두번째 통화"))
.andExpect(jsonPath("$[1].body").value("첫번째 통화"));
}
@Test
void 메모_내용이_비면_400과_한글_메시지를_돌려준다() throws Exception {
mvc.perform(post("/api/orgs/{id}/memos", orgId)
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content("""
{"body": ""}
"""))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.message").value(containsString("메모 내용")));
}
@Test
void 존재하지_않는_기관이면_404다() throws Exception {
long missingId = orgId + 999999L;
mvc.perform(get("/api/orgs/{id}/memos", missingId))
.andExpect(status().isNotFound())
.andExpect(jsonPath("$.message").value(containsString(String.valueOf(missingId))));
}
@Test
void 메모를_삭제하면_204와_함께_목록에서_사라진다() throws Exception {
mvc.perform(post("/api/orgs/{id}/memos", orgId)
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content("""
{"body": "삭제될 메모"}
"""))
.andExpect(status().isOk());
Long memoId = memoMapper.findByOrg(orgId).get(0).getId();
mvc.perform(delete("/api/orgs/{id}/memos/{memoId}", orgId, memoId).with(csrf()))
.andExpect(status().isNoContent());
mvc.perform(get("/api/orgs/{id}/memos", orgId))
.andExpect(status().isOk())
.andExpect(jsonPath("$").isEmpty());
}
@Test
void 다른_기관_경로로_삭제하면_404다() throws Exception {
mvc.perform(post("/api/orgs/{id}/memos", orgId)
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content("""
{"body": "삭제될 메모"}
"""))
.andExpect(status().isOk());
Long memoId = memoMapper.findByOrg(orgId).get(0).getId();
Organization other = new Organization();
other.setOrgNo("002");
other.setOrgName("다른기관");
other.setChannelSlug("002");
orgMapper.upsertBySeed(other);
Long otherOrgId = orgMapper.findAll().stream()
.filter(o -> o.getOrgNo().equals("002"))
.findFirst().get().getId();
mvc.perform(delete("/api/orgs/{id}/memos/{memoId}", otherOrgId, memoId).with(csrf()))
.andExpect(status().isNotFound());
}
@Test
@WithAnonymousUser
void 인증없이_호출하면_401이다() throws Exception {
mvc.perform(get("/api/orgs/{id}/memos", orgId))
.andExpect(status().isUnauthorized());
}
@Test
void 메모를_수정하면_본문만_바뀌고_작성자와_작성시각은_그대로다() throws Exception {
String created = mvc.perform(post("/api/orgs/{id}/memos", orgId)
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content("""
{"body": "고치기 전"}
"""))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString();
long memoId = com.jayway.jsonpath.JsonPath.parse(created).read("$.id", Integer.class);
long createdAt = com.jayway.jsonpath.JsonPath.parse(created).read("$.createdAt", Long.class);
mvc.perform(put("/api/orgs/{id}/memos/{memoId}", orgId, memoId)
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content("""
{"body": "고친 뒤"}
"""))
.andExpect(status().isOk())
.andExpect(jsonPath("$.body").value("고친 뒤"))
.andExpect(jsonPath("$.contactName").value("admin"))
.andExpect(jsonPath("$.createdAt").value(createdAt));
}
@Test
void 없는_메모를_수정하면_404다() throws Exception {
mvc.perform(put("/api/orgs/{id}/memos/{memoId}", orgId, 999999L)
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content("""
{"body": "아무거나"}
"""))
.andExpect(status().isNotFound());
}
@Test
void 본문이_비면_수정도_400이다() throws Exception {
mvc.perform(put("/api/orgs/{id}/memos/{memoId}", orgId, 1L)
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content("""
{"body": ""}
"""))
.andExpect(status().isBadRequest());
}
}