(AWS)React 앱 빌드,UI 테스트,배포,완료 처리 자동화 파이프라인 구축하기(3)

배경

아키텍쳐 다이어그램입니다. 클릭하면 크게 볼 수 있습니다.

지난 포스팅에서는 S3에 리액트 앱을 호스팅하기 위한 버킷 생성과 S3를 정리하기 위한 Lambda, 그리고 파이프라인의 이벤트를 알려주기 위한 SNS를 만들어보았습니다. 이번 포스팅에서는 CodePipeline에서 외부 람다를 호출하는 내용을 다루려 합니다. 아시다시피 람다 자체는 거의 모든 것을 할 수 있기 때문에 필요한 로직에 람다를 호출해 파이프라인의 여러 작업중 아직 AWS에서 구현되지 않은 작업을 수행할 수 있습니다.

이번시간엔 예제로 리액트로 만들어진 앱의 UI테스트를 위한 람다를 만들어보겠습니다.

1화-CodeCommit, CodeBuild
2화-S3,SNS
3화-UITest Lambda
4화-Codepipeline, CloudWatch Rule, CF 템플릿 공유


시작하기 전에

UI를 테스트하기 위한 람다는 템플릿에 포함되지 않아 수동으로 만들어야 합니다. 사실 Serverless 와 같은 프레임워크를 써 간단하게 개발 할 수 있지만, 해당 내용은 다음에 기회가 되면 다루기로 하고 이 포스팅에서는 람다를 직접 만들겠습니다.

마지막 포스트에서 공유하는 CloudFromation 템플릿에선 수동으로 람다를 만들어야 하는 점을 감안해 람다 이름을 명시하지 않으면 해당 부분을 자동으로 생략하도록 구성하였습니다. 따라서 아래 설명할 람다를 굳이 만들고 싶지 않으신 분은 다음 포스트로 넘어가셔도 무방합니다.


UI Test Lambda 소스코드

GitHub에 예제 소스코드를 올려두었습니다. [링크]

포스팅의 주제 자체가 UI테스트가 아니고 빌드/배포 파이프라인이기 때문에 테스트를 위한 Lambda를 간단하게 만들고 CodePipeline에서 외부 람다를 호출하는 방법을 중심으로 설명하겠습니다.

CodePipeline에서 외부 람다를 호출하면 파이프라인에호출 결과에 대해 알려줄 필요가 있습니다. 그래야 람다가 성공적으로 수행되었는지를 파악해서 파이프라인을 실패 처리 할지 계속 진행할 지를 판단할 수 있기 때문입니다. 람다의 처리 결과를 CodePipeline에 알려주는 API는 codepipeline:putJobFailureResult(실패시)/codepipeline:putJobSuccessResult(성공시) 입니다. 람다 호출은 다음 순서로 진행됩니다.

  1. CodePipeline에서 스테이지에 도달하면 람다를 호출하며 JobID와 파라메터를 전달
  2. 람다에서 받은 파라메터로 로직을 처리
  3. 처리 결과에 따라 putJobFailureResult/putJobSuccessResult를 JobID와 같이 전달하여 호출
  4. 성공시 계속 진행, 실패시 파이프라인 실패 처리

우선 NodeJS 환경으로 Puppeteer을 사용해 UI 테스트를 하겠습니다.

yarn 또는 npm을 사용해 Puppeteer와 chrome-aws-lambda 를 설치합니다.
다음은 프로젝트의 package.json입니다.

package.json
1
2
3
4
5
6
{
"dependencies": {
"chrome-aws-lambda": "^8.0.2",
"puppeteer-core": "^9.0.0"
}
}

람다 내용은 간단합니다. URL주소를 전달받아 해당 페이지에 “환영합니다.” 가 있는지 체크하여 다면 성공처리, 찾을 수 없다면 실패 처리를 하고 결과를 CodePipeline에 전달합니다. 물론 실제 구현에서는 조금 더 복잡하고 긴 테스트를 거치게 됩니다.

index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64


