Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package org.devkor.apu.saerok_server.domain.auth.core.repository;

import org.devkor.apu.saerok_server.domain.auth.core.entity.SocialAuth;
import org.devkor.apu.saerok_server.domain.auth.core.entity.SocialProviderType;
import org.devkor.apu.saerok_server.domain.user.core.entity.User;
import org.devkor.apu.saerok_server.testsupport.AbstractPostgresContainerTest;
import org.devkor.apu.saerok_server.testsupport.builder.UserBuilder;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ActiveProfiles;

import java.util.List;
import java.util.Optional;

import static org.assertj.core.api.Assertions.*;

@DataJpaTest
@Import(SocialAuthRepository.class)
@ActiveProfiles("test")
class SocialAuthRepositoryTest extends AbstractPostgresContainerTest {

@Autowired TestEntityManager em;
@Autowired SocialAuthRepository repo;

private User user() {
return new UserBuilder(em).build();
}

private void socialAuth(User user, SocialProviderType provider, String providerUserId) {
SocialAuth auth = SocialAuth.createSocialAuth(user, provider, providerUserId);
em.persist(auth);
}

/* ------------------------------------------------------------------ */
@Test @DisplayName("save / findByProviderAndProviderUserId")
void save_findByProviderAndProviderUserId() {
User u = user();
SocialAuth auth = SocialAuth.createSocialAuth(u, SocialProviderType.KAKAO, "kakao123");
repo.save(auth);
em.flush(); em.clear();

Optional<SocialAuth> found = repo.findByProviderAndProviderUserId(SocialProviderType.KAKAO, "kakao123");
assertThat(found).isPresent();
assertThat(found.get().getProvider()).isEqualTo(SocialProviderType.KAKAO);
assertThat(found.get().getProviderUserId()).isEqualTo("kakao123");
assertThat(found.get().getUser().getId()).isEqualTo(u.getId());
}

@Test @DisplayName("findByProviderAndProviderUserId - 존재하지 않음")
void findByProviderAndProviderUserId_notFound() {
Optional<SocialAuth> found = repo.findByProviderAndProviderUserId(SocialProviderType.KAKAO, "nonexistent");
assertThat(found).isEmpty();
}

@Test @DisplayName("findByProviderAndProviderUserId - provider가 다르면 조회 안 됨")
void findByProviderAndProviderUserId_differentProvider() {
User u = user();
socialAuth(u, SocialProviderType.KAKAO, "user123");
em.flush(); em.clear();

Optional<SocialAuth> found = repo.findByProviderAndProviderUserId(SocialProviderType.APPLE, "user123");
assertThat(found).isEmpty();
}

@Test @DisplayName("unique constraint - 같은 provider와 providerUserId 중복 불가")
void uniqueConstraint_providerAndProviderUserId() {
User u1 = user();
User u2 = user();

socialAuth(u1, SocialProviderType.KAKAO, "duplicate123");
em.flush();

SocialAuth duplicate = SocialAuth.createSocialAuth(u2, SocialProviderType.KAKAO, "duplicate123");
em.persist(duplicate);

assertThatThrownBy(() -> em.flush())
.isInstanceOf(Exception.class);
}

@Test @DisplayName("findByUserId")
void findByUserId() {
User u1 = user();
User u2 = user();

socialAuth(u1, SocialProviderType.KAKAO, "kakao123");
socialAuth(u1, SocialProviderType.APPLE, "apple123");
socialAuth(u2, SocialProviderType.KAKAO, "kakao456");
em.flush(); em.clear();

List<SocialAuth> u1Auths = repo.findByUserId(u1.getId());
List<SocialAuth> u2Auths = repo.findByUserId(u2.getId());

assertThat(u1Auths).hasSize(2);
assertThat(u1Auths).extracting(SocialAuth::getProvider)
.containsExactlyInAnyOrder(SocialProviderType.KAKAO, SocialProviderType.APPLE);
assertThat(u2Auths).hasSize(1);
assertThat(u2Auths.getFirst().getProvider()).isEqualTo(SocialProviderType.KAKAO);
}

@Test @DisplayName("findByUserId - 빈 리스트")
void findByUserId_empty() {
User u = user();
em.flush(); em.clear();

List<SocialAuth> auths = repo.findByUserId(u.getId());
assertThat(auths).isEmpty();
}

@Test @DisplayName("같은 유저가 여러 provider 사용 가능")
void sameUser_multipleProviders() {
User u = user();
socialAuth(u, SocialProviderType.KAKAO, "kakao123");
socialAuth(u, SocialProviderType.APPLE, "apple123");
em.flush(); em.clear();

Optional<SocialAuth> kakao = repo.findByProviderAndProviderUserId(SocialProviderType.KAKAO, "kakao123");
Optional<SocialAuth> apple = repo.findByProviderAndProviderUserId(SocialProviderType.APPLE, "apple123");

assertThat(kakao).isPresent();
assertThat(apple).isPresent();
assertThat(kakao.get().getUser().getId()).isEqualTo(apple.get().getUser().getId());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
package org.devkor.apu.saerok_server.domain.auth.core.repository;

import org.devkor.apu.saerok_server.domain.auth.core.entity.UserRefreshToken;
import org.devkor.apu.saerok_server.domain.user.core.entity.User;
import org.devkor.apu.saerok_server.testsupport.AbstractPostgresContainerTest;
import org.devkor.apu.saerok_server.testsupport.builder.UserBuilder;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ActiveProfiles;

import java.time.Duration;
import java.util.Optional;

import static org.assertj.core.api.Assertions.*;

@DataJpaTest
@Import(UserRefreshTokenRepository.class)
@ActiveProfiles("test")
class UserRefreshTokenRepositoryTest extends AbstractPostgresContainerTest {

@Autowired TestEntityManager em;
@Autowired UserRefreshTokenRepository repo;

private User user() {
return new UserBuilder(em).build();
}

private UserRefreshToken token(User user, String hash) {
UserRefreshToken t = UserRefreshToken.create(
user,
hash,
"Mozilla/5.0",
"127.0.0.1",
Duration.ofDays(30)
);
em.persist(t);
return t;
}

/* ------------------------------------------------------------------ */
@Test @DisplayName("save / findByRefreshTokenHash")
void save_findByRefreshTokenHash() {
User u = user();
UserRefreshToken token = UserRefreshToken.create(
u,
"hash123",
"Mozilla/5.0",
"127.0.0.1",
Duration.ofDays(30)
);
repo.save(token);
em.flush(); em.clear();

Optional<UserRefreshToken> found = repo.findByRefreshTokenHash("hash123");
assertThat(found).isPresent();
assertThat(found.get().getRefreshTokenHash()).isEqualTo("hash123");
assertThat(found.get().getUser().getId()).isEqualTo(u.getId());
assertThat(found.get().getUserAgent()).isEqualTo("Mozilla/5.0");
assertThat(found.get().getIpAddress()).isEqualTo("127.0.0.1");
}

@Test @DisplayName("findByRefreshTokenHash - 존재하지 않음")
void findByRefreshTokenHash_notFound() {
Optional<UserRefreshToken> found = repo.findByRefreshTokenHash("nonexistent");
assertThat(found).isEmpty();
}

@Test @DisplayName("unique constraint - 같은 user와 hash 중복 불가")
void uniqueConstraint_userAndHash() {
User u = user();
token(u, "duplicateHash");
em.flush();

UserRefreshToken duplicate = UserRefreshToken.create(
u,
"duplicateHash",
"Chrome",
"192.168.1.1",
Duration.ofDays(30)
);
em.persist(duplicate);

assertThatThrownBy(() -> em.flush())
.isInstanceOf(Exception.class);
}

@Test @DisplayName("deleteByUserId")
void deleteByUserId() {
User u1 = user();
User u2 = user();

token(u1, "hash1");
token(u1, "hash2");
token(u2, "hash3");
em.flush(); em.clear();

int deletedCount = repo.deleteByUserId(u1.getId());
em.flush(); em.clear();

assertThat(deletedCount).isEqualTo(2);
assertThat(repo.findByRefreshTokenHash("hash1")).isEmpty();
assertThat(repo.findByRefreshTokenHash("hash2")).isEmpty();
assertThat(repo.findByRefreshTokenHash("hash3")).isPresent();
}

@Test @DisplayName("deleteByUserId - 토큰 없음")
void deleteByUserId_noTokens() {
User u = user();
em.flush(); em.clear();

int deletedCount = repo.deleteByUserId(u.getId());
assertThat(deletedCount).isEqualTo(0);
}

@Test @DisplayName("isUsable - 정상 토큰")
void isUsable_valid() {
User u = user();
UserRefreshToken token = token(u, "validHash");
em.flush(); em.clear();

UserRefreshToken found = repo.findByRefreshTokenHash("validHash").orElseThrow();
assertThat(found.isUsable()).isTrue();
}

@Test @DisplayName("isUsable - revoked된 토큰")
void isUsable_revoked() {
User u = user();
UserRefreshToken token = token(u, "revokedHash");
token.revoke();
em.flush(); em.clear();

UserRefreshToken found = repo.findByRefreshTokenHash("revokedHash").orElseThrow();
assertThat(found.isUsable()).isFalse();
assertThat(found.getRevokedAt()).isNotNull();
}

@Test @DisplayName("isUsable - 만료된 토큰")
void isUsable_expired() {
User u = user();
UserRefreshToken token = UserRefreshToken.create(
u,
"expiredHash",
"Mozilla/5.0",
"127.0.0.1",
Duration.ofMillis(-1000) // 이미 만료됨
);
em.persist(token);
em.flush(); em.clear();

UserRefreshToken found = repo.findByRefreshTokenHash("expiredHash").orElseThrow();
assertThat(found.isUsable()).isFalse();
}

@Test @DisplayName("revoke")
void revoke() {
User u = user();
UserRefreshToken token = token(u, "toRevoke");
em.flush(); em.clear();

UserRefreshToken found = repo.findByRefreshTokenHash("toRevoke").orElseThrow();
assertThat(found.getRevokedAt()).isNull();

found.revoke();
em.flush(); em.clear();

UserRefreshToken revoked = repo.findByRefreshTokenHash("toRevoke").orElseThrow();
assertThat(revoked.getRevokedAt()).isNotNull();
assertThat(revoked.isUsable()).isFalse();
}

@Test @DisplayName("revoke - 이중 revoke 예외")
void revoke_alreadyRevoked() {
User u = user();
UserRefreshToken token = token(u, "doubleRevoke");
token.revoke();
em.flush(); em.clear();

UserRefreshToken found = repo.findByRefreshTokenHash("doubleRevoke").orElseThrow();
assertThatThrownBy(() -> found.revoke())
.isInstanceOf(IllegalStateException.class)
.hasMessageContaining("이미 revoke된 리프레시 토큰");
}

@Test @DisplayName("같은 유저가 여러 디바이스에서 여러 토큰 보유 가능")
void sameUser_multipleTokens() {
User u = user();
token(u, "device1");
token(u, "device2");
token(u, "device3");
em.flush(); em.clear();

assertThat(repo.findByRefreshTokenHash("device1")).isPresent();
assertThat(repo.findByRefreshTokenHash("device2")).isPresent();
assertThat(repo.findByRefreshTokenHash("device3")).isPresent();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@
import org.devkor.apu.saerok_server.domain.collection.core.entity.*;
import org.devkor.apu.saerok_server.domain.user.core.entity.User;
import org.devkor.apu.saerok_server.testsupport.AbstractPostgresContainerTest;
import org.junit.jupiter.api.*;
import org.locationtech.jts.geom.*;
import org.devkor.apu.saerok_server.testsupport.builder.CollectionBuilder;
import org.devkor.apu.saerok_server.testsupport.builder.UserBuilder;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ActiveProfiles;

import java.lang.reflect.Field;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.Optional;
Expand All @@ -27,40 +27,15 @@ class CollectionCommentLikeRepositoryTest extends AbstractPostgresContainerTest
@Autowired CollectionCommentLikeRepository repo;
@Autowired TestEntityManager em;

private final GeometryFactory gf = new GeometryFactory();
private Field collUserField;

/* ------------------------------------------------------------------
* helpers
* ------------------------------------------------------------------ */
@BeforeEach
void setup() throws NoSuchFieldException {
collUserField = UserBirdCollection.class.getDeclaredField("user");
collUserField.setAccessible(true);
}

private User newUser() {
User user = User.createUser("test+" + System.nanoTime() + "@example.com");
em.persist(user);
em.flush();
return user;
return new UserBuilder(em).build();
}

private UserBirdCollection newCollection(User owner) {
try {
UserBirdCollection c = new UserBirdCollection();
collUserField.set(c, owner);

c.setAccessLevel(AccessLevelType.PUBLIC);
c.setDiscoveredDate(LocalDate.now());
Point p = gf.createPoint(new Coordinate(126.9780, 37.5665));
c.setLocation(p);

em.persist(c);
return c;
} catch (IllegalAccessException e) {
throw new IllegalStateException(e);
}
return new CollectionBuilder(em).owner(owner).build();
}

private UserBirdCollectionComment newComment(User user, UserBirdCollection col, String content) {
Expand Down
Loading