1. MockMvc 란?

MockMvc는 웹 애플리케이션을 애플리케이션 서버에 배포하지 않고 테스트용 MVC 환경을 만들어 요청 및 전송, 응답기능을 제공해주는 유틸리티 클래스다.

 

2. MockMvc 사용법

get 방식으로 /post를 요청 시 Hello world가 출력되는 controller를 테스트한다고 가정.

Controller 단

@RestController
public class PostController {

    @GetMapping("/posts")
    public String get(){
        return "Hello world";
    }

}

Test 단

@WebMvcTest
class PostControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    @DisplayName("/posts 요청시 Hello World를 출력한다.")
    void test() throws Exception {
        //expected
        mockMvc.perform(get("/posts"))   		//get방식으로 /posts로 요청을 보냄
                .andExpect(status().isOk())		//응답 status를 ok로 테스트
                .andExpect(content().string("Hello world"))	//반환된 응답값을 확인
                .andDo(print());				//응답값 print

    }
}

3. MockMvcRequestBuilders

  • GET/POST/PUT/DELETE 요청 방식과 매핑되는 메서드들을 제공
  • HTTP 요청 관련 정보(파라미터, 헤더, 쿠키 등)를 설정
메서드 명 설명
param / params 요청 파라미터를 설정한다.
header / headers 요청 헤더를 설정한다. contentType이나 accept와 같은 특정 헤더를 설정할 수 있는 메서드도 제공한다.
cookies 쿠키를 설정한다.
content 요청 본문을 설정한다.
contentType 본문 타입을 설정한다.
requestAttr 요청 스코프에 객체를 설정한다.
flashAttr 플래시 스코프에 객체를 설정한다.
sessionAttr 세션 스코프에 객체를 설정한다.
@Test
@DisplayName("MockMvcRequestBuilders 메서드")
void MockMvcRequestBuilders() throws Exception{
    mockMvc.perform(get("/mockMvcRequestBuilders")
            .param("testParam","test")  // name, values
            .content("Json으로")
            .contentType(APPLICATION_JSON)
    );
}

4. MockMvcResultHandlers

  • andDo() 메서드를 이용하여 실행결과를 출력
메서드 명 설명
log() 실행결과를 디버깅 레벨로 출력
print() 실행결과를 지정해준 대상으로 출력
@Test
@DisplayName("/posts 요청시 Hello World를 출력한다.")
void test() throws Exception {
    //expected
    mockMvc.perform(get("/posts"))
            .andExpect(status().isOk())
            .andExpect(content().string("Hello worlds"))
            .andDo(print())
            .andDo(log());

}

5.MockMvcResultMatchers

  • 응답에 대한 검증을 해줌. andExpect()
메서드 명 설명
status 상태 코드 검증
content 응답 본문 검증
view 컨트롤러가 반환한 뷰 이름 검증
@Test
@DisplayName("/posts 요청시 Hello World를 출력한다.")
void test() throws Exception {
    //expected
    mockMvc.perform(get("/posts"))
            .andExpect(status().isOk())
            .andExpect(content().string("Hello worlds"))
            .andExpect(view().name("viewName"))
            .andDo(print());

}
$ docker pull vault
//dev 용으로 inmemory 저장방식
$ docker run --name devVault --cap-add=IPC_LOCK -e 'VAULT_DEV_ROOT_TOKEN=myroot' -p \
					8200:8200 vault 

//volumn 바인딩을 해줘야 도커를 꺼도 데이터가 저장됨
$ sudo docker run --name vault -d --cap-add=IPC_LOCK -p 8200:8200 --log-opt \
            mode=non-blocking -v /vault/config:/vault/config \
            -v /vault/file:/vault/file -v /vault/logs:/vault/logs vault server

AWS 서버의 퍼블릭 주소 http://~~~~~~:8200 으로 접속

로그인 창이 뜨면 Method를 Token으로 선택하고, 앞서 컨테이너 생성시 설정한 루트 토큰 아이디를 입력한다.(myroot)

 

Secret 작성

로그인 후 Enable new engine을 클릭한다.

Generic > KV를 선택하고 Next 버튼을 클릭합니다.

Path에 원하는 Path를 작성하고 versions은 2로 설정한 후 Enable Engine을 클릭한다.

