Skip to content

Commit

Permalink
Fix: 허브 태그 자동 생성 조건을 수정한다.
Browse files Browse the repository at this point in the history
Fix: 허브 태그 자동 생성 조건을 수정한다.
  • Loading branch information
hseong3243 authored Apr 9, 2024
2 parents 80721cf + 87b59a0 commit 862c619
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 20 deletions.
14 changes: 12 additions & 2 deletions src/main/java/com/seong/shoutlink/domain/tag/Tag.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
package com.seong.shoutlink.domain.tag;

import java.time.LocalDateTime;
import lombok.Getter;

@Getter
public class Tag {

private Long tagId;
private String name;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;

public Tag(String name) {
this(null, name);
this(null, name, null, null);
}

public Tag(Long tagId, String name) {
public Tag(Long tagId, String name, LocalDateTime createdAt, LocalDateTime updatedAt) {
this.tagId = tagId;
this.name = name;
this.createdAt = createdAt;
this.updatedAt = updatedAt;
}

public boolean isCreatedWithinADay() {
LocalDateTime aDayAgo = LocalDateTime.now().minusDays(1);
return createdAt.isAfter(aDayAgo);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,6 @@ public static TagEntity from(HubTag hubTag) {
}

public Tag toDomain() {
return new Tag(tagId, name);
return new Tag(tagId, name, getCreatedAt(), getUpdatedAt());
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.seong.shoutlink.domain.tag.repository;

import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
Expand All @@ -8,4 +9,10 @@ public interface TagJpaRepository extends JpaRepository<TagEntity, Long> {

@Query("delete from HubTagEntity t where t.hubId=:hubId")
long deleteByHubId(@Param("hubId") Long hubId);

@Query("select t from HubTagEntity t"
+ " where t.hubId=:hubId"
+ " order by t.createdAt"
+ " limit 1")
Optional<TagEntity> findLatestTagByHubId(Long hubId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.seong.shoutlink.domain.tag.Tag;
import com.seong.shoutlink.domain.tag.service.TagRepository;
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

Expand All @@ -28,4 +29,10 @@ public List<Tag> saveAll(List<HubTag> tags) {
public long deleteHubTags(Hub hub) {
return tagJpaRepository.deleteByHubId(hub.getHubId());
}

@Override
public Optional<Tag> findLatestTagByHub(Hub hub) {
return tagJpaRepository.findLatestTagByHubId(hub.getHubId())
.map(TagEntity::toDomain);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@
import com.seong.shoutlink.domain.tag.HubTag;
import com.seong.shoutlink.domain.tag.Tag;
import java.util.List;
import java.util.Optional;

public interface TagRepository {

List<Tag> saveAll(List<HubTag> tags);

long deleteHubTags(Hub hub);

Optional<Tag> findLatestTagByHub(Hub hub);
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class TagService {

private static final int MINIMUM_TAG_CONDITION = 5;
private static final int MAXIMUM_TAG_COUNT = 5;
private static final int ZERO = 0;

private final TagRepository tagRepository;
private final HubRepository hubRepository;
Expand All @@ -37,9 +38,9 @@ public class TagService {
@Transactional
public CreateTagResponse autoCreateHubTags(AutoCreateTagCommand command) {
Hub hub = getHub(command.hubId());
checkTagIsCreatedWithinADay(hub);
List<LinkBundle> hubLinkBundles = linkBundleRepository.findHubLinkBundles(hub);
List<LinkWithLinkBundle> links = linkRepository.findAllByLinkBundlesIn(
hubLinkBundles);
List<LinkWithLinkBundle> links = linkRepository.findAllByLinkBundlesIn(hubLinkBundles);

List<LinkBundleAndLinks> linkBundlesAndLinks = groupingLinks(links);
int generateTagCount = calculateNumberOfTag(links);
Expand All @@ -51,12 +52,19 @@ public CreateTagResponse autoCreateHubTags(AutoCreateTagCommand command) {
.map(generatedTag -> new Tag(generatedTag.name()))
.map(tag -> new HubTag(hub, tag))
.toList();
if(!hubTags.isEmpty()) {
if (!hubTags.isEmpty()) {
tagRepository.deleteHubTags(hub);
}
return CreateTagResponse.from(tagRepository.saveAll(hubTags));
}

private void checkTagIsCreatedWithinADay(Hub hub) {
tagRepository.findLatestTagByHub(hub)
.filter(Tag::isCreatedWithinADay)
.ifPresent(tag -> {
throw new ShoutLinkException("태그 생성된 지 하루가 지나지 않았습니다.", ErrorCode.NOT_MET_CONDITION);});
}

private List<LinkBundleAndLinks> groupingLinks(List<LinkWithLinkBundle> links) {
return links.stream()
.collect(groupingBy(
Expand All @@ -69,7 +77,8 @@ private List<LinkBundleAndLinks> groupingLinks(List<LinkWithLinkBundle> links) {

private int calculateNumberOfTag(List<LinkWithLinkBundle> links) {
int totalLinkCount = links.size();
if (totalLinkCount < MINIMUM_TAG_CONDITION) {
if (totalLinkCount < MINIMUM_TAG_CONDITION
|| totalLinkCount % MINIMUM_TAG_CONDITION != ZERO) {
throw new ShoutLinkException("태그 생성 조건을 충족하지 못했습니다.", ErrorCode.NOT_MET_CONDITION);
}
return Math.min(MAXIMUM_TAG_COUNT, totalLinkCount / MINIMUM_TAG_CONDITION);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public class StubTagRepository implements TagRepository {

Expand All @@ -33,7 +34,7 @@ public List<Tag> saveAll(List<HubTag> hubTags) {
}
return memory.entrySet().stream().map(entry -> {
Tag value = entry.getValue();
return new Tag(entry.getKey(), value.getName());
return new Tag(entry.getKey(), value.getName(), value.getCreatedAt(), value.getUpdatedAt());
}).toList();
}

Expand All @@ -43,4 +44,9 @@ public long deleteHubTags(Hub hub) {
memory.clear();
return size;
}

@Override
public Optional<Tag> findLatestTagByHub(Hub hub) {
return memory.values().stream().findFirst();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.seong.shoutlink.domain.link.Link;
import com.seong.shoutlink.domain.link.repository.FakeLinkRepository;
import com.seong.shoutlink.domain.linkbundle.repository.FakeLinkBundleRepository;
import com.seong.shoutlink.domain.tag.Tag;
import com.seong.shoutlink.domain.tag.repository.StubTagRepository;
import com.seong.shoutlink.domain.tag.service.request.AutoCreateTagCommand;
import com.seong.shoutlink.domain.tag.service.response.CreateTagResponse;
Expand All @@ -22,10 +23,13 @@
import com.seong.shoutlink.fixture.TagFixture;
import com.seong.shoutlink.global.client.StubApiClient;
import com.seong.shoutlink.global.client.ai.GeminiClient;
import java.time.LocalDateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

class TagServiceTest {

Expand Down Expand Up @@ -60,15 +64,16 @@ void setUp() {
linkRepository, autoGenerativeClient);
}

@Test
@DisplayName("성공: 링크가 5개 이상인 경우 자동 태그 생성한다.")
void autoCreateTag() {
@ParameterizedTest
@CsvSource({"5", "10", "15", "20", "25"})
@DisplayName("성공: 링크가 5의 배수인 경우 자동 태그 생성한다.")
void autoCreateTag(int totalLinkSize) {
//given
AutoCreateTagCommand command = new AutoCreateTagCommand(1L);

hubRepository.stub(HubFixture.hub(MemberFixture.member()));
linkBundleRepository.stub(LinkBundleFixture.linkBundle());
linkRepository.stub(LinkFixture.links(5).toArray(Link[]::new));
linkRepository.stub(LinkFixture.links(totalLinkSize).toArray(Link[]::new));

//when
CreateTagResponse response = tagService.autoCreateHubTags(command);
Expand Down Expand Up @@ -96,14 +101,50 @@ void thenDeleteOldTags() {
}

@Test
@DisplayName("예외(notFound): 존재하지 않는 허브인 경우")
void notFound_WhenHubNotFound() {
//given
AutoCreateTagCommand command = new AutoCreateTagCommand(1L);

//when
Exception exception = catchException(() -> tagService.autoCreateHubTags(command));

//then
assertThat(exception).isInstanceOf(ShoutLinkException.class)
.extracting(e -> ((ShoutLinkException) e).getErrorCode())
.isEqualTo(ErrorCode.NOT_FOUND);
}

@Test
@DisplayName("예외(notMetCondition): 하루 안에 생성된 태그가 존재하는 경우")
void notMetCondition_WhenLatestTagCreatedWithinADay() {
//given
AutoCreateTagCommand command = new AutoCreateTagCommand(1L);
LocalDateTime createdWithinADay = LocalDateTime.now().minusHours(23);
Tag tag = new Tag(1L, "태그", createdWithinADay, createdWithinADay);

hubRepository.stub(HubFixture.hub(MemberFixture.member()));
tagRepository.stub(tag);

//when
Exception exception = catchException(() -> tagService.autoCreateHubTags(command));

//then
assertThat(exception).isInstanceOf(ShoutLinkException.class)
.extracting(e -> ((ShoutLinkException) e).getErrorCode())
.isEqualTo(ErrorCode.NOT_MET_CONDITION);
}

@ParameterizedTest
@CsvSource({"0","1","2","3","4"})
@DisplayName("예외(notMetCondition): 링크가 5개 미만인 경우")
void notMetCondition_WhenTotalLinkCountLT5() {
void notMetCondition_WhenTotalLinkCountLT5(int totalLinkSize) {
//given
AutoCreateTagCommand command = new AutoCreateTagCommand(1L);

hubRepository.stub(HubFixture.hub(MemberFixture.member()));
linkBundleRepository.stub(LinkBundleFixture.linkBundle());
linkRepository.stub(LinkFixture.links(4).toArray(Link[]::new));
linkRepository.stub(LinkFixture.links(totalLinkSize).toArray(Link[]::new));

//when
Exception exception = catchException(() -> tagService.autoCreateHubTags(command));
Expand All @@ -114,19 +155,24 @@ void notMetCondition_WhenTotalLinkCountLT5() {
.isEqualTo(ErrorCode.NOT_MET_CONDITION);
}

@Test
@DisplayName("예외(notFound): 존재하지 않는 허브인 경우")
void notFound_WhenHubNotFound() {
@ParameterizedTest
@CsvSource({"6","9","11","14","16","19","21","24"})
@DisplayName("예외(notMetCondition): 링크 개수가 5의 배수가 아닐 때")
void notMetCondition_WhenTotalLinkCountIsNotMultiplesOf5(int totalLinkSize) {
//given
AutoCreateTagCommand command = new AutoCreateTagCommand(1L);

hubRepository.stub(HubFixture.hub(MemberFixture.member()));
linkBundleRepository.stub(LinkBundleFixture.linkBundle());
linkRepository.stub(LinkFixture.links(totalLinkSize).toArray(Link[]::new));

//when
Exception exception = catchException(() -> tagService.autoCreateHubTags(command));

//then
assertThat(exception).isInstanceOf(ShoutLinkException.class)
.extracting(e -> ((ShoutLinkException) e).getErrorCode())
.isEqualTo(ErrorCode.NOT_FOUND);
.isEqualTo(ErrorCode.NOT_MET_CONDITION);
}
}
}
}
7 changes: 6 additions & 1 deletion src/test/java/com/seong/shoutlink/fixture/TagFixture.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package com.seong.shoutlink.fixture;

import com.seong.shoutlink.domain.tag.Tag;
import java.time.LocalDateTime;

public final class TagFixture {

public static final long TAG_ID = 1L;
public static final String TAG_NAME = "태그1";
public static final LocalDateTime MORE_THEN_A_DAY = LocalDateTime.now().minusHours(25);

public static Tag tag() {
return new Tag(1L, "태그1");
return new Tag(TAG_ID, TAG_NAME, MORE_THEN_A_DAY, MORE_THEN_A_DAY);
}
}

0 comments on commit 862c619

Please sign in to comment.