-
Notifications
You must be signed in to change notification settings - Fork 1
[BE-Feat] Redis 사용 세팅 #98
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
1e9d44e
31c58e5
a946d14
339c6b5
b4bb03c
0b85493
08577cd
671aba8
aa9e120
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| package endolphin.backend.global.config; | ||
|
|
||
| import org.springframework.beans.factory.annotation.Value; | ||
| import org.springframework.context.annotation.Bean; | ||
| import org.springframework.context.annotation.Configuration; | ||
| import org.springframework.context.annotation.Primary; | ||
| import org.springframework.data.redis.connection.RedisConnectionFactory; | ||
| import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; | ||
| import org.springframework.data.redis.core.RedisTemplate; | ||
| import org.springframework.data.redis.serializer.RedisSerializer; | ||
| import org.springframework.data.redis.serializer.StringRedisSerializer; | ||
|
|
||
| @Configuration | ||
| public class RedisConfig { | ||
|
|
||
| @Value("${spring.data.redis.host}") | ||
| private String host; | ||
|
|
||
| @Value("${spring.data.redis.port}") | ||
| private int port; | ||
|
|
||
| @Bean | ||
| public RedisConnectionFactory redisConnectionFactory() { | ||
| return new LettuceConnectionFactory(host, port); | ||
| } | ||
|
|
||
| /** | ||
| * RedisTemplate for binary data (byte[]) storage. 키는 String, 값은 byte[]로 다룹니다. | ||
| */ | ||
| @Bean | ||
| @Primary | ||
| public RedisTemplate<String, byte[]> redisByteTemplate( | ||
| RedisConnectionFactory connectionFactory) { | ||
| RedisTemplate<String, byte[]> template = new RedisTemplate<>(); | ||
| template.setConnectionFactory(connectionFactory); | ||
| template.setKeySerializer(new StringRedisSerializer()); | ||
| template.setHashKeySerializer(new StringRedisSerializer()); | ||
| template.setValueSerializer(RedisSerializer.byteArray()); | ||
| template.setHashValueSerializer(RedisSerializer.byteArray()); | ||
| template.afterPropertiesSet(); | ||
| return template; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,128 @@ | ||||||||||||||||||||||||||||||||||
| package endolphin.backend.global.redis; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| import java.io.IOException; | ||||||||||||||||||||||||||||||||||
| import java.time.LocalDateTime; | ||||||||||||||||||||||||||||||||||
| import java.time.ZoneOffset; | ||||||||||||||||||||||||||||||||||
| import lombok.RequiredArgsConstructor; | ||||||||||||||||||||||||||||||||||
| import org.springframework.data.redis.RedisSystemException; | ||||||||||||||||||||||||||||||||||
| import org.springframework.data.redis.connection.RedisCommandsProvider; | ||||||||||||||||||||||||||||||||||
| import org.springframework.data.redis.connection.RedisConnection; | ||||||||||||||||||||||||||||||||||
| import org.springframework.data.redis.connection.RedisKeyCommands; | ||||||||||||||||||||||||||||||||||
| import org.springframework.data.redis.core.Cursor; | ||||||||||||||||||||||||||||||||||
| import org.springframework.data.redis.core.RedisCallback; | ||||||||||||||||||||||||||||||||||
| import org.springframework.data.redis.core.RedisTemplate; | ||||||||||||||||||||||||||||||||||
| import org.springframework.data.redis.core.ScanOptions; | ||||||||||||||||||||||||||||||||||
| import org.springframework.stereotype.Service; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| @Service | ||||||||||||||||||||||||||||||||||
| @RequiredArgsConstructor | ||||||||||||||||||||||||||||||||||
| public class DiscussionBitmapService { | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| private final RedisTemplate<String, byte[]> redisTemplate; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||
| * Redis 키 생성: "{discussionId}:{minuteKey}" | ||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||
| private String buildRedisKey(Long discussionId, long minuteKey) { | ||||||||||||||||||||||||||||||||||
| return discussionId + ":" + minuteKey; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||
| * LocalDateTime을 분 단위의 long 값(에포크 기준 분 값)으로 변환. | ||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||
| private long convertToMinuteKey(LocalDateTime dateTime) { | ||||||||||||||||||||||||||||||||||
| return dateTime.toEpochSecond(ZoneOffset.ofHours(9)) / 60; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||
| * 해당 논의 및 시각(분)에 대해 16비트(2바이트) 크기의 비트맵을 초기화하여 Redis에 저장합니다. | ||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||
| * @param discussionId 논의 식별자 | ||||||||||||||||||||||||||||||||||
| * @param dateTime 초기화할 기준 시각 (분 단위로 변환됨) | ||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||
| public void initializeBitmap(Long discussionId, LocalDateTime dateTime) { | ||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||
| int byteSize = 2; | ||||||||||||||||||||||||||||||||||
| long minuteKey = convertToMinuteKey(dateTime); | ||||||||||||||||||||||||||||||||||
| String redisKey = buildRedisKey(discussionId, minuteKey); | ||||||||||||||||||||||||||||||||||
| byte[] initialData = new byte[byteSize]; | ||||||||||||||||||||||||||||||||||
| //TODO: 만료 설정? | ||||||||||||||||||||||||||||||||||
| redisTemplate.opsForValue().set(redisKey, initialData); | ||||||||||||||||||||||||||||||||||
| } catch (RedisSystemException e) { | ||||||||||||||||||||||||||||||||||
| //TODO: 예외 처리 | ||||||||||||||||||||||||||||||||||
| throw e; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||
| * 해당 논의의 특정 시각(분) 비트맵 데이터에서, 지정 오프셋의 비트를 수정합니다. | ||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||
| * @param discussionId 논의 식별자 | ||||||||||||||||||||||||||||||||||
| * @param dateTime 수정할 시각 (분 단위로 변환됨) | ||||||||||||||||||||||||||||||||||
| * @param bitOffset 수정할 비트의 오프셋 (0부터 시작, 최대 15까지 사용 가능) | ||||||||||||||||||||||||||||||||||
| * @param value 설정할 비트 값 (true/false) | ||||||||||||||||||||||||||||||||||
| * @return 이전 비트 값 (true/false) | ||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||
| public Boolean setBitValue(Long discussionId, LocalDateTime dateTime, long bitOffset, | ||||||||||||||||||||||||||||||||||
| boolean value) { | ||||||||||||||||||||||||||||||||||
| long minuteKey = convertToMinuteKey(dateTime); | ||||||||||||||||||||||||||||||||||
| String redisKey = buildRedisKey(discussionId, minuteKey); | ||||||||||||||||||||||||||||||||||
| return redisTemplate.opsForValue().setBit(redisKey, bitOffset, value); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+66
to
+71
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add validation for bitOffset range. Since this is a 16-bit bitmap, bitOffset should be between 0 and 15. public Boolean setBitValue(Long discussionId, LocalDateTime dateTime, long bitOffset,
boolean value) {
+ if (bitOffset < 0 || bitOffset >= BITMAP_SIZE_BYTES * 8) {
+ throw new IllegalArgumentException("bitOffset must be between 0 and " +
+ (BITMAP_SIZE_BYTES * 8 - 1));
+ }
long minuteKey = convertToMinuteKey(dateTime);
String redisKey = buildRedisKey(discussionId, minuteKey);
return redisTemplate.opsForValue().setBit(redisKey, bitOffset, value);
}📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||
| * 해당 논의의 특정 시각(분) 비트맵 데이터에서, 지정 오프셋의 비트 값을 조회합니다. | ||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||
| * @param discussionId 논의 식별자 | ||||||||||||||||||||||||||||||||||
| * @param dateTime 조회할 시각 (분 단위로 변환됨) | ||||||||||||||||||||||||||||||||||
| * @param bitOffset 조회할 비트 오프셋 (0부터 시작) | ||||||||||||||||||||||||||||||||||
| * @return 조회된 비트 값 (true/false) | ||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||
| public Boolean getBitValue(Long discussionId, LocalDateTime dateTime, long bitOffset) { | ||||||||||||||||||||||||||||||||||
| long minuteKey = convertToMinuteKey(dateTime); | ||||||||||||||||||||||||||||||||||
| String redisKey = buildRedisKey(discussionId, minuteKey); | ||||||||||||||||||||||||||||||||||
| return redisTemplate.opsForValue().getBit(redisKey, bitOffset); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+81
to
+85
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add validation for bitOffset range. Similar to setBitValue, validate that bitOffset is within the valid range. public Boolean getBitValue(Long discussionId, LocalDateTime dateTime, long bitOffset) {
+ if (bitOffset < 0 || bitOffset >= BITMAP_SIZE_BYTES * 8) {
+ throw new IllegalArgumentException("bitOffset must be between 0 and " +
+ (BITMAP_SIZE_BYTES * 8 - 1));
+ }
long minuteKey = convertToMinuteKey(dateTime);
String redisKey = buildRedisKey(discussionId, minuteKey);
return redisTemplate.opsForValue().getBit(redisKey, bitOffset);
}📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||
| * 해당 논의의 특정 시각(분) 비트맵 데이터 전체를 조회합니다. | ||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||
| * @param discussionId 논의 식별자 | ||||||||||||||||||||||||||||||||||
| * @param dateTime 조회할 시각 (분 단위로 변환됨) | ||||||||||||||||||||||||||||||||||
| * @return byte[] 형태의 전체 비트맵 데이터 (없으면 null) | ||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||
| public byte[] getBitmapData(Long discussionId, LocalDateTime dateTime) { | ||||||||||||||||||||||||||||||||||
| long minuteKey = convertToMinuteKey(dateTime); | ||||||||||||||||||||||||||||||||||
| String redisKey = buildRedisKey(discussionId, minuteKey); | ||||||||||||||||||||||||||||||||||
| return redisTemplate.opsForValue().get(redisKey); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||
| * SCAN을 이용해 해당 논의의 모든 비트맵 키를 찾고 삭제합니다. | ||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||
| * @param discussionId 논의 식별자 | ||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||
| public void deleteDiscussionBitmapsUsingScan(Long discussionId) { | ||||||||||||||||||||||||||||||||||
| String pattern = discussionId + ":*"; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| // SCAN 옵션 | ||||||||||||||||||||||||||||||||||
| ScanOptions scanOptions = ScanOptions.scanOptions() | ||||||||||||||||||||||||||||||||||
| .match(pattern) | ||||||||||||||||||||||||||||||||||
| .count(1000) | ||||||||||||||||||||||||||||||||||
| .build(); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| redisTemplate.execute((RedisConnection connection) -> { | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| RedisKeyCommands keyCommands = ((RedisCommandsProvider) connection).keyCommands(); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| try (Cursor<byte[]> cursor = keyCommands.scan(scanOptions)) { | ||||||||||||||||||||||||||||||||||
| while (cursor.hasNext()) { | ||||||||||||||||||||||||||||||||||
| byte[] rawKey = cursor.next(); | ||||||||||||||||||||||||||||||||||
| keyCommands.del(rawKey); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| return null; | ||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| package endolphin.backend.global.redis; | ||
|
|
||
| import static org.assertj.core.api.Assertions.assertThat; | ||
|
|
||
| import java.time.LocalDateTime; | ||
| import org.junit.jupiter.api.DisplayName; | ||
| import org.junit.jupiter.api.Test; | ||
| import org.springframework.beans.factory.annotation.Autowired; | ||
| import org.springframework.boot.test.context.SpringBootTest; | ||
|
|
||
|
|
||
| @SpringBootTest | ||
| public class DiscussionBitmapServiceTest { | ||
|
|
||
| @Autowired | ||
| private DiscussionBitmapService bitmapService; | ||
|
|
||
|
|
||
| @DisplayName("비트맵 초기화 및 비트 연산 테스트") | ||
| @Test | ||
| public void testInitializeAndBitOperations() { | ||
| Long discussionId = 100L; | ||
| LocalDateTime dateTime = LocalDateTime.now(); | ||
|
|
||
| // 1. 초기화: 해당 논의 및 시각에 대해 16비트 크기의 비트맵을 생성하여 Redis에 저장 | ||
| bitmapService.initializeBitmap(discussionId, dateTime); | ||
|
|
||
| // 2. 오프셋 5의 비트를 true로 설정 | ||
| Boolean previousValue = bitmapService.setBitValue(discussionId, dateTime, 5, true); | ||
| // 초기화된 비트맵은 모두 0이므로 이전 값은 false여야 함 | ||
| assertThat(previousValue).isFalse(); | ||
|
|
||
| // 3. 수정된 비트 조회: 오프셋 5의 비트 값이 true인지 확인 | ||
| Boolean bitValue = bitmapService.getBitValue(discussionId, dateTime, 5); | ||
| assertThat(bitValue).isTrue(); | ||
|
|
||
| // 4. 전체 비트맵 데이터 조회 및 검증 | ||
| byte[] bitmapData = bitmapService.getBitmapData(discussionId, dateTime); | ||
| int byteIndex = 5 / 8; // 0 | ||
| int bitPosition = 5 % 8; // 5 | ||
| // big-endian 순서로 확인: (7 - bitPosition) | ||
| boolean extractedBit = ((bitmapData[byteIndex] >> (7 - bitPosition)) & 1) == 1; | ||
| assertThat(extractedBit).isTrue(); | ||
|
|
||
| // 5. SCAN을 이용하여 해당 discussionId의 모든 비트맵 키 삭제 | ||
| bitmapService.deleteDiscussionBitmapsUsingScan(discussionId); | ||
|
|
||
| // 6. 삭제 후 데이터 검증: 비트맵 데이터가 없어야 함 | ||
| byte[] afterDelete = bitmapService.getBitmapData(discussionId, dateTime); | ||
| assertThat(afterDelete).as("deleteDiscussionBitmapsUsingScan should remove the bitmap") | ||
| .isNull(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,31 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package endolphin.backend.global.redis; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import static org.assertj.core.api.Assertions.assertThat; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.junit.jupiter.api.DisplayName; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.junit.jupiter.api.Test; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.boot.test.context.SpringBootTest; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.data.redis.core.RedisTemplate; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @SpringBootTest | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public class RedisTemplateTest { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. p3: 삭제, 업데이트 테스트 코드도 있으면 좋을 거 같습니다!
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 추가했습니다 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Autowired | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private RedisTemplate<String, byte[]> redisTemplate; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @DisplayName("작성한 Redis template 테스트") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Test | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public void testSetAndGetByteArray() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| String key = "test:bytearray"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| byte[] expected = new byte[] {10, 20, 30, 40, 50}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 값 저장 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| redisTemplate.opsForValue().set(key, expected); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 값 조회 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| byte[] actual = redisTemplate.opsForValue().get(key); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assertThat(actual).isEqualTo(expected); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+19
to
+30
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add more test cases and cleanup. The test should include more edge cases and cleanup Redis after test execution. + @AfterEach
+ void cleanup() {
+ redisTemplate.delete("test:bytearray");
+ }
@Test
@DisplayName("작성한 Redis template 테스트")
public void testSetAndGetByteArray() {
// ... existing test ...
}
+ @Test
+ @DisplayName("대용량 바이트 배열 테스트")
+ public void testLargeByteArray() {
+ String key = "test:large:bytearray";
+ byte[] expected = new byte[1024 * 1024]; // 1MB
+ new Random().nextBytes(expected);
+
+ redisTemplate.opsForValue().set(key, expected);
+ byte[] actual = redisTemplate.opsForValue().get(key);
+
+ assertThat(actual).isEqualTo(expected);
+ }📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,28 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package endolphin.backend.global.redis; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.junit.jupiter.api.DisplayName; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.context.annotation.Configuration; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.context.annotation.Profile; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.testcontainers.containers.GenericContainer; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.testcontainers.utility.DockerImageName; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @DisplayName("Redis Test Containers") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Profile("dev") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Configuration | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public class RedisTestContainer { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private static final String REDIS_DOCKER_IMAGE = "redis:6-alpine"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| static { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GenericContainer<?> REDIS_CONTAINER = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| new GenericContainer<>(DockerImageName.parse(REDIS_DOCKER_IMAGE)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .withExposedPorts(6379) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .withReuse(true); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| REDIS_CONTAINER.start(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| System.setProperty("spring.data.redis.host", REDIS_CONTAINER.getHost()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| System.setProperty("spring.data.redis.port", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| REDIS_CONTAINER.getMappedPort(6379).toString()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+16
to
+27
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Consider using @DynamicPropertySource instead of static block. Using a static block for container initialization can cause issues with Spring context lifecycle. Consider using - static {
- GenericContainer<?> REDIS_CONTAINER =
- new GenericContainer<>(DockerImageName.parse(REDIS_DOCKER_IMAGE))
- .withExposedPorts(6379)
- .withReuse(true);
-
- REDIS_CONTAINER.start();
-
- System.setProperty("spring.data.redis.host", REDIS_CONTAINER.getHost());
- System.setProperty("spring.data.redis.port",
- REDIS_CONTAINER.getMappedPort(6379).toString());
- }
+ static final GenericContainer<?> REDIS_CONTAINER;
+
+ static {
+ REDIS_CONTAINER = new GenericContainer<>(DockerImageName.parse(REDIS_DOCKER_IMAGE))
+ .withExposedPorts(6379)
+ .withReuse(true);
+ REDIS_CONTAINER.start();
+ }
+
+ @DynamicPropertySource
+ static void redisProperties(DynamicPropertyRegistry registry) {
+ registry.add("spring.data.redis.host", REDIS_CONTAINER::getHost);
+ registry.add("spring.data.redis.port", () ->
+ REDIS_CONTAINER.getMappedPort(6379).toString());
+ }📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implement proper exception handling
Currently, the catch block rethrows the exception without additional handling. Consider adding logging or custom exception handling to provide more context and facilitate debugging when an error occurs.