(이런식으로 Secret Engine을 생성해도 되지만 나는 그냥 기존에 있던 secret에다가 작업함)

Secret Engine(secret)에 들어가서 Create secret버튼을 클릭합니다.

Json을 클릭하고 Path for this secret에 원하는 경로를 작성한 후 application, yml에서 숨기고자 하는 내용들을 json 형식으로 작성 후 Save 버튼 클릭한다.

secret_auth가 생성된 후 Create new version을 클릭해서 Version2 로 변경한다.

Policy 작성

상단 메뉴에서 Policies를 클릭하고, Create ACL policy를 클릭한다.

Name에 Policy명(auth_acl)을, Policy에는 권한 내용을 작성하고 Create policy 버튼을 클릭한다.

앞에서 작성한 Secrets에 대한 권한 → https://www.vaultproject.io/docs/concepts/policies
 

Policies | Vault by HashiCorp

Policies are how authorization is done in Vault, allowing you to restrict which parts of Vault a user can access.

www.vaultproject.io

path "secret/*" {
  capabilities = ["list"]
}

path "secret/data/secret_auth" {
  capabilities = ["read","list"]
}
Userpass를 생성하고 나서 생성한 user로 로그인했을 때 Policy에 권한이 없다고 할때 보면 좋은 사이트 
https://stackoverflow.com/questions/54608202/how-to-get-hashicorp-vault-policy-right
 

How to get HashiCorp Vault policy right?

Here is the situation: I created an user vault write auth/userpass/users/'username' password='password' policies=default with default policy and added path "secret/db_pass/*" { capabilities...

stackoverflow.com

Authentication Methods 작성

상단 메뉴에서 Access를 클릭하고, Enable new method버튼을 클릭한다.

Generic > Username & Password를 선택하고 Next 버튼을 클릭한다.

생성한 userpass에서 Create user버튼을 클릭한다.

Username과 Password는 자유롭게 입력하고, 아래 Generated Token’s Policies에 앞서 작성한 Policy명(auth_acl)을 입력한 후 save 버튼을 클릭한다.

로그아웃한 후 앞서 생성한 Username & Password 정보로 로그인한다.

우측 상단의 사용자 정보 드롭다운을 클릭하고 Copy token을 클릭한다.

앞에서 myroot일때 생성한 Secret가 들어와있는걸 확인할 수 있다.

secret 목록을 클릭하고 들어왔을 때 You do not have permission to read this secret라고 뜨면 앞에 Policy에서 권한을 잘못 준 것이므로 수정해야 함.

저렇게 Secret > secret_auth가 나오면 OK

secret_auth를 클릭했을 때도 json형식으로 저장한 데이터가 잘 나오면 OK

 

** dev용 vault 방식이라서 docker stop vault를 하면 데이터가 다 지워지므로 volumn 바인딩을 해줘야 함

 

* 참고한 사이트

https://logical-code.tistory.com/183

 

[Spring Cloud Config] 설정값을 외부에서 관리하자! - 실습

앞선 포스트 기본편에서 이어집니다! [Spring Cloud Config] 설정값을 외부에서 관리하자! - 기본 시작하기 전에 스프링 또는 스프링 부트 개발을 하다 보면 *.properties 혹은 *.yml로 관리되는 환경설정

logical-code.tistory.com

https://velog.io/@limsubin/Vault-관리자-화면을-시작-및-간단한-테스트를-해보자

 

Vault 관리자 화면을 시작 및 간단한 테스트를 해보자!

vault : v1.10.0📌 Vault를 Docker로 올려보자!비상 시 필요한 마스터 키의 초기 세트를 설정Key shares : 총 key 수 설정Key threshold : 몇 개 이상의 key를 보유해야 login이 가능한지 설정저는 테스트를 위해 각

velog.io

'개발' 카테고리의 다른 글

Vault란  (0) 2022.07.19

* Vault란?

  • ID 기반 비밀 및 암호화 관리 시스템
  • 비밀은 공개되면 안되는 API 암호화키, 암호 또는 인증서와 같이 액세스를 엄격하게 제어하려는 모든 것
  • Vault는 인증 및 권한 부여 방법으로 차단되는 암호화 서비스를 제공

* 주요 기능

1. Secure Secret Storage

  • Vault에 임의의 키/값 비밀을 저장, Vault는 이러한 비밀을 영구 저장소에 쓰기전에 암호화하므로 원시 저장소에 대한 액세스 권한을 얻는 것만으로는 비밀에 액세스할 수 없다.

2. Dynamic Secrets

  • AWS 또는 SQL 데이터베이스와 같은 일부 시스템에 대해 온디맨드로 비밀을 생성할 수 있다.

3. Data Encryption

  • 데이터를 저장하지 않고 암호화 및 해독할 수 있습니다. 이를 통해 보안 팀은 암호화 매개변수를 정의하고 개발자는 자체 암호화 방법을 설계하지 않고도 SQL 데이터 베이스와 같은 위치에 암호화된 데이터를 저장할 수 있승비다.

4. Leasing and Renewal

  • 모든 비밀에는 관련 임대가 있습니다. 임대 기간이 끝나면 Vault는 해당 비밀을 자동으로 취소한다.

5. Revocation

  • 키 롤링과 침입 시 시스템 잠금을 지원한다.

* Vault docker 설치하기

1)  최신 vault 도커 이미지를 가져옴

