테스트
테스트 (Tests)
HBase의 단위 테스트와 통합 테스트 작성·분류·실행 방법을 살펴볼게요. HBase 테스트는 다른 프로젝트에서 보기 드문 특징이 많아요. 작은(small)·중간(medium)·큰(large)·통합(integration) 카테고리 분류, JUnit Category 주석, HBase ClassRule, 그리고 ChaosMonkey 기반 파괴적 테스트까지 다뤄요.
출처: 문서
본문
개발자라면 최소한 단위 테스트 세부 사항을 숙지해야 해요. HBase의 단위 테스트는 다른 프로젝트에서 보통 볼 수 없는 특성이 있어요.
이 정보는 HBase 자체의 단위 테스트에 대한 것이에요. HBase 애플리케이션을 위한 단위 테스트 개발은 Unit Testing HBase Applications를 참고해 주세요.
Apache HBase 모듈 (Apache HBase Modules)
0.96부터 Apache HBase는 여러 모듈로 나뉘어 있어요. 이것은 테스트를 어떻게, 어디에 작성하는지에 대한 "흥미로운" 규칙을 만들어요. hbase-server용 코드를 작성한다면 단위 테스트 작성법은 Unit Tests를 참고해 주세요. 이 테스트들은 minicluster를 띄울 수 있고 분류(categorized)되어야 해요. hbase-common 같은 다른 모듈의 테스트는 엄격한 단위 테스트여야 하며 테스트 대상 클래스만 테스트해야 해요. HBaseTestingUtility나 minicluster의 사용은 허용되지 않아요(의존성 트리상 심지어 가능하지도 않아요).
3.0.0부터 HBaseTestingUtility는 HBaseTestingUtil로 이름이 바뀌고 IA.Private로 표시돼요. 물론 API는 여전히 동일해요.
HBase 셸 테스트하기 (Testing the HBase Shell)
HBase 셸과 그 테스트는 주로 jruby로 작성돼요.
이 테스트들을 표준 빌드의 일부로 실행하기 위해, jruby로 구현된 테스트를 로드하고 실행하는 몇 가지 JUnit 테스트 클래스가 있어요. 테스트는 클래스 레벨 타임아웃을 수용하도록 별도 클래스로 나뉘었어요(Unit Tests에서 자세히 참고). 탑 레벨에서 다음으로 이 모든 테스트를 실행할 수 있어요.
mvn clean test -Dtest=Test*Shell
이전에 mvn install을 했다면 maven에 hbase-shell 모듈의 테스트만 실행하라고 지시할 수 있어요.
mvn clean test -pl hbase-shell
또는 시스템 변수 shell.test를 사용해 실행할 셸 테스트를 제한할 수 있어요. 이 값은 이름으로 특정 테스트 케이스의 ruby literal 동등물을 지정해야 해요. 예를 들어 테이블 변경을 위한 셸 명령을 다루는 테스트는 AdminAlterTableTest 테스트 케이스에 포함되어 있으며 다음으로 실행할 수 있어요.
mvn clean test -pl hbase-shell -Dshell.test=/AdminAlterTableTest/
Ruby 정규식 literal(/pattern/ 스타일)을 사용해 테스트 케이스 집합을 선택할 수도 있어요. 일반 관리와 보안 관리를 포함한 모든 HBase admin 관련 테스트를 다음 명령으로 실행할 수 있어요.
mvn clean test -pl hbase-shell -Dshell.test=/.*Admin.*Test/
테스트 실패 시 surefire 보고서 결과의 XML 버전을 살펴보면 세부 사항을 볼 수 있어요.
vim hbase-shell/target/surefire-reports/TEST-org.apache.hadoop.hbase.client.TestShell.xml
다른 모듈에서 테스트 실행하기 (Running Tests in other Modules)
개발 중인 모듈이 다른 HBase 모듈에 의존성이 없다면 해당 모듈로 cd해서 다음만 실행하면 돼요.
mvn test
그냥 그 모듈의 테스트만 실행할 거예요. 다른 모듈에 대한 의존성이 있다면 ROOT HBASE DIRECTORY에서 명령을 실행해야 해요. 이렇게 하면 다른 모듈의 테스트도 실행되는데, 해당 모듈의 테스트를 건너뛰도록 지정하지 않는 한 그렇지 않아요. 예를 들어 hbase-server 모듈의 테스트를 건너뛰려면 탑 레벨 디렉터리에서 다음을 실행해 hbase-server를 제외한 모든 모듈의 테스트를 실행하세요.
mvn clean test -PskipServerTests
여러 모듈에 대해 테스트 건너뛰기를 지정할 수도 있고 단일 모듈만 지정할 수도 있어요. 예를 들어 hbase-server와 hbase-common의 테스트를 건너뛰려면 다음을 실행해요.
mvn clean test -PskipServerTests -PskipCommonTests
또한 hbase-server 모듈에서 테스트를 실행한다면 Running tests에서 논의된 maven 프로파일을 적용해 테스트가 제대로 실행되도록 해야 해요.
단위 테스트 (Unit Tests)
Apache HBase 단위 테스트는 Category 주석을 반드시 가져야 하고, hbase-2.0.0부터 HBase ClassRule이 찍혀 있어야 해요. Category와 ClassRule이 포함된 Test Class가 어떻게 생겼는지 예는 다음과 같아요.
...
@Category(SmallTests.class)
public class TestHRegionInfo {
@ClassRule
public static final HBaseClassTestRule CLASS_RULE =
HBaseClassTestRule.forClass(TestHRegionInfo.class);
@Test
public void testCreateHRegionInfoName() throws Exception {
// ...
}
}
여기서 Test Class는 TestHRegionInfo예요. CLASS_RULE은 모든 테스트 클래스에서 같은 형태이며, 전달하는 .class만 로컬 테스트의 것이에요. 즉 TestTimeout Test Class에서는 위의 TestHRegionInfo.class 대신 CLASS_RULE에 TestTimeout.class를 전달해요. CLASS_RULE은 타임아웃(현재 모든 테스트에 대해 하드 리밋 13분(780초)으로 설정)과 기타 교차 단위 테스트 기능을 강제하는 곳이에요. 이 테스트는 SmallTest Category에 있어요.
Category는 임의적일 수 있고 목록으로 제공될 수 있지만, 각 테스트는 반드시 다음 크기 목록(small, medium, large, integration) 중 하나를 가져야 해요. 테스트 크기는 JUnit 카테고리 SmallTests, MediumTests, LargeTests, IntegrationTests를 사용해 지정돼요. JUnit Category는 java 주석을 사용해 표시돼요(특수 단위 테스트가 모든 단위 테스트에서 @Category 주석의 존재를 찾고 크기 표시가 없는 테스트 스위트를 찾으면 실패해요).
처음 세 카테고리(small, medium, large)는 $ mvn test를 입력할 때 실행되는 테스트 케이스를 위한 것이에요. 즉 이 세 분류는 HBase 단위 테스트를 위한 것이에요. integration 카테고리는 단위 테스트가 아니라 통합 테스트를 위한 것이에요. 이 테스트는 보통 $ mvn verify를 호출할 때 실행돼요. 통합 테스트는 Integration Tests에서 설명해요.
계속 읽어 새 HBase 테스트 케이스에 small, medium, large 집합 중 어떤 주석을 붙일지 파악해 주세요.
테스트 분류하기 (Categorizing Tests)
작은 테스트 (Small Tests):
작은 테스트 케이스는 별도 JVM에서 실행되며 각 테스트 스위트/테스트 클래스가 15초 이내에 실행되어야 해요. 즉 테스트 메서드로 구성된 java 객체인 junit 테스트 픽스처는 테스트 메서드가 몇 개든 15초 미만에 끝나야 해요. 이런 테스트 케이스는 minicluster를 사용하면 안 돼요. minicluster는 테스트 대상과 대부분 무관한 많은 서비스를 시작하니까요.
중간 테스트 (Medium Tests):
중간 테스트 케이스는 별도 JVM에서 실행되며 개별 테스트 스위트나 테스트 클래스(junit 용어로 test fixture)가 50초 이내에 실행되어야 해요. 이 테스트 케이스는 mini cluster를 사용할 수 있어요. 테스트 픽스처당 JVM 하나(그리고 종종 클러스터 하나)를 시작하므로, 테스트 메서드마다 jvm(과 클러스터)을 띄우기보다 수십 초 동안 실행되며 여러 테스트를 결합해 많은 테스트를 하는 테스트 픽스처를 작성해 시작 비용을 충분히 활용하세요. 이 관행이 전체 테스트 시간에 도움이 될 거예요.
큰 테스트 (Large Tests):
큰 테스트 케이스는 그 외 전부예요. 보통 대규모 테스트, 특정 버그에 대한 회귀 테스트, 타임아웃 테스트, 성능 테스트예요. 어떤 큰 테스트 스위트도 13분보다 길게 걸릴 수 없어요. 타임아웃으로 종료될 거예요. 더 오래 실행해야 한다면 Integration Test로 캐스팅하세요.
통합 테스트 (Integration Tests):
통합 테스트는 시스템 레벨 테스트예요. 자세한 내용은 Integration Tests를 참고해 주세요. 통합 테스트에 $ mvn test를 호출하면 테스트에 대한 타임아웃이 없어요.
테스트 실행 (Running tests)
hbase 브랜치의 테스트 상태는 다양해요. 어떤 브랜치는 좋은 테스트 위생을 유지하며 어쩌다 드물게 flaky 테스트 실패가 있어도 모든 테스트가 확실히 통과해요. 다른 브랜치는 빈번한 flakies와 때로는 100% 실패하는 주의가 필요한 깨진 테스트까지 있어 상황이 덜 좋을 수 있어요. 현재 관심 있는 브랜치의 테스트 상태를 파악해 보세요. 아파치 jenkins 빌드의 현재 야간 상태가 좋은 시작점이에요. master 브랜치의 테스트는 일반적으로 최상의 상태가 아니에요. master에서 릴리스가 덜 빈번하기 때문이죠. 특히 "패치는 master 브랜치에 먼저 상륙한다"는 우리 격언을 고려하면 패치 상륙을 어렵게 만들 수 있어요.
전체 테스트 스위트는 CPU 4개와 최소 병렬성의 빈약한 VM에서 5-6시간, 수십 개 CPU와 충분한 RAM을 가진 linux 머신에서는 50분 이하가 걸릴 수 있어요.
전체 테스트 스위트를 실행하려 할 때 테스트 러너 사용자의 nproc(ulimit -u — 병렬성을 더 늘리면 6000보다 크게), 열린 파일 수(ulimit -n — 10240 이상) 한계를 높여야 해요. 제약 때문에 테스트 실행이 오류를 내는 경우는 종종 그 한계와 모호하게만 관련돼 있어요. 현재 사용자 설정은 ulimit -a로 볼 수 있어요.
기본값: small과 medium 카테고리 테스트
mvn test를 실행하면 모든 small 테스트를 단일 JVM에서(fork 없이) 실행하고 각 테스트 인스턴스에 대해 fork된 별도 JVM에서 medium 테스트를 실행해요('small' 테스트 등 정의는 Unit Tests 참고). 작은 테스트에 오류가 있으면 medium 테스트는 실행되지 않아요. Large 테스트는 실행되지 않아요.
모든 테스트 실행
mvn test -P runAllTests를 실행하면 small 테스트를 단일 JVM에서, 그다음 medium과 large 테스트를 각 테스트에 대해 fork된 별도 JVM에서 실행해요. 작은 테스트에 오류가 있으면 medium과 large 테스트는 실행되지 않아요.
단일 테스트 또는 패키지의 모든 테스트 실행
개별 테스트(예: MyTest)를 실행하려면 mvn test -Dtest=MyTest를 실행하세요. 여러 개별 테스트를 쉼표로 구분된 목록으로 전달할 수도 있어요.
mvn test -Dtest=MyTest1,MyTest2,MyTest3
패키지를 전달해 그 패키지 아래의 모든 테스트를 실행할 수도 있어요.
mvn test '-Dtest=org.apache.hadoop.hbase.client.*'
-Dtest가 지정되면 localTests 프로파일이 사용돼요. 각 junit 테스트는 별도 JVM에서 실행돼요(테스트 클래스당 fork 하나). 이 모드에서 테스트가 실행될 때 병렬화는 없어요. -report 끝에 "[INFO] Tests are skipped"라는 새 메시지가 보일 거예요. 무해해요. 그러나 존재하지 않는 테스트 케이스를 지정해도 오류가 보고되지 않으므로, 테스트 보고서의 Results: 섹션에서 Tests run: 의 합이 지정한 테스트 수와 일치하는지 확인해야 해요.
기타 테스트 호출 변형
mvn test -P runSmallTests를 실행하면 단일 JVM을 사용해 "small" 테스트만 실행해요. mvn test -P runMediumTests를 실행하면 "medium" 테스트만 실행하며 각 test-class마다 새 JVM을 띄워요. mvn test -P runLargeTests를 실행하면 "large" 테스트만 실행하며 각 test-class마다 새 JVM을 띄워요. 편의상 mvn test -P runDevTests를 실행해 단일 JVM을 사용해 small과 medium 테스트를 모두 실행할 수 있어요.
테스트 더 빠르게 실행 (Running tests faster)
기본적으로 $ mvn test -P runAllTests는 테스트 실행을 호스팅하는 머신의 CPU 4분의 1로 모든 테스트를 실행해요(탑 레벨 hbase pom.xml의 surefire.firstPartForkCount와 surefire.secondPartForkCount 참고. 기본값은 0.25C, 즉 CPU 수의 1/4). 이 카운트를 올리면 빌드가 더 빨리 실행돼요. maven을 호출할 때 --threads=N을 전달해 의존성 그래프가 허용할 때 hbase 모듈이 테스트를 병렬로 실행하게 할 수도 있어요. 여기서 N은 원하는 모듈 병렬성 양이에요.
예를 들어 머신의 모든 코어를 테스트 실행에 사용하려면 다음으로 maven 테스트 실행을 시작할 수 있어요.
$ x="1.0C"; mvn -Dsurefire.firstPartForkCount=$x -Dsurefire.secondPartForkCount=$x test -PrunAllTests
32 코어 머신이라면 각각 단위 테스트를 실행하는 32개의 fork된 jvm이 프로세스 목록에 나타나는 시기가 보일 거예요. 상황은 다를 수 있어요. 하드웨어에 따라 CPU 및/또는 메모리 과잉 할당이 테스트 스위트를 무너뜨릴 수 있으며, 보통 테스트 시스템 exit과 불완전한 테스트 보고서 xml 파일로 불평해요. 기본 fork부터 시작해 점진적으로 올리세요.
--threads=N을 추가하면 maven이 N개의 maven 모듈을 병렬로 실행해요(모듈 상호 의존성이 허용할 때). forkcount를 1.0C로 설정하고 --threads 카운트를 '2'로 설정하면 동시 테스트 러너 수가 2 * CPU에 근접할 수 있고, 이는 호스트 머신을 과잉 할당할 가능성이 큰 수예요(그에 따른 테스트 exit 실패와 함께).
fork된 JVM당 약 2.2GB 메모리와 maven 자체가 사용하는 메모리(3-4G)가 필요해요.
RAM 디스크 (RAM Disk)
속도를 높이려면 ramdisk를 사용할 수도 있어요. 2-3G면 충분해요. 각 테스트 실행 사이에 파일을 삭제해야 해요. Linux에서 ramdisk를 구성하는 일반적인 방법은 다음과 같아요.
$ sudo mkdir /ram2G
sudo mount -t tmpfs -o size=2048M tmpfs /ram2G
그런 다음 2.0의 모든 HBase 테스트를 다음 명령으로 실행할 수 있어요.
mvn test -PrunAllTests -Dtest.build.data.basedirectory=/ram2G
hbasetests.sh
hbasetests.sh 스크립트를 사용할 수도 있어요. 이 스크립트는 두 개의 maven 인스턴스로 medium과 large 테스트를 병렬로 실행하고 단일 보고서를 제공해요. 이 스크립트는 hbase 버전의 surefire를 사용하지 않으므로 스크립트가 설정한 두 maven 인스턴스 외에는 병렬화가 없어요. pom.xml을 포함하는 디렉터리에서 실행해야 해요.
예를 들어 ./dev-support/hbasetests.sh를 실행하면 small과 medium 테스트를 실행해요. ./dev-support/hbasetests.sh runAllTests를 실행하면 모든 테스트를 실행해요. ./dev-support/hbasetests.sh replayFailed를 실행하면 실패한 테스트를 별도 jvm에서 병렬화 없이 두 번째 실행해요.
테스트 타임아웃 (Test Timeouts)
HBase 단위 테스트 크기 분류 타임아웃은 엄격하게 강제되지 않아요.
10분보다 오래 실행되는 테스트는 타임아웃/종료돼요.
hbase-2.0.0부터 모든 테스트 메서드별 타임아웃을 제거했어요. 즉:
...
@Test(timeout=30000)
public void testCreateHRegionInfoName() throws Exception {
// ...
}
이것들은 권장되지 않으며, 전체 Test Fixture/Class/Suite가 얼마나 오래 걸리는지를 기준으로 타이밍을 잡고 테스트 메서드가 걸리는 시간의 분산이 컨텍스트에 따라 크게 달라지므로(부하가 걸린 Apache 인프라 대 다른 것이 아무것도 실행되지 않는 개발자 머신) 별 의미가 없어요.
테스트 리소스 검사기 (Test Resource Checker)
사용자 지정 Maven SureFire 플러그인 리스너가 각 HBase 단위 테스트 전후에 여러 리소스를 검사하고, Maven 모듈별 target/surefire-reports에서 찾을 수 있는 테스트 출력 파일 끝에 그 발견 사항을 기록해요(테스트는 테스트 클래스 이름으로 명명된 테스트 보고서를 이 디렉터리에 써요. *-out.txt 파일을 확인하세요). 계산되는 리소스는 스레드 수, 파일 디스크립터 수 등이에요. 수가 증가했으면 로그에 LEAK? 주석을 추가해요. 백그라운드에서 HBase 인스턴스가 실행 중일 수 있으므로 테스트에서 특별한 조치 없이도 일부 스레드가 삭제/생성될 수 있어요. 그러나 테스트가 예상대로 작동하지 않거나 테스트가 이런 리소스에 영향을 주지 말아야 한다면 ...hbase.ResourceChecker(157): before...와 ...hbase.ResourceChecker(157): after.... 로그 줄을 확인할 가치가 있어요. 예:
2012-09-26 09:22:15,315 INFO [pool-1-thread-1]
hbase.ResourceChecker(157): after:
regionserver.TestColumnSeeking#testReseeking Thread=65 (was 65),
OpenFileDescriptor=107 (was 107), MaxFileDescriptor=10240 (was 10240),
ConnectionCount=1 (was 1)
테스트 작성 (Writing Tests)
일반 규칙 (General rules)
- 가능한 한 테스트는 category small 테스트로 작성해야 해요.
- 모든 테스트는 같은 머신에서 병렬 실행을 지원하도록 작성해야 해요. 따라서 고정 포트나 고정 파일 이름 같은 공유 리소스를 사용하지 말아야 해요.
- 테스트는 과도하게 로깅하면 안 돼요. 초당 100줄 이상이면 로그를 읽기 어렵게 만들고, 다른 테스트에 없어서는 안 될 i/o를 사용해요.
- 테스트는 HBaseTestingUtility로 작성할 수 있어요. 이 클래스는 임시 디렉터리를 만들고 정리하거나 클러스터를 시작하는 헬퍼 함수를 제공해요.
카테고리와 실행 시간
- 모든 테스트는 분류되어야 해요. 그렇지 않으면 건너뛸 수 있어요.
- 모든 테스트는 가능한 한 빠르게 작성되어야 해요.
- 테스트 케이스 카테고리와 해당 타임아웃은 Unit Tests를 참고해 주세요. 이렇게 하면 사용하는 사람들이 좋은 병렬화를 얻고 테스트 실패 시 분석을 쉽게 할 수 있어야 해요.
테스트에서의 Sleep
가능하면 테스트는 Thread.sleep을 사용하지 말고 필요한 실제 이벤트를 기다려야 해요. 이게 더 빠르고 읽는 사람에게 명확해요. 테스트는 종료 조건을 테스트하지 않고 Thread.sleep을 하면 안 돼요. 이러면 테스트가 무엇을 기다리는지 이해할 수 있어요. 게다가 테스트는 머신 성능과 무관하게 작동할 거예요. Sleep은 가능한 한 빨리 하려면 최소여야 해요. 변수를 기다리는 것은 40ms sleep 루프로, 소켓 연산을 기다리는 것은 200ms sleep 루프로 해야 해요.
클러스터를 사용하는 테스트
HRegion을 사용하는 테스트는 클러스터를 시작할 필요가 없어요. region은 로컬 파일 시스템을 사용할 수 있으니까요. 클러스터 시작/중지는 약 10초가 걸려요. 테스트 메서드마다 시작하면 안 되고 테스트 클래스마다 시작해야 해요. 시작된 클러스터는 디렉터리를 정리하는 HBaseTestingUtility#shutdownMiniCluster로 종료해야 해요. 가능한 한 테스트는 클러스터의 기본 설정을 사용해야 해요. 그렇지 않으면 문서화해야 해요. 이러면 나중에 클러스터를 공유할 수 있어요.
테스트 스켈레톤 코드 (Tests Skeleton Code)
복사해 붙여 넣어 테스트 기여의 기반으로 사용할 수 있는 Categorization과 Category 기반 타임아웃 규칙이 있는 테스트 스켈레톤 코드가 있어요.
/**
* Describe what this testcase tests. Talk about resources initialized in @BeforeClass (before
* any test is run) and before each test is run, etc.
*/
// Specify the category as explained in Unit Tests section.
@Category(SmallTests.class)
public class TestExample {
// Replace the TestExample.class in the below with the name of your test fixture class.
private static final Log LOG = LogFactory.getLog(TestExample.class);
// Handy test rule that allows you subsequently get the name of the current method. See
// down in 'testExampleFoo()' where we use it to log current test's name.
@Rule public TestName testName = new TestName();
// The below rule does two things. It decides the timeout based on the category
// (small/medium/large) of the testcase. This @Rule requires that the full testcase runs
// within this timeout irrespective of individual test methods' times. The second
// feature is we'll dump in the log when the test is done a count of threads still
// running.
@Rule public static TestRule timeout = CategoryBasedTimeout.builder().
withTimeout(this.getClass()).withLookingForStuckThread(true).build();
@Before
public void setUp() throws Exception {
}
@After
public void tearDown() throws Exception {
}
@Test
public void testExampleFoo() {
LOG.info("Running test " + testName.getMethodName());
}
}
통합 테스트 (Integration Tests)
HBase 통합/시스템 테스트는 HBase 단위 테스트를 넘어서는 테스트예요. 일반적으로 오래 지속되고 크기가 크며(테스트는 1M행이나 1B행을 요청받을 수 있어요), 대상 지정이 가능하고(실행 대상인 기성 클러스터를 가리키는 구성을 받을 수 있어요. 통합 테스트는 클러스터 시작/중지 코드를 포함하지 않아요), 성공 검증 시 통합 테스트는 공개 API만 사용해요. 서버 내부를 조사해 성공/실패를 단정하지 않아요. 통합 테스트는 단위 테스트가 할 수 있는 것보다 릴리스 후보를 더 정교하게 증명해야 할 때 실행하는 것이에요. 이 테스트는 일반적으로 Apache Continuous Integration 빌드 서버에서 실행되지 않지만, 일부 사이트는 실제 클러스터에서 지속 테스트의 일부로 통합 테스트를 실행하기로 선택해요.
통합 테스트는 현재 hbase-it 하위 모듈의 src/test 디렉터리에 있으며 정규식 IntegrationTest.java와 일치해요. 모든 통합 테스트는 @Category(IntegrationTests.class)로도 주석 처리돼요.
통합 테스트는 mini cluster를 사용하거나 실제 분산 클러스터에 대해 두 모드로 실행할 수 있어요. Maven failsafe는 mini cluster를 사용해 테스트를 실행하는 데 사용돼요. IntegrationTestsDriver 클래스는 분산 클러스터에 대해 테스트를 실행하는 데 사용돼요. 통합 테스트는 mini cluster에 대해 실행 중이라고 가정하면 안 되고, 클러스터 상태에 접근하기 위해 private API를 사용하면 안 돼요. 분산 또는 mini cluster와 균일하게 상호작용하려면 IntegrationTestingUtility, HBaseCluster 클래스, 공개 client API를 사용할 수 있어요.
분산 클러스터에서 ChaosMonkey를 사용하거나 클러스터 관리자를 통해 서비스를 조작(예: regionserver 재시작)하는 통합 테스트는 SSH를 사용해 그렇게 해요. 이를 실행하려면 테스트 프로세스가 원격 측에서 명령을 실행할 수 있어야 하므로 ssh가 그에 맞게 구성되어야 해요(예: HBase가 클러스터에서 hbase 사용자로 실행된다면 그 사용자에 대해 passwordless ssh를 설정하고 그 사용자로도 테스트를 실행할 수 있어요). 이를 돕기 위해 hbase.it.clustermanager.ssh.user, hbase.it.clustermanager.ssh.opts, hbase.it.clustermanager.ssh.cmd 구성 설정을 사용할 수 있어요. "User"는 클러스터 관리자가 ssh 명령을 수행할 원격 사용자예요. "Opts"는 SSH에 전달되는 추가 옵션(예: "-i /tmp/my-key")을 포함해요. 마지막으로 사용자 지정 환경 설정이 있다면 "cmd"는 전체 tunnel(ssh) 명령의 재정의 형식이에요. 기본 문자열은 {/usr/bin/ssh %1$s %2$s%3$s%4$s "%5$s"}이며 좋은 시작점이에요. 이것은 원격 명령을 실행하는 데 사용되는 5개 인수를 가진 표준 Java 형식 문자열이에요. 인수 1(%1$s)은 opts 설정이나 환경 변수를 통해 설정된 SSH 옵션, 2는 SSH 사용자 이름, 3은 사용자 이름이 설정되면 "@" 그렇지 않으면 "", 4는 대상 호스트 이름, 5는 실행할 논리 명령(작은 따옴표를 포함할 수 있으므로 사용하지 마세요)이에요. 예를 들어 non-hbase 사용자로 테스트를 실행하지만 원격 머신에서 hbase로 전환해 ssh하고 싶다면 다음을 사용할 수 있어요.
/usr/bin/ssh %1$s %2$s%3$s%4$s "su hbase - -c \"%5$s\""
그렇게 해서 RS를 죽이려면(예) 통합 테스트가 다음을 실행할 수 있어요.
{/usr/bin/ssh some-hostname "su hbase - -c \"ps aux | ... | kill ...\""}
명령은 테스트 로그에 기록되므로 환경에 맞게 올바른지 검증할 수 있어요.
통합 테스트 실행을 비활성화하려면 명령 줄에 -PskipIntegrationTests 프로파일을 전달하세요. 예:
$ mvn clean install test -Dtest=TestZooKeeper -PskipIntegrationTests
mini cluster에 대해 통합 테스트 실행
HBase 0.92는 verify maven target을 추가했어요. 이를 호출하면(예: mvn verify로) maven failsafe 플러그인을 통해 verify 단계까지 모든 단계를 실행하여 위에서 언급한 모든 HBase 단위 테스트뿐 아니라 HBase 통합 테스트 그룹의 테스트도 실행해요. mvn install -DskipTests를 완료한 후 invoke만으로 통합 테스트만 실행할 수 있어요.
cd hbase-it
mvn verify
탑 레벨에서 통합 테스트만 실행하려면 두 명령을 실행해야 해요. 먼저:
mvn failsafe:integration-test
이것은 실제로 모든 통합 테스트를 실행해요.
이 명령은 테스트 실패가 있어도 항상 BUILD SUCCESS를 출력해요.
이 시점에서 출력을 손으로 grep해 실패한 테스트를 찾을 수 있어요. 그러나 maven이 대신 해줄 거예요. 그냥 사용하세요.
mvn failsafe:verify
위 명령은 기본적으로 모든 테스트 결과를 보고('target' 디렉터리를 제거하지 마세요) 테스트 실패를 보고해요.
통합 테스트 하위 집합 실행
이것은 단위 테스트 하위 집합 실행을 지정하는 것과 매우 비슷하지만(위 참고), test 대신 it.test 속성을 사용해요. IntegrationTestClassXYZ.java만 실행하려면 다음을 사용하세요.
mvn failsafe:integration-test -Dit.test=IntegrationTestClassXYZ -DfailIfNoTests=false
다음으로 통합 테스트 그룹을 실행하고 싶을 수도 있어요. 예를 들어 IntegrationTestClassX*.java로 명명된 모든 통합 테스트를 실행하려면:
mvn failsafe:integration-test -Dit.test=*ClassX* -DfailIfNoTests=false
이것은 ClassX와 일치하는 모든 통합 테스트를 실행해요. 즉 "/IntegrationTestClassX"와 일치하는 모든 것을 뜻해요. 쉼표로 구분된 목록을 사용해 여러 통합 테스트 그룹을 실행할 수도 있어요(단위 테스트와 유사). 일치 목록을 사용해도 각 그룹에 대한 전체 정규식 일치를 지원해요. 다음과 같을 거예요.
mvn failsafe:integration-test -Dit.test=*ClassX*,*ClassY -DfailIfNoTests=false
분산 클러스터에 대해 통합 테스트 실행
이미 설정된 HBase 클러스터가 있다면 IntegrationTestsDriver 클래스를 호출해 통합 테스트를 시작할 수 있어요. 먼저 test-compile을 실행해야 할 수도 있어요. 구성은 bin/hbase 스크립트가 선택할 거예요.
mvn test-compile
그런 다음 테스트를 시작하세요.
bin/hbase [--config config_dir] org.apache.hadoop.hbase.IntegrationTestsDriver
이 멋진 도구의 사용법은 -h를 전달해 얻으세요. 인수 없이 IntegrationTestsDriver를 실행하면 hbase-it/src/test 아래에서 @Category(IntegrationTests.class) 주석이 있고 이름이 IntegrationTests로 시작하는 테스트를 실행해요. -h를 전달해 테스트 클래스를 필터링하는 방법을 보세요. 전체 클래스 이름에 대해 검사되는 정규식을 전달할 수 있어요. 그래서 클래스 이름의 일부를 사용할 수 있어요. IntegrationTestsDriver는 Junit으로 테스트를 실행해요. 현재 maven을 사용해 분산 클러스터에 대해 통합 테스트를 실행하는 것은 지원되지 않아요(HBASE-6201 참고).
테스트는 DistributedHBaseCluster(HBaseCluster 구현) 클래스의 메서드를 사용해 분산 클러스터와 상호작용하며, 이 클래스는 다시 pluggable ClusterManager를 사용해요. 구체적인 구현은 배포별·환경별 작업(SSH 등)을 수행하는 실제 기능을 제공해요. 기본 ClusterManager는 HBaseClusterManager이며, SSH로 start/stop/kill/signal 명령을 원격 실행하고 몇 가지 posix 명령(ps 등)을 가정해요. 또한 테스트를 실행하는 사용자가 원격 머신에서 서버를 시작/중지할 충분한 "권한"이 있다고 가정해요. 기본적으로 env에서 HBASE_SSH_OPTS, HBASE_HOME, HBASE_CONF_DIR을 가져오고 bin/hbase-daemon.sh를 사용해 작업을 수행해요. 현재 tarball 배포, hbase-daemons.sh를 사용하는 배포, Apache Ambari 배포가 지원돼요. /etc/init.d/ 스크립트는 현재 지원되지 않지만 쉽게 추가할 수 있어요. 다른 배포 옵션에는 ClusterManager를 구현하고 연결할 수 있어요.
일부 통합 테스트는 진입점으로 main 메서드를 정의하며 테스트 드라이버 대신 단독으로 실행할 수 있어요. 예를 들어 itbll 테스트는 다음과 같이 실행할 수 있어요.
bin/hbase org.apache.hadoop.hbase.test.IntegrationTestBigLinkedList loop 2 1 100000 /temp 1 1000 50 1 0
hbase 스크립트는 노출된 main 메서드가 있는 모든 통합 테스트가 위에서 언급한 IntegrationTest 정규식 명명 패턴을 따르고 분산 클러스터에 대해 실행될 것이라고 가정해, classpath에 테스트 의존성을 제대로 설정해요.
파괴적 통합/시스템 테스트 (ChaosMonkey)
HBase 0.96은 Netflix의 Chaos Monkey 도구와 같은 이름의 도구를 모델링한 ChaosMonkey라는 도구를 도입했어요. ChaosMonkey는 랜덤 서버를 죽이거나 연결을 끊거나 환경에 다른 실패를 주입해 실행 중인 클러스터에서 실제 세상의 결함을 시뮬레이션해요. ChaosMonkey는 다른 테스트가 실행되는 동안 정책을 실행하는 독립 도구로 사용할 수 있어요. 어떤 환경에서는 고가용성과 내결함성이 기대대로 작동하는지 계속 확인하기 위해 ChaosMonkey가 항상 실행돼요.
ChaosMonkey는 Action과 Policy를 정의해요.
Actions:
Actions는 다음과 같은 미리 정의된 이벤트 시퀀스예요.
- Restart active master (sleep 5 sec)
- Restart random regionserver (sleep 5 sec)
- Restart random regionserver (sleep 60 sec)
- Restart META regionserver (sleep 5 sec)
- Restart ROOT regionserver (sleep 5 sec)
- Batch restart of 50% of regionservers (sleep 5 sec)
- Rolling restart of 100% of regionservers (sleep 5 sec)
Policies:
Policy는 하나 이상의 action을 실행하는 전략이에요. 기본 policy는 미리 정의된 action 가중치에 따라 매분마다 랜덤 action을 실행해요. 주어진 policy는 ChaosMonkey가 중단될 때까지 실행돼요.
대부분의 ChaosMonkey action은 합리적인 기본값을 갖도록 구성되어 있으므로 추가 구성 없이 기존 클러스터에 대해 ChaosMonkey를 실행할 수 있어요. 다음 예시는 기본 구성으로 ChaosMonkey를 실행해요.
$ bin/hbase org.apache.hadoop.hbase.chaos.util.ChaosMonkeyRunner
12/11/19 23:21:57 INFO util.ChaosMonkey: Using ChaosMonkey Policy: class org.apache.hadoop.hbase.util.ChaosMonkey$PeriodicRandomActionPolicy, period:60000
12/11/19 23:21:57 INFO util.ChaosMonkey: Sleeping for 26953 to add jitter
12/11/19 23:22:24 INFO util.ChaosMonkey: Performing action: Restart active master
12/11/19 23:22:24 INFO util.ChaosMonkey: Killing master:master.example.com,60000,1353367210440
12/11/19 23:22:24 INFO hbase.HBaseCluster: Aborting Master: master.example.com,60000,1353367210440
12/11/19 23:22:24 INFO hbase.ClusterManager: Executing remote command: ps aux | grep master | grep -v grep | tr -s ' ' | cut -d ' ' -f2 | xargs kill -s SIGKILL , hostname:master.example.com
12/11/19 23:22:25 INFO hbase.ClusterManager: Executed remote command, exit code:0 , output:
12/11/19 23:22:25 INFO hbase.HBaseCluster: Waiting service:master to stop: master.example.com,60000,1353367210440
12/11/19 23:22:25 INFO hbase.ClusterManager: Executing remote command: ps aux | grep master | grep -v grep | tr -s ' ' | cut -d ' ' -f2 , hostname:master.example.com
12/11/19 23:22:25 INFO hbase.ClusterManager: Executed remote command, exit code:0 , output:
12/11/19 23:22:25 INFO util.ChaosMonkey: Killed master server:master.example.com,60000,1353367210440
12/11/19 23:22:25 INFO util.ChaosMonkey: Sleeping for:5000
12/11/19 23:22:30 INFO util.ChaosMonkey: Starting master:master.example.com
12/11/19 23:22:30 INFO hbase.HBaseCluster: Starting Master on: master.example.com
12/11/19 23:22:30 INFO hbase.ClusterManager: Executing remote command: /homes/enis/code/hbase-0.94/bin/../bin/hbase-daemon.sh --config /homes/enis/code/hbase-0.94/bin/../conf start master , hostname:master.example.com
12/11/19 23:22:31 INFO hbase.ClusterManager: Executed remote command, exit code:0 , output:starting master, logging to /homes/enis/code/hbase-0.94/bin/../logs/hbase-enis-master-master.example.com.out
....
12/11/19 23:22:33 INFO util.ChaosMonkey: Started master: master.example.com,60000,1353367210440
12/11/19 23:22:33 INFO util.ChaosMonkey: Sleeping for:51321
12/11/19 23:23:24 INFO util.ChaosMonkey: Performing action: Restart random region server
12/11/19 23:23:24 INFO util.ChaosMonkey: Killing region server:rs3.example.com,60020,1353367027826
12/11/19 23:23:24 INFO hbase.HBaseCluster: Aborting RS: rs3.example.com,60020,1353367027826
12/11/19 23:23:24 INFO hbase.ClusterManager: Executing remote command: ps aux | grep regionserver | grep -v grep | tr -s ' ' | cut -d ' ' -f2 | xargs kill -s SIGKILL , hostname:rs3.example.com
12/11/19 23:23:25 INFO hbase.ClusterManager: Executed remote command, exit code:0 , output:
12/11/19 23:23:25 INFO hbase.HBaseCluster: Waiting service:regionserver to stop: rs3.example.com,60020,1353367027826
12/11/19 23:23:25 INFO hbase.ClusterManager: Executing remote command: ps aux | grep regionserver | grep -v grep | tr -s ' ' | cut -d ' ' -f2 , hostname:rs3.example.com
12/11/19 23:23:25 INFO hbase.ClusterManager: Executed remote command, exit code:0 , output:
12/11/19 23:23:25 INFO util.ChaosMonkey: Killed region server:rs3.example.com,60020,1353367027826. Reported num of rs:6
12/11/19 23:23:25 INFO util.ChaosMonkey: Sleeping for:60000
12/11/19 23:24:25 INFO util.ChaosMonkey: Starting region server:rs3.example.com
12/11/19 23:24:25 INFO hbase.HBaseCluster: Starting RS on: rs3.example.com
12/11/19 23:24:25 INFO hbase.ClusterManager: Executing remote command: /homes/enis/code/hbase-0.94/bin/../bin/hbase-daemon.sh --config /homes/enis/code/hbase-0.94/bin/../conf start regionserver , hostname:rs3.example.com
12/11/19 23:24:26 INFO hbase.ClusterManager: Executed remote command, exit code:0 , output:starting regionserver, logging to /homes/enis/code/hbase-0.94/bin/../logs/hbase-enis-regionserver-rs3.example.com.out
12/11/19 23:24:27 INFO util.ChaosMonkey: Started region server:rs3.example.com,60020,1353367027826. Reported num of rs:6
출력은 ChaosMonkey가 모든 사용 가능한 action으로 구성된 기본 PeriodicRandomActionPolicy 정책을 시작했음을 나타내요. RestartActiveMaster와 RestartRandomRs action을 실행하기로 선택했어요.
SSH 없는 ChaosMonkey
Chaos service와 ZNode cluster manager를 사용해 SSH 없이 chaos monkey를 실행할 수 있어요. HBase는 hbase-it/src/test/java/org/apache/hadoop/hbase/ 디렉터리에 있는 많은 cluster manager를 제공해요.
ZNodeClusterManager로 전환하려면 hbase 구성에 다음 속성을 설정하세요.
<property>
<name>hbase.it.clustermanager.class</name>
<value>org.apache.hadoop.hbase.ZNodeClusterManager</value>
</property>
chaos 시나리오를 테스트하려는 모든 호스트에서 chaos agent를 시작하세요.
$ bin/hbase org.apache.hadoop.hbase.chaos.ChaosService -c start
어느 한 호스트(가급적 edgenode)에서 chaos monkey runner를 시작하세요. 기본 정책 PeriodicRandomActionPolicy로 chaos monkey를 실행하는 동안의 예시 로그는 아래와 같아요.
$ bin/hbase org.apache.hadoop.hbase.chaos.util.ChaosMonkeyRunner
INFO [main] hbase.HBaseCommonTestingUtility: Instantiating org.apache.hadoop.hbase.ZNodeClusterManager
INFO [ReadOnlyZKClient-host1.example.com:2181,host2.example.com:2181,host3.example.com:2181@0x003d43fe] zookeeper.ZooKeeper: Initiating client connection, connectString=host1.example.com:2181,host2.example.com:2181,host3.example.com:2181 sessionTimeout=90000 watcher=org.apache.hadoop.hbase.zookeeper.ReadOnlyZKClient$$Lambda$19/2106254492@1a39cf8
INFO [ReadOnlyZKClient-host1.example.com:2181,host2.example.com:2181,host3.example.com:2181@0x003d43fe] zookeeper.ClientCnxnSocket: jute.maxbuffer value is 4194304 Bytes
INFO [ReadOnlyZKClient-host1.example.com:2181,host2.example.com:2181,host3.example.com:2181@0x003d43fe] zookeeper.ClientCnxn: zookeeper.request.timeout value is 0. feature enabled=
INFO [ReadOnlyZKClient-host1.example.com:2181,host2.example.com:2181,host3.example.com:2181@0x003d43fe-SendThread(host2.example.com:2181)] zookeeper.ClientCnxn: Opening socket connection to server host2.example.com/10.20.30.40:2181. Will not attempt to authenticate using SASL (unknown error)
INFO [ReadOnlyZKClient-host1.example.com:2181,host2.example.com:2181,host3.example.com:2181@0x003d43fe-SendThread(host2.example.com:2181)] zookeeper.ClientCnxn: Socket connection established, initiating session, client: /10.20.30.40:35164, server: host2.example.com/10.20.30.40:2181
INFO [ReadOnlyZKClient-host1.example.com:2181,host2.example.com:2181,host3.example.com:2181@0x003d43fe-SendThread(host2.example.com:2181)] zookeeper.ClientCnxn: Session establishment complete on server host2.example.com/10.20.30.40:2181, sessionid = 0x101de9204670877, negotiated timeout = 60000
INFO [main] policies.Policy: Using ChaosMonkey Policy class org.apache.hadoop.hbase.chaos.policies.PeriodicRandomActionPolicy, period=60000 ms
[ChaosMonkey-2] policies.Policy: Sleeping for 93741 ms to add jitter
INFO [ChaosMonkey-0] policies.Policy: Sleeping for 9752 ms to add jitter
INFO [ChaosMonkey-1] policies.Policy: Sleeping for 65562 ms to add jitter
INFO [ChaosMonkey-3] policies.Policy: Sleeping for 38777 ms to add jitter
INFO [ChaosMonkey-0] actions.CompactRandomRegionOfTableAction: Performing action: Compact random region of table usertable, major=false
INFO [ChaosMonkey-0] policies.Policy: Sleeping for 59532 ms
INFO [ChaosMonkey-3] client.ConnectionImplementation: Getting master connection state from TTL Cache
INFO [ChaosMonkey-3] client.ConnectionImplementation: Getting master state using rpc call
INFO [ChaosMonkey-3] actions.DumpClusterStatusAction: Cluster status
Master: host1.example.com,16000,1678339058222
Number of backup masters: 0
Number of live region servers: 3
host1.example.com,16020,1678794551244
host2.example.com,16020,1678341258970
host3.example.com,16020,1678347834336
Number of dead region servers: 0
Number of unknown region servers: 0
Average load: 123.6666666666666
Number of requests: 118645157
Number of regions: 2654
Number of regions in transition: 0
INFO [ChaosMonkey-3] policies.Policy: Sleeping for 89614 ms
더 많은 커스터마이징 정보는 ChaosMonkeyRunner의 help를 볼 수 있어요. 예를 들어 chaos 연산을 수행할 테이블 이름 등을 전달할 수 있어요. 아래는 지원되는 모든 옵션을 나열한 help 명령의 출력이에요.
$ bin/hbase org.apache.hadoop.hbase.chaos.util.ChaosMonkeyRunner --help
usage: hbase org.apache.hadoop.hbase.chaos.util.ChaosMonkeyRunner <options>
Options:
-c <arg> Name of extra configurations file to find on CLASSPATH
-m,--monkey <arg> Which chaos monkey to run
-monkeyProps <arg> The properties file for specifying chaos monkey properties.
-tableName <arg> Table name in the test to run chaos monkey against
-familyName <arg> Family name in the test to run chaos monkey against
예를 들어 다음을 실행하면 RS를 rolling batch restart하고, 한 번에 하나씩 graceful rolling restart RS하고, active master를 재시작하고, balancer를 강제 실행하는 action들을 선택하는 ServerKillingMonkeyFactory를 시작해요.
$ bin/hbase org.apache.hadoop.hbase.chaos.util.ChaosMonkeyRunner -m org.apache.hadoop.hbase.chaos.factories.ServerKillingMonkeyFactory
사용 가능한 정책 (Available Policies)
HBase는 hbase/hbase-it/src/test/java/org/apache/hadoop/hbase/chaos/policies/ 디렉터리에 있는 여러 ChaosMonkey 정책을 제공해요.
개별 ChaosMonkey Actions 구성 (Configuring Individual ChaosMonkey Actions)
ChaosMonkey 통합 테스트는 테스트 실행별로 구성할 수 있어요. HBase CLASSPATH에 Java properties 파일을 만들고 -monkeyProps 구성 플래그로 ChaosMonkey에 전달하세요. 구성 가능한 속성과(해당된다면) 기본값은 org.apache.hadoop.hbase.chaos.factories.MonkeyConstants 클래스에 나열돼요. 기본값이 있는 속성은 properties 파일에 포함해 덮어쓸 수 있어요.
다음 예시는 monkey.properties라는 properties 파일을 사용해요.
$ bin/hbase org.apache.hadoop.hbase.IntegrationTestIngest -m slowDeterministic -monkeyProps monkey.properties
위 명령은 통합 테스트와 chaos monkey를 시작해요. HBase CLASSPATH에서 monkey.properties properties 파일을 찾을 거예요. 예를 들어 HBASE conf dir 안에서요.
다음은 예시 chaos monkey 파일이에요.
예시 ChaosMonkey Properties 파일
sdm.action1.period=120000
sdm.action2.period=40000
move.regions.sleep.time=80000
move.regions.max.time=1000000
move.regions.sleep.time=80000
batch.restart.rs.ratio=0.4f
Period/time은 밀리초로 표시돼요.
HBase 1.0.2+는 HBase의 기반 ZooKeeper quorum이나 HDFS 노드를 재시작하는 기능을 추가해요. 이러한 actions를 사용하려면 배포별이므로 합리적인 기본값이 없는 몇 가지 새 속성을 hbase-site.xml이나 다른 properties 파일일 수 있는 ChaosMonkey properties 파일에 구성해야 해요.
<property>
<name>hbase.it.clustermanager.hadoop.home</name>
<value>$HADOOP_HOME</value>
</property>
<property>
<name>hbase.it.clustermanager.zookeeper.home</name>
<value>$ZOOKEEPER_HOME</value>
</property>
<property>
<name>hbase.it.clustermanager.hbase.user</name>
<value>hbase</value>
</property>
<property>
<name>hbase.it.clustermanager.hadoop.hdfs.user</name>
<value>hdfs</value>
</property>
<property>
<name>hbase.it.clustermanager.zookeeper.user</name>
<value>zookeeper</value>
</property>
파괴적 ChaosMonkey Actions 커스터마이징
위 세션은 slowDeterministic monkey 정책에 대한 사용자 지정 구성을 설정하는 방법을 보여줘요. 이것은 실행 중인 클러스터에 대해 다양한 심각도의 미리 정의된 파괴적 actions 집합을 정의하는 정책이에요. 이러한 actions는 light weight, mid weight, heavy weight 세 가지 범주로 그룹화돼요. 다른 actions에 대한 일부 속성(타임아웃, 빈도 등)을 정의할 수는 있지만, actions 자체는 구성할 수 없어요.
특정 배포에서는 slowDeterministic에서 제공하는 미리 정의된 actions 집합보다 덜 또는 더 공격적인 자신의 테스트 전략을 정의하는 것이 흥미로울 수 있어요. 이러한 경우 configurableSlowDeterministic 정책을 사용할 수 있어요. monkey.properties 속성 파일에서 구성 가능한 heavy weight actions 집합을 정의할 수 있어요:
batch.restart.rs.ratio=0.3f
heavy.actions=RestartRandomRsAction(500000);MoveRandomRegionOfTableAction(360000,$table_name);SplitAllRegionOfTableAction($table_name)
위 properties 파일 정의는 chaos monkey가 8분마다 RegionServer 충돌을, 6분마다 랜덤 region 이동을, 그리고 모든 테이블 region의 최소 하나의 분할을 수행하도록 지시해요.
이 정책을 실행하려면 heavy.actions 속성 정의를 포함하는 속성 파일과 함께 monkey policy로 configurableSlowDeterministic을 지정하기만 하면 돼요.
$ bin/hbase org.apache.hadoop.hbase.IntegrationTestIngest -m configurableSlowDeterministic -monkeyProps monkey.properties
monkey actions를 지정할 때 필요한 모든 생성자 매개변수를 정의해야 해요. 테이블 이름 매개변수가 필요한 actions에는 $table_name 플레이스홀더를 지정할 수 있으며, 통합 테스트 실행이 만든 테이블로 자동 대체돼요.
properties 파일에서 heavy.actions 속성이 생략되면 configurableSlowDeterministic은 그냥 slowDeterministic 정책으로 실행돼요(slowDeterministic 정책이 정의한 모든 heavy weight actions를 실행해요).
더 알아보기 (Learn more)
빌드와 개발 참여는 Building Apache HBase, Getting Involved, Developer Guidelines 문서를 보시길 권해요.