const AWS = require('aws-sdk');
AWS.config.update({
region: "ap-northeast-2"
});
const chromium = require('chrome-aws-lambda');
exports.handler = async (event, context) => {
console.log(event);
console.log(event["CodePipeline.job"].data.actionConfiguration.configuration);
var codepipeline = new AWS.CodePipeline();
var jobId = event["CodePipeline.job"].id;
const UserParameters = event["CodePipeline.job"].data.actionConfiguration.configuration.UserParameters.split(",");
let browser = null;
try {
browser = await chromium.puppeteer.launch({
args: chromium.args,
defaultViewport: chromium.defaultViewport,
executablePath: await chromium.executablePath,
headless: chromium.headless,
ignoreHTTPSErrors: true,
});
console.log("page url:", UserParameters[0])
let page = await browser.newPage();
await page.goto(`${UserParameters[0]}`);

//"환영합니다." 가 있다면,
let find = await page.$x(`//p[contains(., '환영합니다.')]`);
if (find.length < 1) {
var failedParm = {
jobId: jobId,
failureDetails: {
message: "환영합니다를 찾지 못했습니다.",
type: 'JobFailed',
externalExecutionId: context.awsRequestId
}
};
await codepipeline.putJobFailureResult(failedParm).promise();
}
else {
await codepipeline.putJobSuccessResult({ jobId: jobId }).promise();
}

} catch (error) {
console.log(error);
console.log(e);
var failedParm = {
jobId: jobId,
failureDetails: {
message: JSON.stringify(e.message),
type: 'JobFailed',
externalExecutionId: context.awsRequestId
}
};
await codepipeline.putJobFailureResult(failedParm).promise();
} finally {
if (browser !== null) {
let pages = await browser.pages()
await Promise.all(pages.map(page => page.close()))
await browser.close();
}
}
}

만약 예제 앱을 수정해 “환영합니다”를 지운다면 테스트는 실패하게 되고 Lambda는 CodePipeline에 테스트가 실패했음을 전달하게 됩니다.


UI Test Lambda 역할 생성

우선 람다는 CodePipeline의 putJobFailureResult/putJobFailureResult API를 호출할 수 있는 권한이 있어야 합니다. 권한을 부여하기 위해 역할(role)을 먼저 생성하겠습니다.

  • IAM에서 역할에서 역할 생성을 누릅니다.

IAM 역할을 생성합니다.

  • 신뢰 서비스에 Lambda를 클릭하고 다음으로 넘어갑니다.

신뢰 서비스에 Lambda를 선택합니다.

  • 따로 정책을 부여할 예정이기 때문에 따로 정책을 선택하지 않고 다음으로 넘어갑니다.

  • 적절한 이름을 부여합니다.(예시는 lambdaUITestRole)

적당한 이름을 입력합니다.

  • 방금 만든 역할을 눌러 인라인 정책을 추가하겠습니다.

인라인 정책을 추가합니다.

  • JSON탭을 누르고 다음 정책을 복사합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:CreateLogGroup"
],
"Resource": "arn:aws:logs:*:*:*"
},
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"codepipeline:PutJobFailureResult",
"codepipeline:PutJobSuccessResult"
],
"Resource": "*"
}
]
}
  • 다음을 눌러 진행 후 적절한 이름을 부여합니다.

UI Test Lambda 생성

실제 람다를 생성하겠습니다.

  • 우선 람다로 진입해 람다를 생성합니다. 설정에서 이름을 부여후 (예시는:lambdaUITest) 런타임은 node.JS 12.x로 설정합니다. 그리고 기존 역할 사용을 눌러 아까 전 만들었던 역할을 선택합니다.

스크린샷 처럼 세팅합니다..

  • 함수 생성을 눌러 함수를 생성합니다.

  • 우선 우측의 “에서 업로드” 를 눌러 zip파일을 선택후 아까 생성한 람다 프로젝트의 node_moudles와 index.js를 zip파일로 생성해 업로드 합니다.

에서 업로드는 upload from의 번역입니다(..)

  • 소스 코드 업로드후 위의 텝에서 구성을 눌러 일반구성의 편집을 누릅니다.

일반구성은 구성을 누르면 바로 선택되어 있습니다.

  • 편집의 제한시간을 넉넉하게 10분 정도로 만들고 메모리도 1024gb로 넣어준후 저장을 누릅니다.

실제로는 이만큼 걸리지 않지만 그냥 넉넉하게 잡아줍니다.

람다에서 Puppeteer를 구동하기 위한 충분한 시간을 타임아웃으로 주지 않을경우 테스트가 실패할 수 있습니다.

마치며

이번 포스팅에서는 CodePipeline에서 호출할 람다의 예시로 UI를 테스트하는 람다를 만들어 보았습니다. 다음 포스팅에서는 지금까지 만든 모든 서비스를 통합하여 관리해줄 CodePipeline과 필요한 CloudWatch Event를 만들어보겠습니다.

WRITTEN BY
Dev Lead | Certified Professional AWS Solutions Architect/Devops Engineer

댓글