$ docker pull vault
//또는
$ sudo docker pull vault

2) Host PC에 사용할 디렉토리를 만듬

$ sudo mkdir /vault/logs   -> 로그를 저장할 디렉토리
$ sudo mkdir /vault/files  -> 데이터를 저장할 디렉토리
$ sudo mkdir /vault/config -> 설정 디렉토리(HCL 또는 JSON 형태 파일)

3) 설정파일을 만듬

  • local.json 파일을 만들어 /vault/config 디렉토리로 복사, backend 데이터 저장소로 /vault/file 디렉토리를 사용
  • TTL(Time To Live = Duration)은 초 단위로 지정 및 표시, 시간으로 지정하고자 하는 경우 “h”를 붙여 문자열로 기입함
  • 프로젝트 성격과 보안 정책에 따라 기본 Lease TTL는 168시간(7일), 최대 Lease TTL은 720시간(30일)값을 설정할 수 있음
  • 참고로 Vault는 Eternity(token_duration) 영원히 유지되는 토큰은 Root Token만 지원 일반 Token은 TTL이 존재함, 만약 0으로 설정시 기본 32일(2,764,800초)로 설정됨
{
   "listener":{
      "tcp":{
         "address":"0.0.0.0:8200",
         "tls_disable":1
      }
   },
   "backend":{
      "file":{
         "path":"/vault/file"
      }
   },
   "default_lease_ttl":"876000h",   //100년
   "max_lease_ttl":"876000h",
   "ui":true,
   "log_level": "trace"
}
https://www.vaultproject.io/docs/configuration
자세한 설정 정보는 위의 링크 참고

4) docker 컨테이너를 실행

  • Vault의 8200번 포트를 외부에 열고 설정, backend 데이터, 로그 디렉토리를 Host 디렉토리와 연결
  • 옵션 중 —cap-add=IPC_LOCK은 강력하게 권장되는 옵션, IPC(Inter Process Communication)을 잠그는 것으로 메모리 스왑 공격으로부터 보호함 데몬실행 후 로깅할 때 콘솔을 계속 잡고있지 않도록 논블록킹으로 설정 —log-opt mode=non-blocking
//dev 용으로 inmemory 저장방식
$ sudo docker run --name devVault --cap-add=IPC_LOCK -e 'VAULT_DEV_ROOT_TOKEN=myroot' -p \
					8200:8200 vault 
                    
//volumn 바인딩을 해줘야 도커를 종료해도 데이터가 저장됨
$ sudo docker run --name vault -d --cap-add=IPC_LOCK -p 8200:8200 --log-opt mode=non-blocking \
            -v /vault/config:/vault/config \
            -v /vault/file:/vault/file \
            -v /vault/logs:/vault/logs vault server
  • docker logs 명령의 -f 옵션을 이용해서 위에서 만든 컨테이너의 로그들을 백그라운드모드로 stdout.log 파일에 기록합니다.
  • 리눅스는 가장 마지막에 &를 붙이면 백그라운드에서 실행하겠다는 의미
  • 2>&1 옵션은 stdout은 1, stderr은 2인데 stderr도 stdout으로 추가로 보내겠다는 의미 결국 stdout과 stderr 모두 남김없이 mystd.log 파일에 남기라는 의미
