ngrinder 설정하다가 눈물흘린 썰 푼다

김운채·2024년 5월 4일
0

저번 프로젝트에서 ngrinder를 도커로 설정했었는데 이번에 로컬에 설치하려다가 오류에 오류에 오류를 마주치다가 결국 도커로 설정한 썰 푼다

과정

  1. https://naver.github.io/ngrinder/ 여기서 최신버전으로 war파일을 다운로드 해주고 아래 명령어로 controller를 설치
    ** 자바 11만 실행 가능하다
java -Djava.io.tmpdir=/Users/{Myhome}/ngrinder/ngrinder-controller/lib -jar ngrinder-controller-3.5.9.war --port 8080
  1. localhost:8080 으로 접속하여 초기 ID/Password(admin/admin)를 입력

  2. admin>Download Agent 에서 Agent를 다운받아 압축을 출어주고 cmd 창으로 접근하여 agent를 실행

# Agent쉘스크립트 파일 실행
./run_agent.sh 

# Agent 백그라운드 실행
./run_agent_bg.sh
  1. Agent Management 로 들어가서 Agent 확인

  2. Script 탭으로 가서 script 작성
    하려고 했는데 Script탭으로 안넘어가짐 [1차 오류]
    .nGrinder 폴더 삭제 후 다시 기동이 필요하다는 글을 보고 다시 삭제 후 agent 재기동

sudo rm -r .ngrinder

참고 : https://github.com/naver/ngrinder/discussions/968

  1. 간단한 테스트 스크립트 작성 (GET)
@RunWith(GrinderRunner)
class TestRunner {

	public static GTest test
	public static HTTPRequest request
	public static Map<String, String> headers = [:]
	public static Map<String, Object> params = [:]
	public static List<Cookie> cookies = []

	@BeforeProcess
	public static void beforeProcess() {
		HTTPRequestControl.setConnectionTimeout(300000)
		test = new GTest(1, "192.168.100.104")
		request = new HTTPRequest()
		grinder.logger.info("before process.")
	}

	@BeforeThread
	public void beforeThread() {
		test.record(this, "test")
		grinder.statistics.delayReports = true
		grinder.logger.info("before thread.")
	}

	@Before
	public void before() {
		request.setHeaders(headers)
		CookieManager.addCookies(cookies)
		grinder.logger.info("before. init headers and cookies")
	}

	@Test
	public void test() {
		HTTPResponse response = request.GET("http://192.168.100.104:8081/products", params)

		if (response.statusCode == 301 || response.statusCode == 302) {
			grinder.logger.warn("Warning. The response may not be correct. The response code was {}.", response.statusCode)
		} else {
			assertThat(response.statusCode, is(200))
		}
	}
}
  1. validation 해보고 ok 잘 돌아가는구만 체크하고 Performance test 탭으로 가서 테스트 만들어서 테스트 실행. (테스트 만들기전에는 테스트가 안만들어지는 오류를 만났지만 agent 재기동해서 여차여차 해결함.)

[2차 오류] TPS 그래프가 안그려짐
다시 테스트 만들어서 테스트 실행하니 [3차 오류]테스트 무반응 현상..

Agent 를 확인해보니 Agent 가 busy 상태였고 stop시킨 다음에 다시 테스트 실행.
[4차 오류] test stopped by error 를 마주침

ㅋㅋ

다시 .ngrinder 파일을 지우고,, 재부팅,, 다시 스크립트 작성,, 테스트 실행,,
똑같은 현상이 반복됨..
내 무지함의 한계이긴하겠지만 구글링을 아무리 해도 해결방법이 보이지 않아서 아예 도커로 설정하는 방법으로 방향을 틀었다.

눈물,,,
  1. 눈물 닦고 도커로 ngrinder 재설정
    1) nGrinder .war 파일을 다운로드 받은 경로에 Dockerfile 작성
FROM openjdk:11-slim

