본문 바로가기
nestjs

Nestjs 테스트코드 + Github action으로 EC2 자동화 배포

by Rogan_Kim 2023. 8. 29.
728x90

과정

1. test 코드 작성

2. gtihub action yml 작성

 

 

 

1. test code 작성 

- test module 만들기

describe('FirebaseService', () => {
  let service: FCMService;
  let module: TestingModule;

  const userId = 1;
  let createdFcmToken: FcmToken;

  afterAll(async () => {
    await module.close();
  });

  beforeAll(async () => {
    module = await Test.createTestingModule({
      imports: [
        ConfigModule.forRoot({
          isGlobal: true,
          envFilePath: [`.env`],
        }),
        TypeOrmModule.forRootAsync({
          useClass: MySqlConfigService,
        }),
        forwardRef(() => UserModule),
        TypeOrmModule.forFeature([FcmToken]),
      ],
      providers: [FCMService],
    }).compile();
    service = module.get<FCMService>(FCMService);
  });

});

beforeAll을 사용하여 모듈 1번만 만들기

afterAll을 사용하여 module 닫아주기

(module을 닫지 않으면 아래의 경고문이 나온다)

A worker process has failed to exit gracefully and has been force exited. This is likely caused by tests leaking due to improper teardown. Try running with --detectOpenHandles to find leaks. Active timers can also cause this, ensure that .unref() was called on them.

 

 

- 테스트 코드  작성 (제일 간단한 부분 예시)

import { forwardRef } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { Test, TestingModule } from '@nestjs/testing';
import { TypeOrmModule } from '@nestjs/typeorm';
import { MySqlConfigService } from 'src/database/mysqlConfig.service';
import { UserModule } from 'src/user/user.module';

import { CreateFcmToken } from './dto/create-fcm-token';
import { FcmToken } from './entities/fcm-token.entity';
import { FCMService } from './fcm.service';

describe('FirebaseService', () => {
  let service: FCMService;
  let module: TestingModule;

  const userId = 1;
  let createdFcmToken: FcmToken;

  afterAll(async () => {
    await module.close();
  });

  beforeAll(async () => {
    module = await Test.createTestingModule({
      imports: [
        ConfigModule.forRoot({
          isGlobal: true,
          envFilePath: [`.env`],
        }),
        TypeOrmModule.forRootAsync({
          useClass: MySqlConfigService,
        }),
        forwardRef(() => UserModule),
        TypeOrmModule.forFeature([FcmToken]),
      ],
      providers: [FCMService],
    }).compile();
    service = module.get<FCMService>(FCMService);
  });

  it('should be defined', () => {
    expect(service).toBeDefined();
  });

  it('create fcm token', async () => {
    const object: CreateFcmToken = {
      token:
        'dKHmSjkxT8aa-y4ZuTjHal:APA91bG-ipMBtARo-MU_wuE9B5RJA0D9oLW5bosmFu8qAo7Imru99WZ1XbGwASDHmBMxHmnOgr4MR-5l7G41VCQGRjfP4VP-f-66s9fdMFv9gR-n0DJvebs71VmX_pSXpwxzVOeL-YTx',
      userId,
    };
    createdFcmToken = await service.createFcmToken(object);

    expect(createdFcmToken.token).toEqual(object.token);
  });

  it('update fcm token', async () => {
    const updateToken = {
      userId,
      token: 'aaaaaaa',
    } as CreateFcmToken;
    await service.updateFcmToken(updateToken);
    const updatedToken = await service.getFcmToken(userId);
    expect(updatedToken?.token).toEqual('aaaaaaa');
    await service.deleteFcmToken(updatedToken!.id);
  });
});

 

 

1.  gtihub action yaml 작성

- Actions secrets and variables 세팅

경로 :  https://github.com/{{ repo_name }}/settings/secrets/actions

해당되는 레포에 Settings > secrets > actions

 