//리눅스인 경우
$ sudo chmod 777 /vault/logs
$ sudo docker logs -f vault >> /vault/logs/mystd.log 2>&1 &
$ tail -f /vault/logs/mystd.log

* 참고한 사이트

https://velog.io/@limsubin/Vault를-Docker로-올려보자

 

Vault란 ? vault를 Docker로 올려보자!

vault :v1.10.0OS : CentOS Linux release 7.8.2003(Core)Docker : 19.03.13ID 기반 비밀 및 암호화 관리 시스템비밀은 공개되면 안되는 API 암호화 키, 암호 또는 인증서와 같이 액세스를 엄격하게 제어하려는 모든 것

velog.io

'개발' 카테고리의 다른 글

Vault 설정하기(AWS EC2)_dev용  (0) 2022.07.19

https://www.edwith.org/cs50/joinLectures/15240

 

[해외명강] 컴퓨터 과학 교양 강좌: CS50 강좌소개 : edwith

- 커넥트재단

www.edwith.org

1. 알고리즘

- 입력값을 출력값의 형태로 바뀌기 위해 어떤 명령들이 수행되어야 하는지에 대한 규칙들의 순서적 나열

정확한 알고리즘

- 알고리즘은 입력을 출력으로 바꾸기 위해 컴퓨터가 따르는 일련의 절차

- 알고리즘의 평가할 때는 정확성도 중요하지만, 효율성도 중요합니다. 효율성은 작업을 완료하기까지 얼마나 시간과 노력을 덜 들일 수 있는지에 대한 척도입니다. 

// 전화번호부에서 Mike Smith를 찾는 일을 한다고 가정하자
pick up phone book			// 전화번호부를 집어들고 
open to first page of phone book	// 첫 페이지를 펼친 후
look at names				// Mike Smith가 그 페이지에 있는 지 찾습니다.
if "Smith" is among names		// Smith가 있다면 
	call Mike				// Mike에게 전화를 하면 끝
else if not at end of book 		// 그렇지 않으면 책의 끝까지
	flip to next page			// 다음 페이지로 넘긴다.
    go to line 3				// 3번째 줄로 돌아감.(재귀/반복)
else						// 책의 끝에도 없으면
	give up				// 전화번호부에 없으므로 포기한다.

효율적인 알고리즘(효율성)

pick up phone book				// 전화번호부를 집어든다. 
open to middle of phone book		// 전화번호부의 가운데를 펼친다.
look at names					// 이름들은 살펴본다.
if "Smith" is among names			// 만약 "Smith"라는 이름이 있으면
	call Mike					// "Mike"에게 전화를 건다.
else if "Smith" is earlier in book		// 그렇지않고 만약 "Smith"가 전화번호부 앞쪽에 있으면
	open to middle of left half of book //책의 왼쪽 반의 중간을 열어본다.
    go to line 3					// 3번째 줄로 돌아감 (재귀/반복)
else if "Smith" is later in book		// 그렇지 않고 만약 "Smith"가 전화번호부 뒤쪽에 있으면 
	open to middel of right half of book	// 책의 오른쪽 반의 중간을 열어본다.
    go to line 3						// 다시 3번째 줄로 돌아감 (재귀/반복)
else 								// 그렇지 않으면 열어본 장에도 없고 전화번호부 초반부나 후반부에도 없다면
	give up						// 포기하라

- 2번째 알고리즘이 1번째 알고리즘보다 더 효율적입니다. 만약 500페이지가 추가되었다고 가정해 봅시다. 첫번째 알고리즘을 사용한다면, 추가된 500페이지에 대해 절차가 500번 더 수행될 것입니다. 하지만 두 번째 알고리즘을 사용한다면 단 1번만 추가로 수행하면 됩니다.

 

2. 의사코드

- 컴퓨터 프로그램은 프로그래밍 언어로 작성됩니다. 프로그래밍 언어는 일반적으로 기계가 알아들을 수 있도록 명령을 내리기 위해 사용되는 언어입니다. 의사코드는 프로그래밍 언어보다 문법적 제약을 적게 받으므로 알고리즘 표현에 많이 사용됩니다.

