[๊ฐœ๋ฐœ ํ™˜๊ฒฝ]๐Ÿ˜ถEmbeded Redis Test code in Spring

์œ ํ˜•์ฐฌยท2023๋…„ 1์›” 15์ผ
0

Springboot

๋ชฉ๋ก ๋ณด๊ธฐ
2/2

์Šคํ”„๋ง ๊ฐœ๋ฐœ ํ™˜๊ฒฝ๐Ÿ˜ถ๐Ÿ˜ถ

๐Ÿ˜ถ ์š”์ฆ˜์€ docker๋กœ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์„ ๊ตฌ์„ฑํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค.๐Ÿ˜ถ

๊ทธ๋Ÿฐ๋ฐ docker๋กœ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์„ ๊ตฌ์„ฑํ•˜๋Š”๊ฒŒ ์˜ณ์€ ๊ฐ€์— ๋Œ€ํ•ด ๊ณ ๋ฏผ์„ ํ•ด๋ณด์•˜๋‹ค.

๋ฐฐํฌ๋Š” docker๋กœ ํ•˜๊ณ  ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์€ docker๋กœ ํ•˜์ง€ ์•Š๋Š”๊ฒŒ ๋งž๋Š” ๊ฒƒ ๊ฐ™๋‹ค๋Š” ์ƒ๊ฐ์ด ๋งŽ์ด ๋“ ๋‹ค.

๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ๋Š” ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์ž์ฃผ ํ•˜๊ธฐ๋„ ํ•˜๋ฉฐ , ๊ฐ๊ฐ์˜ ๊ธฐ๋Šฅ์ด ์„œ๋กœ ๋…๋ฆฝ์ ์œผ๋กœ

์ž‘๋™ํ•ด์•ผ ํ•˜๋Š”๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค. docker ๋กœ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์„ ๋„์šฐ๋ฉด ์‚ฌ์‹ค ์ข€ ๋ฌด๊ฒ๋‹ค๊ณ  ์ƒ๊ฐ ๋œ๋‹ค.

๋žจ ์žก์–ด๋จน๋Š” ๊ท€์‹  ๊ทธ ์ž์ฒด docker

๋‹ค์‹œ ๋Œ์•„์™€์„œ, ๋ฌด๊ฑฐ์šด ๋งŒํผ , ๋ ˜์„ ์žก์•„๋จน๋Š” ๋งŒํผ , ๋นŒ๋“œ ์†๋„์™€ ๋„์šฐ๋Š” ์†๋„๋Š” ๋Š๋ฆฌ๋‹ค.

๋˜ํ•œ, docker ๊ฐ€ ์„ค์น˜ ๋˜์ง€ ์•Š์€ ๊ฐœ๋ฐœ์ž๋“ค์€ docker-compose ๊นŒ์ง€ ์„ค์ •ํ•˜๊ณ  ๋ญํ•˜๊ณ ...

์„œ๋กœ ๊ฐœ๋ฐœํ™˜๊ฒฝ์„ ๋งž์ถฐ์ฃผ๋Š” ๊ฑด ์ข‹์ง€๋งŒ ๋Š๋ ค...

๋˜ ์™ธ๋ถ€ ํ™˜๊ฒฝ์— ์ข…์† ๋œ๋‹ค. ์ด๊ฒŒ ๊ฐ€์žฅ ํฐ ๋ฌธ์ œ ์•„๋‹Œ๊ฐ€?

๋ฌด์กฐ๊ฑด ๋‹ค์šด ๋ฐ›์ž๋งˆ์ž ์‹คํ–‰ ๊ฐ€๋Šฅ ํ•ด์•ผ ํ•œ๋‹ค.

์š”์ฆ˜์€ ์ด๊ฑธ ๊ฐ€์žฅ ํฌ๊ฒŒ ๋Š๋‚€๋‹ค. ํ˜‘์—…์„ ํ•˜๋ฉด์„œ ์ค‘๊ฐ„์— ์ฐธ์—ฌํ•˜๋Š” ๊ฒƒ๋„ ๊ทธ๋ ‡๊ณ 

์‚ฌ์‹ค ์„œ๋กœ์˜ ํ™˜๊ฒฝ์ด ๋งž์ง€ ์•Š์œผ๋ฉด ๊ฐœ๋ฐœ์ด ๋ถˆ๊ฐ€๋Šฅ ํ•˜๋‹ค. ๋‚˜๋Š” ๋˜๋Š”๋ฐ ๋„Œ ์™œ ์•ˆ๋ผ?

