Selenium으로 Ansible 웹 앱 Role 테스트하기
원문은 Michael Lynch님이 에 게재했습니다. 이 블로그 구독하기
개요
Ansible은 웹 앱을 배포하는 데 탁월한 도구입니다. Ansible을 이용하면 웹 앱을 구성하는 다양한 “role”(예: 웹 서버, 데이터베이스 서버, 애플리케이션 서버) 단위로 웹 앱을 정의할 수 있습니다. Role과 Role 간의 상호작용이 점점 복잡해질수록 웹 앱이 올바르게 배포되고 있는지 검증하기 위해 그에 걸맞게 더욱 강력한 Role 테스트 방법이 필요합니다.
지난 글에서는 Ansible을 이용해 ClipBucket이라는 동영상 호스팅 웹 앱을 배포했습니다. 해당 글에서는 웹 앱이 올바르게 설치되었는지 확인하는 자동화된 테스트를 포함했지만, 이러한 테스트는 애플리케이션 기능을 그다지 엄격하게 검증하지는 못했습니다.
이번 글에서는 앱의 기능을 더 깊이 검증하는 더욱 강력한 자동화 테스트를 선보이겠습니다. 이를 위해 Selenium이라는 웹 브라우저 자동화 도구를 사용할 것입니다. 여기서는 ClipBucket role을 계속 사용하겠지만, 이 아이디어는 Ansible로 배포하는 어떤 웹 앱에도 일반적으로 적용할 수 있습니다.
curl을 이용한 기본 테스트
원래 빌드 스크립트에서 마지막 테스트는 다음과 같았습니다:
curl -s "${container_ip}" \
| grep "Login" && \
(echo 'Landing page test: pass' && exit 0) || \
(echo 'Landing page test: fail' && exit 1)이 테스트는 다음과 같은 웹 앱의 몇 가지 중요한 속성을 검증하므로 유용합니다:
- 웹 서버가 80번 포트에서 수신 대기 중이다
- 웹 서버가 사용자 요청에 응답하고 있다
- 웹 서버가 ClipBucket 랜딩 페이지를 제공하고 있다
더 나은 테스트가 필요한 이유
원래 테스트가 몇 가지 중요한 검사를 제공하긴 했지만, 웹 앱의 실제 기능은 거의 검증하지 못했습니다. Ansible role에 버그가 생겨 웹 앱이 망가져도 기본 테스트에서는 이를 감지하지 못할 수 있습니다.
예를 들어 ClipBucket 플레이북에서 중요한 task를 실수로 삭제했다고 상상해 보겠습니다:
diff --git a/tasks/main.yml b/tasks/main.yml
index 8542ffc..e9d42c0 100644
--- a/tasks/main.yml
+++ b/tasks/main.yml
@@ -29,15 +29,6 @@
name: flvtool2
state: present
-- name: create a symlink for ClipBucket to find ffmpeg and MP4Box
- file:
- path: "/usr/local/bin/{{ item }}"
- src: "/usr/bin/{{ item }}"
- state: link
- with_items:
- - ffmpeg
- - MP4Box
-
- name: install the Python MySQLB module
pip: name=MySQL-python수정된 플레이북으로 배포한 뒤 대상 서버에 접속해 보면 모든 것이 정상으로 보입니다:
모든 설치 task가 성공하고 ClipBucket 랜딩 페이지가 표시됩니다. 무엇이 문제일까요?
동영상을 업로드해 보겠습니다. 영상을 보려고 할 때까지는 모든 것이 정상적으로 동작합니다:
플레이북에서 ffmpeg에 대한 symlink를 생성하는 task를 삭제했기 때문에, ClipBucket이 동영상을 스트리밍 가능한 형식으로 트랜스코딩하지 못합니다.
이를 위한 자동화된 테스트를 만들고 싶지만, 간단한 커맨드라인 도구로 동영상 업로드를 스크립트로 작성하기는 어렵습니다. 사용자가 먼저 로그인해야 하고(즉, 스크립트가 요청 간에 쿠키를 관리해야 함), 그 다음 웹 UI를 탐색해 동영상을 업로드해야 합니다. 이를 일련의 curl 명령으로 구현하는 것은 매우 어렵습니다.
다행히 Selenium을 사용할 수 있습니다. Selenium은 웹 브라우저 동작을 프로그래밍 방식으로 수행할 수 있게 해주는 웹 테스트 도구입니다.
Selenium 설정하기
Selenium을 시작하려면 Ansible 컨트롤 머신에 몇 가지 구성 요소를 설치해야 합니다:
- Selenium Python Package - Python API를 사용할 예정이며, 이 패키지를 통해 Selenium 프레임워크와 Python 바인딩을 얻을 수 있습니다.
- Firefox - Selenium이 제어할 브라우저가 필요합니다. Selenium은 대부분의 주요 브라우저에서 동작하지만, Firefox를 네이티브로 지원합니다.
- xvfb - 실제 디스플레이가 없는 VM에서 테스트를 실행할 예정이므로, xvfb를 가상 디스플레이로 사용해 Firefox가 모니터에서 실행 중인 것처럼 동작하게 합니다.
이를 위해 상당히 간단한 플레이북을 만들 수 있습니다. 조금 어려웠던 부분은 xvfb가 눈에 잘 띄지 않는 init 스크립트를 필요로 한다는 점뿐이었습니다. 다행히 블로거 Cory Klein이 작년에 xvfb init 스크립트 예제를 담은 글을 작성했고, 그의 예제를 활용해 우리의 필요에 맞는 스크립트를 만들 수 있었습니다.
테스트할 웹 플로우 선택하기
이제 Selenium을 설치했으니 웹 앱을 검증할 Selenium 스크립트를 만들 차례입니다. 검증하고 싶은 웹 플로우로는 다음과 같은 다양한 가능성이 있습니다:
- 로그인
- 동영상 업로드 및 재생
- 동영상에 댓글 작성 및 표시 확인
- 새 사용자 계정 생성
ClipBucket의 경우 동영상이 올바르게 업로드되는지 확인하는 데 특히 관심이 있으므로, 로그인과 동영상 업로드를 테스트해야 합니다. 안타깝게도 ClipBucket은 업로드 관리를 위해 무거운 JavaScript 패키지를 사용하므로, 일반적인 파일 업로드용 Selenium API가 동작하지 않습니다.
대안으로 ClipBucket 모듈 진단 페이지를 사용하겠습니다. 이 페이지는 ClipBucket에 설치된 모듈을 표시하고, 모듈이 제대로 설치되지 않았을 때 오류 메시지를 표시합니다:
동영상 업로드 플로우 대신 이 페이지를 사용해 모든 모듈이 올바르게 설치되었는지 검증할 수 있습니다.
이제 어떤 기능을 검증할지 알았으니, 자동화하려는 웹 플로우를 간략히 그려볼 수 있습니다. 대략 다음과 같습니다:
- ClipBucket URL 로드
- 관리자로 로그인
- 모듈 진단 페이지로 이동
- 모든 모듈이 설치되었는지 확인
이를 통해 기본 테스트에서는 검증하지 못했던 몇 가지 추가 기능에 대한 자동화된 검증을 얻을 수 있습니다:
- 사용자 로그인이 동작한다(즉, ClipBucket이 데이터베이스에 성공적으로 접근할 수 있다)
- ClipBucket이 의존하는 도구들에 접근할 수 있다
웹 플로우 자동화하기
Selenium에서 브라우저 동작을 자동화하려면 Selenium에게 브라우저에서 로드할 URL을 알려준 뒤, 페이지에서 요소를 찾고 상호작용하는 방법을 알려줘야 합니다. 원하는 웹 플로우에 필요한 동작을 어떻게 자동화할지 살펴보겠습니다.
로그인 자동화
로그인하려면 로그인 페이지에서 인증 정보 필드를 찾아 사용자 이름과 비밀번호를 입력한 뒤 “Login” 버튼을 눌러야 합니다. 다행히 사용자 이름과 비밀번호 필드에는 id 속성이 있어 페이지에서 쉽게 식별할 수 있습니다. “Login” 버튼에는 id 속성이 없지만, 페이지에서 고유한 login이라는 name 속성이 있어 이를 고유 식별자로 사용할 수 있습니다:
다음 코드 스니펫에서 이러한 필드를 찾고 로그인 자격 증명을 입력합니다:
self.get('/admin_area/login.php')
username_element = self._driver.find_element_by_id('username')
ui.WebDriverWait(
self._driver, TIMEOUT).until(
expected_conditions.visibility_of(username_element))
password_element = self._driver.find_element_by_id('password')
username_element.send_keys(username)
password_element.send_keys(password)
self._driver.find_element_by_name('login').click()모듈 목록 스크래핑
설치된 모듈 페이지를 확인하는 방법은 조금 다릅니다. 페이지와 상호작용할 필요는 전혀 없으며, 단지 일부 페이지 요소를 찾아 해석하기만 하면 됩니다. 모든 모듈이 올바르게 설치되었는지 확인하려면 각 모듈을 식별하는 박스를 찾은 뒤, 오류 메시지를 표시하는지 프로그래밍 방식으로 판단해야 합니다.
관심 있는 요소(또는 DOM에서 그 부모 요소) 중 어느 것도 id 속성을 가지고 있지 않기 때문에 까다롭습니다. 모두 class="well"인 <div>이므로, 각 모듈 정보 박스를 찾는 데 사용할 수 있는 최선의 옵션은 이것입니다.
박스를 찾은 뒤에는 해당 박스가 모듈 설치 성공을 나타내는지 아니면 문제를 나타내는지 판단해야 합니다. 성공 지표를 찾거나 실패 지표가 없음을 확인함으로써 이를 수행할 수 있습니다. 전자가 조금 더 엄격하지만, 후자가 코드로 작성하기는 더 간단합니다. 오류 메시지가 있는 박스는 항상 class="alert" 속성을 가진 요소를 포함하므로, 이 클래스를 가진 자식 요소가 없는 경우 성공적인 박스로 식별할 수 있습니다.
다음 코드 스니펫으로 이를 수행할 수 있습니다.
self.get('/admin_area/cb_mod_check.php')
for module_element in self._driver.find_elements_by_class_name('well'):
try:
ui.WebDriverWait(
self._driver, TIMEOUT).until(
expected_conditions.visibility_of(module_element))
alert_element = module_element.find_element_by_class_name(
'alert')
if alert_element:
raise ClipBucketModuleError(alert_element.text)
except exceptions.NoSuchElementException:
# Lack of alert is good: the module is installed correctly.
continueTravis에 웹 플로우 테스트 통합하기
이 모든 것을 종합하면, Selenium 설치 플레이북과 Selenium 스크립트를 빌드 파일에 추가할 수 있습니다.
이제 앞서 만든 깨진 커밋으로 GitHub 풀 리퀘스트를 생성합니다. Travis 빌드가 실행되면 실패하는 것을 볼 수 있습니다:
2016-09-21 00:17:06,229 clipbucket_driver INFO Logging in with username=testadmin
2016-09-21 00:17:06,229 clipbucket_driver INFO Loading url: http://172.17.0.2/admin_area/login.php
2016-09-21 00:17:07,525 clipbucket_driver INFO Login complete
2016-09-21 00:17:07,526 clipbucket_driver INFO Checking ClipBucket modules
2016-09-21 00:17:07,526 clipbucket_driver INFO Loading url: http://172.17.0.2/admin_area/cb_mod_check.php
Traceback (most recent call last):
File "tests/clipbucket_driver/main.py", line 36, in <module>
main(parser.parse_args())
File "tests/clipbucket_driver/main.py", line 24, in main
driver.do_check_modules()
File "/home/travis/build/mtlynch/ansible-role-clipbucket/tests/clipbucket_driver/clipbucket_driver.py", line 64, in do_check_modules
raise ClipBucketModuleError(alert_element.text)
clipbucket_driver.ClipBucketModuleError: ffmpeg is not found훌륭합니다! 새로운 테스트가 Ansible role의 결함을 정확히 잡아냈습니다.
그리고 정상적인 플레이북을 실행했을 때 모든 것이 동작하는지 확인해 보겠습니다:
2016-09-21 01:58:21,992 clipbucket_driver INFO Logging in with username=testadmin
2016-09-21 01:58:21,992 clipbucket_driver INFO Loading url: http://172.17.0.2/admin_area/login.php
2016-09-21 01:58:23,036 clipbucket_driver INFO Login complete
2016-09-21 01:58:23,039 clipbucket_driver INFO Checking ClipBucket modules
2016-09-21 01:58:23,040 clipbucket_driver INFO Loading url: http://172.17.0.2/admin_area/cb_mod_check.php
2016-09-21 01:58:23,724 clipbucket_driver INFO Module check complete
2016-09-21 01:58:23,724 clipbucket_driver INFO Exiting ClipBucket driverSelenium 스크립트가 필요한 모든 모듈이 올바르게 설치되었음을 정확히 판단합니다. 향후 로그인 기능이 실패하거나 모듈이 잘못 설치되도록 하는 변경을 가하더라도 자동화된 테스트가 이를 잡아낼 것입니다.
결론
이번 글에서는 Ansible과 Selenium을 결합해 Ansible role이 웹 앱을 올바르게 배포했고, 그 결과 배포된 환경이 예상된 사용자 동작을 지원하는지 검증했습니다. Selenium은 매우 유연하므로 다양한 웹 애플리케이션에서 여러 가지 웹 UI 플로우를 테스트할 수 있습니다.
글을 무작위로 읽기





댓글
로그인하고 댓글 남기기