- 방 안에 있는 사람의 수를 세기 위한 알고리즘을 만들어야 한다고 생각해 봅시다. 우리는 숫자 0부터 시작할 것이고 방안에 있는 각각의 사람을 셀 때마다 1씩 더할 것입니다.

//방 안에 있는 사람 수 세기 
let n = 0;
for each person in room
	sest n = n + 1;

- 프로그래밍 언어로 작성되지 않았는데도 위의 알고리즘은 굉장히 정교합니다. 1번 줄처럼 n이라는 이름을 부여하고 0값을 넣어주는 것으로 시작합니다. 이 과정을 '할당'이라고 합니다.

코드는 어떤 코드 블록이 어떤 문장에 포함되는지 알 수 있도록 들여쓰기를 합니다. 예를 들어 3번 줄에 들여쓰기 되어있는데, 이것은 2번줄에 작성된 '방에 사람이 있다면' 그 아래 줄들이 반복되어야 한다는 뜻입니다. 

 

의사 코드의 요소

- 의사 코드를 작성하는 올바른 방법이란 없습니다. 의사코드에는 반복문이나 조건문을 포함하기도 합니다. 의사코드에서 사용될 수 있는 이런 개념들은 프로그래밍 언어로 작성된 프로그램에서도 중요한 개념입니다. 프로그램 언어를 배운 후에도 의사 코드는 문법 걱정 없이 알고리즘을 단계별로 표현할 수 있는 유용한 방법이며 프로그램의 논리를 이해하는데 더 효과적인 방법입니다.

전화번호부에 적힌 전화번호 중, 한 번호가 다른 번호의 접두어인 경우가 있는지 확인하려 합니다.전화번호가 다음과 같을 경우, 구조대 전화번호는 영석이의 전화번호의 접두사입니다.
  • 구조대 : 119
  • 박준영 : 97 674 223
  • 지영석 : 11 9552 4421

전화번호부에 적힌 전화번호를 담은 배열 phone_book 이 solution 함수의 매개변수로 주어질 때, 어떤 번호가 다른 번호의 접두어인 경우가 있으면 false를 그렇지 않으면 true를 return 하도록 solution 함수를 작성해주세요.

제한 사항

  • phone_book의 길이는 1 이상 1,000,000 이하입니다.
    • 각 전화번호의 길이는 1 이상 20 이하입니다.
    • 같은 전화번호가 중복해서 들어있지 않습니다.

입출력 예제

phone_book return
["119", "97674223", "1195524421"] false
["123","456","789"] true
["12","123","1235","567","88"] false

 

입출력 예 설명

입출력 예 #1앞에서 설명한 예와 같습니다.

입출력 예 #2한 번호가 다른 번호의 접두사인 경우가 없으므로, 답은 true입니다.

입출력 예 #3첫 번째 전화번호, “12”가 두 번째 전화번호 “123”의 접두사입니다. 따라서 답은 false입니다.

내가 푼 코드

public class Main {
	public static void main(String[] args) {
		String[] phone_book = {"12", "345", "1"};
		boolean answer = true;
		List<Boolean> answerList = new ArrayList<Boolean>();
		Arrays.sort(phone_book);
		
		for(int i=0;i<phone_book.length-1;i++) {
			if(phone_book[i+1].startsWith(phone_book[i])) {
				answerList.add(true);
			}else {
				answerList.add(false);
			}
		}
		
		if(answerList.contains(true)) {
			answer = false;
		}else {
			answer = true;
		}
		
		System.out.println(answer);
	}
}

- Arrays.sort로 정렬시킨 후 startsWith를 사용하는 방식으로 접근했지만 테스트 12,13,15,19번 문제에서 false

boolean startsWith(String prefix)

비교 대상 문자열이 입력된 문자열값으로 시작되는지 여부를 확인하고 boolean값으로 리턴합니다.

비교대상문자열.startsWith("체크할문자열"); -> 123.starsWith(1);

 

참고한 문제풀이