์™ธ๋ถ€ ํ™˜๊ฒฝ์— ์ข…์†๋˜๋Š” ๊ฐœ๋ฐœ์€ ์ข‹์ง€ ์•Š๋‹ค. ๊ทธ๋Ÿฐ ๋งˆ์Œ ๊ฐ€์ง์œผ๋กœ ์—ฌ๋Ÿฌ embeded ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ฐพ์•„๋ณด์•˜๋‹ค.

๋Œ€ํ‘œ์ ์œผ๋กœ๋Š” h2 , hsql , derby , redis , mongo ๋“ฑ์ด ์žˆ๋‹ค.

์—ฌ๊ธฐ์— kafka , zookeeper ๋“ฑ๋“ฑ๋„ ์žˆ๋‹ค.

embeded redis

embeded redis ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด redis ๋ฅผ ์„ค์น˜ํ•˜์ง€ ์•Š๊ณ ๋„ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ redis ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

@Configuration
public class RedisConfig {

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        return new LettuceConnectionFactory("localhost", 6379);
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate() {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        return redisTemplate;
    }
}

์œ„์ฒ˜๋Ÿผ ๋ญ... ๋กœ์ปฌ์—์„œ๋งŒ ํ•  ๊ฑฐ๋ฉด ์ €๋ ‡๊ฒŒ ํ•˜๊ณ 

package com.yata.backend.global.config.redis;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;

import java.util.Arrays;

@Configuration
@EnableRedisRepositories
public class RedisRepositoryConfig {
    @Value("${spring.redis.host}")
    private String redisHost;

    @Value("${spring.redis.port}")
    private int redisPort;

    @Value(value = "${spring.redis.password}")
    private String redisPassword;
    @Autowired
    private Environment environment;

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        redisStandaloneConfiguration.setHostName(redisHost);
        redisStandaloneConfiguration.setPort(redisPort);
        // redis password ์„ค์ •
        Arrays.stream(environment.getActiveProfiles()).forEach(profile -> {
            if (profile.equals("prod")) {
                redisStandaloneConfiguration.setPassword(redisPassword);
            }
        });
        return new LettuceConnectionFactory(redisStandaloneConfiguration);
    }

    @Bean
    public RedisTemplate<?, ?> redisTemplate() {
        RedisTemplate<byte[], byte[]> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        return redisTemplate;
    }
}

์ด ์ฒ˜๋Ÿผ ํ”„๋กœํ•„ ๋ณ„๋กœ ์„ค์ •์„ ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” embeded redis๋ฅผ ์ค‘์ ์œผ๋กœ ๋ดค๊ณ 

์—ฌ๊ธฐ์„œ ์ถ”๊ฐ€์ ์œผ๋กœ ๋ฌธ์ œ์ ์ด ํ•˜๋‚˜์žˆ๋‹ค.

๋ฌธ์ œ์ 

๋ฌธ์ œ์ ์€ test ํ™˜๊ฒฝ์—์„œ redis ํ…Œ์ŠคํŠธ ํ•  ๋•Œ ๋ฌธ์ œ๊ฐ€ ๋œ๋‹ค.

config Bean ๋“ฑ์„ ์‚ฌ์šฉ ํ•  ๋•Œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ spiringBootTest ๊ฐ™์ด ์ „์—ญ ํ…Œ์ŠคํŠธ๋ฅผ ํ•  ๋•Œ

์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋Š”๋ฐ ์ด๋Š” ๋งค ๊ฐ๊ฐ์˜ ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค ๋งˆ๋‹ค redis๋ฅผ ๋„์šฐ๊ฒŒ ๋œ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์ด์ œ redis ์„œ๋ฒ„๊ฐ€ ์ฃฝ๊ธฐ์ „์— ๋‹ค์Œ ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค๊ฐ€ ๋„์›Œ์ง€๊ฒŒ ๋˜๋ฉด

์ด์ „์— ๋„์›Œ์ง„ redis ์„œ๋ฒ„๊ฐ€ ์•„์ง ์‚ด์•„์žˆ๊ธฐ ๋•Œ๋ฌธ์— port ์ถฉ๋Œ๋กœ ์ธํ•ด ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํŒจํ•˜๊ฒŒ ๋œ๋‹ค.

redis๊ฐ€ ์•ˆ ๋„์›Œ์ง€๊ธฐ ๋•Œ๋ฌธ์— ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํŒจํ•˜๊ฒŒ ๋œ๋‹ค.

์ด ๋ฌธ์ œ๋Š” jojodu ๋‹˜์˜ ๋ธ”๋กœ๊ทธ๋ฅผ ์ฐธ๊ณ ํ–ˆ๋‹ค.
https://jojoldu.tistory.com/297 ์ •๋ง ์•Œ ์ฐฌ ๋‚ด์šฉ!