ARG WAR_FILE=./*war
COPY ${WAR_FILE} app.war

ENTRYPOINT ["java", "-jar", "/app.war"]

2) docker-compose.yml 파일도 작성해준다.

version: "3.8"
services:
  ngrinder:
    container_name: arm_ngrinder

    build:
      context: .
      dockerfile: Dockerfile

    ports:
      - "8080:8080"

docker-compose up -d 로 도커에 빌드!

ngrinder-controller 디렉토리 구조

./ngrinder
├─docker-compose.yml
├─/ngrinder-controller
│├─ngrinder-controller-3.5.9.war
│├─lib
│├─Dockerfile
│└─docker-compose.yml
│
└─/ngrinder-agent

3) ngrinder-agent 디렉토리 안의 Docker file은 다음과 같이 작성

FROM openjdk:11-slim
COPY / /home/

CMD /home/run_agent.sh -ch ngrinder-controller-arm

ngrinder-agent 디렉토리 구조

├/ngrinder-agent
│├─ Dockerfile
│├─ lib
│├─ run-agent.sh
│├─ run-agent-bg.sh
│   .
│   .
│   .

4) ngrinder-agent, ngrinder-controller가 들어있는 경로에 docker-compose.yml 파일을 작성 후에 docker-compose up -d 로 도커에 올려줌

version: "3.8"

services:
  ngrinder-controller:
    container_name: ngrinder-controller-arm

    build:
      context: ./ngrinder-controller
      dockerfile: Dockerfile
    restart: always
    ports:
      - "8080:8080"
      - "12000-12009:12000-12009"
      - "16001:16001"
    networks:
      - ngrinder

  ngrinder-agent:
    container_name: ngrinder-agent-arm
    depends_on:
      - ngrinder-controller
    build:
      context: ./ngrinder-agent
      dockerfile: Dockerfile
    restart: always

    networks:
      - ngrinder
networks:
  ngrinder:
    driver: bridge

  1. 이제 localhost:8080으로 다시 ngrinder 접속해서 스크립트 만들고 테스트 실행

된다ㅜㅜ 하

  1. POST api도 테스트 해보려고 함. 새벽에 시작했는데 그러지 말았어야 했음
    로그인해서 jwt 토큰 받고 헤더에 넣어서 장바구니에 아이템을 추가하는 api를 테스트하는 스크립트를 작성함
    [5차 오류] 토큰 잘 받아오는데 두번째 test를 실행할때 헤더에 값이 안넘어가서 401오류가 남..

초기에 작성한 스크립트

@RunWith(GrinderRunner)
class TestRunner {

	public static GTest login
	public static GTest add
	public static HTTPRequest request
	public static Map<String, String> headers = [:]
	public static Map<String, Object> params = [:]
	public static List<Cookie> cookies = []
	public static String body = '[{ "optionId" : 1,"quantity" : 1},{ "optionId" : 2,"quantity" : 5}]'
	public static String token
	
	@BeforeProcess
	public static void beforeProcess() {
		HTTPRequestControl.setConnectionTimeout(300000)
		
		login = new GTest(1, "POST /api/v1/login")
		add  = new GTest(2, "POST /carts/add")
		
		request = new HTTPRequest()
		
		grinder.logger.info("before process.")
	}
	
	@BeforeThread
	public void beforeThread() {
		login.record(this, "login")
		add.record(this, "add")
		
		grinder.statistics.delayReports = true
		grinder.logger.info("before thread.")
	}
	
	//로그인
	@Test
	public void login() {
	// 로그인 API에 요청을 보내서 JWT 토큰을 받아옴
		HTTPResponse response = request.POST("http://192.168.100.91:8081/api/v1/login", [email: "ssar@nate.com", password: "ssar"])
		
		grinder.logger.info("처음에 추가되는 토큰: {}", response.getHeader("Authorization").toString().substring(15))
		
		//토큰 앞에 붙는 쓸데없는 String 제거
		token = response.getHeader("Authorization").toString().substring(15);
		
		//헤더에 넣어줌
		headers.put("Authorization", token)
		
		//헤더 가져옴
		def result = response.getHeader("Authorization");
		grinder.logger.info("header: {}", result)
		
		if (response.statusCode == 301 || response.statusCode == 302) {
			grinder.logger.warn("Warning. The response may not be correct. The response code was {}.", response.statusCode)
		} else {
			assertThat(response.statusCode, is(200))
		}
		
	}
	
	@Test
	public void add() {
	
	grinder.logger.info("봐야되는거: {}", headers)
		request.setHeaders(headers)
		
		
		HTTPResponse response = request.POST("http://192.168.100.91:8081/carts/add", body.getBytes())

		if (response.statusCode == 301 || response.statusCode == 302) {
			grinder.logger.warn("Warning. The response may not be correct. The response code was {}.", response.statusCode)
		} else {
			assertThat(response.statusCode, is(200))
		}
	}
}

결국 오랫동안 구글링을 하다가 테스트를 알파벳 순으로 한다는 것을 알게됨..ㅋ

login() 보다 add()를 먼저 실행하니 당연히 오류가 나지.. 그래서 test1, test2로 이름을 바꿈

최종 스크립트

@RunWith(GrinderRunner)
class TestRunner {

	public static GTest test1
	public static GTest test2
	public static HTTPRequest request
	public static Map<String, String> headers = [:]
	public static Map<String, Object> params = [:]
	public static List<Cookie> cookies = []
	public static String body = '[{ "optionId" : 1,"quantity" : 1},{ "optionId" : 2,"quantity" : 5}]'
	public static String token
	
	@BeforeProcess
	public static void beforeProcess() {
		HTTPRequestControl.setConnectionTimeout(300000)
		
		test1 = new GTest(1, "POST /api/v1/login")
		test2  = new GTest(2, "POST /carts/add")
		
		request = new HTTPRequest()
		
		grinder.logger.info("before process.")
	}
	
	@BeforeThread
	public void beforeThread() {
		test1.record(this, "test1")
		test2.record(this, "test2")
		
		grinder.statistics.delayReports = true
		grinder.logger.info("before thread.")
	}
	
	//로그인
	@Test
	public void test1() {
	// 로그인 API에 요청을 보내서 JWT 토큰을 받아옴
		HTTPResponse response = request.POST("http://192.168.100.91:8081/api/v1/login", [email: "ssar@nate.com", password: "ssar"])
		
		grinder.logger.info("처음에 추가되는 토큰: {}", response.getHeader("Authorization").toString().substring(15))
		
		//토큰 앞에 붙는 쓸데없는 String 제거
		token = response.getHeader("Authorization").toString().substring(15);
		
		//헤더에 넣어줌
		headers.put("Authorization", token)
		
		//헤더 가져옴
		def result = response.getHeader("Authorization");
		grinder.logger.info("header: {}", result)
		
		if (response.statusCode == 301 || response.statusCode == 302) {
			grinder.logger.warn("Warning. The response may not be correct. The response code was {}.", response.statusCode)
		} else {
			assertThat(response.statusCode, is(200))
		}
		
	}
	
	@Test
	public void test2() {
	
	grinder.logger.info("봐야되는거: {}", headers)
		request.setHeaders(headers)
		
		
		HTTPResponse response = request.POST("http://192.168.100.91:8081/carts/add", body.getBytes())

		if (response.statusCode == 301 || response.statusCode == 302) {
			grinder.logger.warn("Warning. The response may not be correct. The response code was {}.", response.statusCode)
		} else {
			assertThat(response.statusCode, is(200))
		}
	}
}

마치며

과정을 겪으면서 여러가지 에러(test가 안만들어지는 error while fetching files from svn for admin 에러, 스크립트 500에러 등)를 만났지만 굵직한 에러들만 몇개 정리해봄..

모든 개발자들이 그렇듯 새로운 툴의 설치 과정과 설정과정에서 다양한 에러들을 마주치게 되는데 과정은 괴로워도 해결하고 나면 미화됨.. 변태같은 직종

다음 포스트는 tps 그래프에 대한 내용을 다룰예정..!!

3개의 댓글

comment-user-thumbnail
2024년 5월 27일

안녕하세요. 저도 스크립트 탭으로 넘어가지지 않는 오류 때문에 막혔는데 .nGrinder 폴더 삭제를 하려고 하는데 어디 위치에 있는지 알 수 있을까요?

1개의 답글