- test code 작성

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Node.js 16.x
        uses: actions/setup-node@v3
        with:
          node-version: 16.x

      - name: Setting environment variables
        run: |
          echo "DATABASE_HOST=$DATABASE_HOST" >> .env
          echo "DATABASE_PORT=$DATABASE_PORT" >> .env
          echo "DATABASE_USER_NAME=$DATABASE_USER_NAME" >> .env
          echo "DATABASE_PASSWORD=$DATABASE_PASSWORD" >> .env
          echo "DATABASE_DB=$DATABASE_DB" >> .env
          echo "JWT_SECRET_KEY=$JWT_SECRET_KEY" >> .env
          echo "PORT=$PORT" >> .env
        env:
          DATABASE_HOST: ${{secrets.DATABASE_HOST}}
          DATABASE_PORT: ${{secrets.DATABASE_PORT}}
          DATABASE_USER_NAME: ${{secrets.DATABASE_USER_NAME}}
          DATABASE_PASSWORD: ${{secrets.DATABASE_PASSWORD}}
          DATABASE_DB: ${{secrets.DATABASE_DB}}
          JWT_SECRET_KEY: ${{secrets.JWT_SECRET_KEY}}
          PORT: ${{secrets.PORT}}

      - name: Install Dependencies
        run: npm install

      - name: Run the test
        run: npm run test
        continue-on-error: false # 테스트 실패 시 작업 중지

publish전에 테스트코드를 실행합니다.

 

- ssh-action으로 ec2 접근

      - name: Connect AWS Instance
        uses: appleboy/ssh-action@master

        with:
          host: ${{ secrets.EC2_HOST }} # AWS EC2 인스턴스의 호스트 주소
          username: ${{ secrets.SSH_USERNAME }} # SSH 접속에 사용되는 사용자 이름
          key: ${{ secrets.SSH_PRIVATE_KEY }} # SSH 키 (비밀)
          script: |
            whoami
            ls -al
            cd chaam_server/
            git pull
            export NVM_DIR="$HOME/.nvm"
            [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
            npm run pm2:restart

(이슈)  npm command not found > https://github.com/appleboy/ssh-action/issues/21

아래의 코드가 추가된 이유 

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"

 

 

- (번외) github을 private로 관리하여 ssh key로 pull 권한 주는 방법 참고

 

https://github.com/settings/keys 해당 링크를 통해 Authentication key 등록

 

 

- ec2 터미널로 접속하여 ssh키를 생성해야 합니다

https://www.lainyzine.com/ko/article/creating-ssh-key-for-github/   < 참고

 

 

 

전체 yml 코드

name: CHAAM SERVER PUBLISH

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Node.js 16.x
        uses: actions/setup-node@v3
        with:
          node-version: 16.x

      - name: Setting environment variables
        run: |
          echo "DATABASE_HOST=$DATABASE_HOST" >> .env
          echo "DATABASE_PORT=$DATABASE_PORT" >> .env
          echo "DATABASE_USER_NAME=$DATABASE_USER_NAME" >> .env
          echo "DATABASE_PASSWORD=$DATABASE_PASSWORD" >> .env
          echo "DATABASE_DB=$DATABASE_DB" >> .env
          echo "JWT_SECRET_KEY=$JWT_SECRET_KEY" >> .env
          echo "PORT=$PORT" >> .env
        env:
          DATABASE_HOST: ${{secrets.DATABASE_HOST}}
          DATABASE_PORT: ${{secrets.DATABASE_PORT}}
          DATABASE_USER_NAME: ${{secrets.DATABASE_USER_NAME}}
          DATABASE_PASSWORD: ${{secrets.DATABASE_PASSWORD}}
          DATABASE_DB: ${{secrets.DATABASE_DB}}
          JWT_SECRET_KEY: ${{secrets.JWT_SECRET_KEY}}
          PORT: ${{secrets.PORT}}

      - name: Install Dependencies
        run: npm install

      - name: Run the test
        run: npm run test
        continue-on-error: false # 테스트 실패 시 작업 중지

      - name: Connect AWS Instance
        uses: appleboy/ssh-action@master

        with:
          host: ${{ secrets.EC2_HOST }} # AWS EC2 인스턴스의 호스트 주소
          username: ${{ secrets.SSH_USERNAME }} # SSH 접속에 사용되는 사용자 이름
          key: ${{ secrets.SSH_PRIVATE_KEY }} # SSH 키 (비밀)
          script: |
            whoami
            ls -al
            cd chaam_server/
            git pull
            export NVM_DIR="$HOME/.nvm"
            [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
            npm run pm2:restart

 

성공까지 실행한 횟수..

속 섞였던 에러

728x90

'nestjs' 카테고리의 다른 글

Server-Sent Events(SSE) in nestjs  (0) 2023.10.15
open-ai chat-gpt streaming 통신 기록  (0) 2023.10.14
nestjs socket server https 접속  (0) 2023.09.05

댓글