public class Main {
	public static void main(String[] args) {

		String[] phone_book = {"12", "345", "1"};
		boolean answer = true;
		
		Map<String, Integer> map = new HashMap<>();
		
		for(int i=0;i<phone_book.length;i++) {
			map.put(phone_book[i], i);
			//map = {"12"=0,"345"=1,"1"=2}
		}
		
		for(int i=0;i<phone_book.length;i++) {
			//phone_book[i].length
			//phone_book[0].length = 2	
			for(int j=0;j<phone_book[i].length();j++) {
				//phone_book[0].substring(0,0) = x
				//phone_book[0].substring(0,1) = 1
				//map.containsKey(1) -> true 
				if(map.containsKey(phone_book[i].substring(0, j))) {
					answer = false;
				}
			}
		}
        
		System.out.println(answer);
    }
}

containsKey(key)

맵에서 인자로 보낸 키가 있으면 true,없으면 false를 반환한다.

containsValue(value)

맵에서 인자로 보낸 값이 있으면 true 없으면 false를 반환함

'코딩테스트' 카테고리의 다른 글

[프로그래머스] 완주하지 못한 선수(X) - Java  (0) 2022.05.23

수많은 마라톤 선수들이 마라톤에 참여하였습니다. 단 한 명의 선수를 제외하고는 모든 선수가 마라톤을 완주하였습니다.

마라톤에 참여한 선수들의 이름이 담긴 배열 participant와 완주한 선수들의 이름이 담긴 배열 completion이 주어질 때, 완주하지 못한 선수의 이름을 return 하도록 solution 함수를 작성해주세요.

제한사항

  • 마라톤 경기에 참여한 선수의 수는 1명 이상 100,000명 이하입니다.
  • completion의 길이는 participant의 길이보다 1 작습니다.
  • 참가자의 이름은 1개 이상 20개 이하의 알파벳 소문자로 이루어져 있습니다.
  • 참가자 중에는 동명이인이 있을 수 있습니다.

입출력 예

participant completion return
["leo", "kiki", "eden"] ["eden", "kiki"] "leo"
["marina", "josipa", "nikola", "vinko", "filipa"] ["josipa", "filipa", "marina", "nikola"] "vinko"
["mislav", "stanko", "mislav", "ana"] ["stanko", "ana", "mislav"] "vinko"
import java.util.HashMap;

class Solution {
    public String solution(String[] participant, String[] completion) {
        String answer = "";
        HashMap<String, Integer> hm = new HashMap<>();
        for (String player : participant) hm.put(player, hm.getOrDefault(player, 0) + 1);
        //hm : {ana=1, mislav=2, stanko=1}
        for (String player : completion) hm.put(player, hm.get(player) - 1);
	//hm : {ana=0, mislav=0, stanko=0}
        for (String key : hm.keySet()) {
            if (hm.get(key) != 0){
                answer = key;
            }
        }
        return answer;
    }
}

 

getOrDefault(Object key,V DefaultValue)
- 매개변수 : 이 메서드는 두 개의 매개 변수를 허용한다.
- key : 값을 가져와야 하는 요소의 키
- defaultValue : 지정된 키로 매핑된 값이 없는 경우 반환되어야 하는 기본값
- 반환값 : 찾는 key가 존재하면 해당 key에 매핑되어 있는 값을 반환하고 그렇지 않으면 디폴트값이 반환

ex) String[] arr = {"aaa","bbb","ccc","aaa","aaa","ccc"};
		
Map<String, Integer> map = new HashMap<String, Integer>();

for(String a : arr) {
   map.put(a, map.getOrDefault(a, 0)+1);
}

{aaa=3,ccc=2,bbb=1}

1.map에 "aaa"가 있는 지 확인하고 없으면 defalut 값인 0+1해서 {aaa=1} 이 들어감
2.map에 "bbb"가 있는 지 확인하고 없으면 defalut 값인 0+1해서 {aaa=1, bbb=1} 이 들어감
3.map에 "ccc"가 있는 지 확인하고 없으면 defalut 값인 0+1해서 {aaa=1, bbb=1, ccc=1} 이 들어감
4.map에 "aaa"가 있으므로 "aaa"의 value값을 가지고 와서 1+1해서 {aaa=2, bbb=1, ccc=1}이 들어감
- hashMap.keySet() -> HashMap에 저장된 key들을 Set객체로 리턴해줌
- Set객체 -> 중복값을 삽입할 수 없다, 특정한 순서를 가지고 있지 않다.

'코딩테스트' 카테고리의 다른 글

[프로그래머스] 전화번호 목록(X) - Java  (0) 2022.05.23

+ Recent posts