๊ฐ€์žฅ ํฐ ๋ฌธ์ œ๋Š” ํฌํŠธ ์ถฉ๋Œ ๋•Œ๋ฌธ์— ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํŒจํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

ํ•ด๊ฒฐ flow idea๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • redis ์„œ๋ฒ„๋ฅผ ๋„์šฐ๊ธฐ ์ „์— ํฌํŠธ ๋ฒˆํ˜ธ๊ฐ€ ์œ ํšจํ•œ์ง€ ํ™•์ธํ•œ๋‹ค.
  • ์œ ํšจํ•˜๋ฉด redis ์„œ๋ฒ„๋ฅผ ๋„์šด๋‹ค.
  • ์œ ํšจํ•˜์ง€ ์•Š์œผ๋ฉด ์œ ํšจํ•œ ํฌํŠธ ๋ฒˆํ˜ธ๋ฅผ ์ฐพ์•„ redis ์„œ๋ฒ„๋ฅผ ๋„์šด๋‹ค.

๊ทธ๋ž˜์„œ redis ์„œ๋ฒ„๋ฅผ ๋„์šฐ๊ธฐ ์ „์— ํฌํŠธ ๋ฒˆํ˜ธ๊ฐ€ ์œ ํšจํ•œ์ง€ ํ™•์ธํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค.


import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.util.StringUtils;
import redis.embedded.RedisServer;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

@Slf4j
@Profile("!prod")
@Configuration
public class LocalRedisConfig {
    @Value("${spring.redis.port}")
    private int redisPort;

    private RedisServer redisServer;

    @PostConstruct
    public void redisServer() throws IOException {
        int port = isRedisRunning() ? findAvailablePort() : redisPort;
        redisServer = RedisServer.builder()
                .port(port)
                .setting("maxmemory 128M")
                .build();
        redisServer.start();
    }

    @PreDestroy
    public void stopRedis() {
        if (redisServer != null) {
            redisServer.stop();
        }
    }


    /**
     * Embedded Redis๊ฐ€ ํ˜„์žฌ ์‹คํ–‰์ค‘์ธ์ง€ ํ™•์ธ
     */
    private boolean isRedisRunning() throws IOException {
        return isRunning(executeGrepProcessCommand(redisPort));
    }

    /**
     * ํ˜„์žฌ PC/์„œ๋ฒ„์—์„œ ์‚ฌ์šฉ๊ฐ€๋Šฅํ•œ ํฌํŠธ ์กฐํšŒ
     */
    public int findAvailablePort() throws IOException {

        for (int port = 10000; port <= 65535; port++) {
            Process process = executeGrepProcessCommand(port);
            if (!isRunning(process)) {
                return port;
            }
        }

        throw new IllegalArgumentException("Not Found Available port: 10000 ~ 65535");
    }

    /**
     * ํ•ด๋‹น port๋ฅผ ์‚ฌ์šฉ์ค‘์ธ ํ”„๋กœ์„ธ์Šค ํ™•์ธํ•˜๋Š” sh ์‹คํ–‰
     */
    private Process executeGrepProcessCommand(int port) throws IOException {
        String OS = System.getProperty("os.name").toLowerCase();
        if (OS.contains("win")) {
            log.info("OS is  " + OS + " " + port);
            String command = String.format("netstat -nao | find \"LISTEN\" | find \"%d\"", port);
            String[] shell = {"cmd.exe", "/y", "/c", command};
            return Runtime.getRuntime().exec(shell);
        }
        String command = String.format("netstat -nat | grep LISTEN|grep %d", port);
        String[] shell = {"/bin/sh", "-c", command};
        return Runtime.getRuntime().exec(shell);
    }

    /**
     * ํ•ด๋‹น Process๊ฐ€ ํ˜„์žฌ ์‹คํ–‰์ค‘์ธ์ง€ ํ™•์ธ
     */
    private boolean isRunning(Process process) {
        String line;
        StringBuilder pidInfo = new StringBuilder();

        try (BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream()))) {

            while ((line = input.readLine()) != null) {
                pidInfo.append(line);
            }

        } catch (Exception e) {
        }

        return !StringUtils.isEmpty(pidInfo.toString());
    }
}

jojodu ๋‹˜์˜ ์ฝ”๋“œ์— ์ถ”๊ฐ€์ ์œผ๋กœ OS๋ณ„๋กœ ํฌํŠธ๋ฅผ ํ™•์ธํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค.

์œ„ ์ฒ˜๋Ÿผ embeded redis testcode ๊ฐ€ ์ถฉ๋Œ์ด ๋‚˜๋Š” ๊ฒฝ์šฐ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด๋‹ค. ํŒŒ์ดํŒ…!

profile
rocoli์—์š”

0๊ฐœ์˜ ๋Œ“๊ธ€