Load Testing with Artillery.io

Long time no see !! Chào mừng các bạn đến với phần tiếp theo trong Performance Tool Series: Artillery.io. Nhìn chung thì đây là một performance tool khá thú vị được viết bằng Node.js, và đồng thời nó được xem khá là nhẹ so với các tool đồng trang lứa. Trong bài này mình sẽ chia sẻ về những tính năng của tool mà mình đã xài trong project thực tế, kèm theo đó là các tips và các hạn chế của tool. Hi vọng bài viết này sẽ cung cấp thêm cho các bạn một option mới khi cân nhắc chọn performance tool.

Các bạn có thể tham khảo phần trước ở link sau.

Artillery.io?

Search google nhớ ghi là “artillery.io” nguyên văn nhé không là nó ra hình súng thần công như trên.

Về cơ bản, Artillery cũng là một load generator như các tool khác đồng trang lứa khác như Apache JMeter, Locust, etc, chuyên dụng cho việc load testing. Tuy nhiên có một số điểm tạo nên sự khác biệt so với các tool còn lại, đây đồng thời cũng là những điểm mà các bạn cần cân nhắc trước khi chọn tool này làm trong project thực tế:

  • Pros:
    • Không có giao diện windows 2000 như của JMeter. Mọi thứ đều thông qua command line interface và text editor cho nên rất là nhẹ.
    • Open source.
    • Test viết bằng yaml/jsonnode.js.
    • Có hỗ trợ load test cho socket.io.
    • Có cơ chế plugin để phục vụ cho các nhu cầu fck tạp. Một số plugin có sẵn như DataDog, Influx, StatsD dùng để gửi dữ liệu real-time vào các real-time database.
    • Có version PRO….. Mình chưa có điều kiện xài cái này nhưng theo document của tool thì ở version này mình có thể chạy test ở distributed mode, bạn nào làm performance nhiều chắc cũng nghe qua khái niệm này rồi.
  • Cons:
    • Cái socket.io nói support vậy chứ một vài trường hợp đòi hỏi phải workaround mới có thể chạy được.
    • Ít performance metrics (từ này các bạn có thể hiểu là những con số thống kê, dựa vào nó mà một người tester có thể phân tích được tình trạng của system mình – ví dụ như số lượng requests trên 1s, trung bình của response time) nếu so với các tool khác.
    • Trường hợp các bạn muốn load test kiểu phức tạp như chạy test với tỉ lệ 6:3:1 cho 1000 users, hay muốn giữ cho throughput của system ở một mức nhất định thì tool chưa support cho mấy chuyện này (nhưng muốn thì vẫn làm được).

Cài đặt

Với những bạn chưa cài node.js thì vào link sau để cài: https://nodejs.org/en/download/

Cài xong rồi thì mở command line và run lệnh sau:

npm install -g artillery

Run lệnh kế để check version, nếu hiện ra version là quá trình cài đặt thành thụ:

artillery -V


        ___         __  _ ____                  _
  _____/   |  _____/ /_(_) / /__  _______  __  (_)___  _____
 /____/ /| | / ___/ __/ / / / _ \/ ___/ / / / / / __ \/____/
/____/ ___ |/ /  / /_/ / / /  __/ /  / /_/ / / / /_/ /____/
    /_/  |_/_/   \__/_/_/_/\___/_/   \__, (_)_/\____/
                                    /____/

------------ Version Info ------------
Artillery: 1.6.0-29
Artillery Pro: not installed (https://artillery.io/pro)
Node.js: v10.15.3
OS: darwin/x64
--------------------------------------

Viết Test

Test trong artillery thông thường sẽ bao gồm 2 phần chính: các file test scenario (*.yml) và các file JS (.js). Mình sẽ giải thích detail từng phần thông qua các code mẫu (hàng thiệt phiên bản cắt xén) dưới đây.

Test Scenario Files

Một test scenario file bao gồm hai phần: configuration and scenarios

Configuration

Trong phần này, bạn sẽ chỉ định bao nhiêu virtual users sẽ được tạo ra trong load test của bạn và các tuỳ chỉnh như dùng plugin nào, định nghĩa biến, chỉ định đường dẫn tới JS file, bla bla….

  • config: đây là keyword bắt buộc để đánh dấu phần configuration của test scenario file.
  • target: URL của application. Mấy bạn đừng thêm dấu “/” vào cuối nhé, không là lúc run nó báo lỗi tè le.
  • processor: đường dẫn tương đối tới file JS.
  • plugins: ở phần trước mình có đề cập về plugin trong artillery, thì đây là cách mà mình chỉ định plugin nào sẽ xài, ở đây mình xài plugin gọi là faker. Một điểm cần lưu ý ở đây là trước khi bạn muốn xài plugin nào thì bạn phải install plugin đó thông qua npm. Ví dụ với plugin faker trong sample là : npm install -g artillery-plugin-faker
  • variables: định nghĩa biến. Xài bằng cách {{ tên biến }}, ví dụ {{ timeout }}.
  • payload: chỉ định csv file. Thường test data của các bạn nhiều thì sẽ bỏ nó trong csv file và test sẽ đọc csv file và loop trên đó. Trong sample dưới đây thì file csv của mình có 1 cột và mình lưu data trong cột đó vào biến email.
  • phases: define số lượng virtual users sẽ được tạo ra. Mình lấy ví dụ bên dưới là test của mình chia làm 2 phase (bạn có thể tạo nhiều phase): phase đầu tiên kéo dài trong 5s (duration) và cứ mỗi giây là 1 virtual user (arrivalRate) được tạo ra, tương tự ở phase sau test sẽ kéo dài 60s và cứ mỗi giây có 20 virtual user được tạo. Bạn có thể tham khảo thêm các option khác ở link này https://artillery.io/docs/script-reference/#load-phases.
config:
  target: http://127.0.0.1:7000
  processor: "../processors/console_proc.js"
  plugins:
    faker: {}
  variables:
    password: "123456789"
    prefix: "QA"
  payload:
  - path: "../data/QA_accounts.csv"
    fields:
      - "email"
  phases:
      - duration: 5
        arrivalRate: 1
        name: "Init phase"
      - duration: 60
        arrivalRate: 20
        name: "Intense phase"

Scenarios

Phần này chứa các action mà một virtual user sẽ làm, nói dễ hiểu ví dụ như hành động mua hàng, đặt sách, chuyển tiền, bla bla…. Ở mặt technical thì nó là chuỗi các request. Một file có thể có một hoặc nhiều scenario. Scenario được pick random dựa trên weight mà bạn input vào.

  • name: tên của scenario. Có thể có nhiều name trong một file, mỗi name đại diện cho 1 scenario.
  • weight: đây là trọng số của scenario, scenario nào có weight càng cao càng dễ xảy ra hơn. Giá trị mặc định của weight là 1, tức khả năng xảy ra của các scenario như nhau.
  • flow: chứa chuỗi các HTTP requests, hay dễ hiểu là chuỗi action của virtual user.
  • Đống còn lại chắc các bạn cũng biết nó là gì nếu bạn đã quen với HTTP request và response, mình chỉ giải thích về các syntax đặc biệt như
    • beforeRequest: hàm này sẽ chạy trước khi request được send. Đây là một trong các hooks được cung cấp bởi Artillery.
    • capture: dùng để store response trả về và lưu vào biến tên là response, biến này có thể dùng cho các request kế đó hoặc cho các hàm sau đó.
    • transform: operation cho cái biến được capture. Ở đây mình cộng chuỗi từ JWT với caí token mình capture được.
...
scenarios:
  - name: "Create a bot"
    weight: 1
    flow:
      - post: 
            url: /auth/sign_in
            json:
              email: "{{ email }}"
              password: "{{ password }}"
            beforeRequest: hashPassword
            capture:
              json: "$.jwtToken"
              transform: "`JWT ${this.token}`"
              as: "token"
      - think: 5
      - post:
            url: /bot/create
            headers:
              Authorization: "{{ token }}"
            json:
              botName: "{{ prefix }}_{{ botName }}"
              botWebsite: "https://artillery.io/"
              zoneName: "Asia/Bangkok"

JavaScript Files

Ở phần trên có một đoạn trong scenario file mình dùng để chỉ định đường dẫn tới JS file: processor: "./laura.js". File này chứa custom code viết bằng node.js. Do nhu cầu đa dạng nên hầu như lúc nào các bạn cũng sẽ dùng tới các file này. Trong file này bạn chú ý cho mình một vài tham số sau, còn tại sao nó nhận vào những tham số như vậy là do syntax của Artillery bắt buộc thế.

  • requestParams/response: dùng biến này để truy xuất vào header, body, v.v.. của request/response. Chi tiết hơn về thao tác trên request object, mấy bạn xem ở link sau: https://github.com/request/request
  • context: mỗi virtual user có một context riêng, context chứa tất cả các variables của từng virtual user. Mấy bạn chưa từng làm performance testing thì có thể hiểu context là khái niệm mà các performance tool dùng để phân biệt giữa các virtual users với nhau, tránh trường hợp VU này xoá nhầm hàng của VU khác chẳng hạn.
  • ee: Event Emitter. Ở một trường hợp nhất định, bạn có thể dùng biến này communicate với runner của artillery.
  • next: hàm callback của artillery, bắt buộc phải có để scenario file có thể chạy tiếp.
 module.exports = {
    saveUserToFile: saveUserToFile,
    hashPassword: hashPassword
}

const crypto = require('crypto');
var fs = require('fs');

function saveUserToFile(requestParams, response, context, ee, next) {
    if (response.statusCode === 200) {
        appendToFile(`./data/${context.vars.prefix}_accounts.csv`, response.body.email);
    }
    else {
        appendToFile(`./data/${context.vars.prefix}_accounts_err.csv`,
            `${requestParams.json['email']},${JSON.stringify(response.body)}`);
    }
    return next();
}

function appendToFile(filename, payload) {
    fs.appendFile(filename, payload + '\n', function (err) {
        if (err) throw err;
    });
}

function hashPassword(requestParams, context, ee, next) {
    requestParams.json['password'] = crypto.pbkdf2Sync(context.vars.password, new Buffer('', 'hex'), 100, 256, 'sha256').toString('hex');
    return next();
}

Cách dùng trong scenario files

  • Dùng dưới dạng hook.
  # ... a request in a scenario definition:
  - post:
      url: "/api/signin"
      beforeRequest: "setCredentials"
      afterResponse: "getJWTToken"
  • Dùng như function step
scenarios: 
  - name: "Chat" 
    engine: "socketio"
    flow:   
      - function: initConversation
      - think: 3
      - loop:
        - function: chat
        - think: 3
        count: 10
      - think: 10

Chạy test và phân tích kết quả

Khi code xong rồi thì còn đợi gì nữa mà không chạy thử xem thơm không :))). Có 2 cách để bạn chạy test

  • Chạy trực tiếp bằng command line
artillery run athenka.yml
  • Chạy thông qua node.js code.
const artillery = require('artillery');
const path = require('path');
const read = require('read-yaml');
var baseDir = path.basename(__dirname);
var scriptPath = `..\\${baseDir}\\Scripts\\${process.argv[2]}`;
var environment = process.argv[3]||'qa';
var fileName = path.basename(scriptPath, path.extname(scriptPath));
var scriptConfig = read.sync(scriptPath);
var phaseInfo;
var options;
if (scriptConfig.config.phases[0].arrivalRate) {
    phaseInfo = `${scriptConfig.config.phases[0].arrivalRate}-Rate_In-${scriptConfig.config.phases[0].duration}s`;
}
else {
    phaseInfo = `${scriptConfig.config.phases[0].arrivalCount}-Count_In-${scriptConfig.config.phases[0].duration}s`;
}

artillery.run(scriptPath, options);

Sau đó mở cmd lên và gõ:

node athenka.js

Bất kể bạn run bằng kiểu gì thì nó cũng sẽ hiển thị tương tự như hình dưới, toàn số là số do cái này không có giao diện, những số này cứ mỗi 10s sẽ update lại.

  • Scenarios launched: tổng số VU.
  • Scenarios completed: tổng số VU đã hoàn thành session.
  • Requests completed: tổng số request (HTTP, sockets) đã send.
  • RPS sent: số lượng request trung bình mỗi giây.
  • Request latency (milliseconds): nếu các bạn đã nghe về percentile (google đi bro) thì sẽ biết p95, p99 nghĩa là gì.
  • Codes: HTTP response code.
Complete report @ 2019-01-02T17:32:36.653Z
  Scenarios launched:  300
  Scenarios completed: 300
  Requests completed:  600
  RPS sent: 18.86
  Request latency:
    min: 52.1
    max: 11005.7
    median: 408.2
    p95: 1727.4
    p99: 3144
  Scenario counts:
    0: 300 (100%)
  Codes:
    200: 300
    302: 300

Bonus 1: Good Practices

Có một vài cái practices nho nhỏ về Artillery mình muốn share cho mấy bạn ở đây để khỏi phải đạp shit sau này.

  • Tin buồn là rồi sẽ tới lúc các bạn sẽ run test trên nhiều môi trường khác nhau, tin vui là Artillery có hỗ trợ 2 cách để quản lý cũng như chạy test trên nhiểu environment khác nhau.
    • Cách thứ nhất là xài magic syntax environment trong phần config của scenario file. Cách này bạn có thể dễ dàng tách biệt config của các môi trường với nhau. Config đơn giản thì ổn nhưng về sau config phức tạp file này no to đùng lên khó quản lý lắm. Điểm lợi của cách này là nó cho bạn quyền truy cập vào biến {{ $environment }}.
    • Cách thứ hai là xài một file config riêng, khi dùng cmd để run test nó có một option để bạn chỉ định đường dẫn tới file config nằm ngoài scenario file, về syntax thì y chang. Cách này các bạn dễ quản lý config của mình hơn, nhưng không truy cập được vào biến {{ $environment }} như cách trên.
# Reuse the same config to run two different scenarios:

artillery run --config common-config.yaml my-scenario.yaml
artillery run --config common-config.yaml another-scenario.yaml
  • Tuy Artillery cho phép mình bỏ nhiều scenario trong một scenario file nhưng bạn sẽ không control được số lượng virtual users cho từng scenario của file đó cho nên practice ở đây là nên tách ra mỗi scenario file một scenario thôi.
  • Một trường hợp mà mình cũng hay thường thấy của các bạn mới bắt đầu làm là ghi thẳng những thông tin nhạy cảm vào test luôn (e.g. secret key) rồi push lên github chơi <(“). Các bạn có thể ngăn trường hợp này xảy ra bằng cách dùng một magic syntax khác là processEnvironment, lúc này bạn không cần để mấy info nhạy cảm trong test nữa mà chỉ cần truyền vào lúc run test thôi.

Bonus 2: Artillery.io with Grafana

Làm performance testing chỉ xem bằng command line thôi thì nhiều vấn đề bị che khuất lắm. Do đó Artillery có support việc send những data (scenario launched, completed, RPS, v.v…) lên các real time database thông qua plugin, khi có data rồi mình có thể dùng một tool nào đó để vẽ nhưng con số thành những chart để dễ monitor hơn. Tool mình từng dùng để monitor là Grafana và plugin mình dùng là influx plugin.

Mình chỉ giới thiệu cho các bạn vậy thôi chứ không provide steps by steps :D, nói chứ dễ lắm, bạn chỉ cần set up được cái real time database và cái Grafana server là xong (dùng docker xí là xong ấy mà). Việc còn lại chỉ tìm và cài influxdb plugin cho Artillery và làm theo hướng dẫn.

Hết Artillery.io basic

Vậy là các bạn đã biết sương sương cách xài Artillery rồi. Theo cá nhân mình thấy tool này tương đối dễ xài cho một người mới bắt đầu (giống mình) làm performance testing mặc dù không có giao diện.

Một phần quan trọng mà mình không đề cập là cách chạy distributed trong Artillery, lý do là vì mình chưa có cơ hội xài nó và nó thuộc bản PRO. Ngoài ra còn một cách khác nữa nhưng phải dùng đến K8S hoặc Ansible, nếu có điều kiện thì mình sẽ thử và share với các bạn ở phần sau. See ya !!

P/S: code các bạn có thể vào repo này để lấy sample về nghiền ngẫm nhé.

Molecule : bạn tốt của Devops

Wassup các bạn đọc giả, hôm nay mình xin phép giới thiệu cho các bạn một tool mà mình đã nghiên cứu và sử dụng trong vài tháng vừa qua.

Tool này được giang hồ gọi là Molecule a.k.a “Mò Cua”, nếu các bạn đã từng sử dụng Ansible rồi thì tool này có thể giúp ích cho các bạn, còn nếu chưa từng dùng Ansible hay thậm chí không biết Ansible là gì thì ….. đọc bài viết này để lấy kinh nghiệm như chơi confetti ấy <(“).

Giới thiệu

Các khái niệm

Ansible

Ở bài này mình sẽ không nói sâu về Ansible nhưng chỉ nói sơ qua để mấy bạn dễ hình dung. Đại khái mọi người dùng nó để deploy ứng dụng, bạn có thể tưởng tượng là khi deploy một ứng dụng nào đó thì bạn phải thực hiện các công đoạn config, cài đặt các package trên một hoặc nhiều máy khác nhau, thì thằng Ansible này hỗ trợ bạn thực hiện các việc đó dễ dàng hơn (đỡ hơn phải truy cập vô từng máy rồi config, setup trực tiếp trên đó).

Playbook

Để thực hiện những công việc fancy nói trên thì bạn phải có một file playbook (file này viết dưới định dạng YAML) để mô tả những task mà bạn cần Ansible thực hiện cho công việc deploy của mình. Bên dưới là một playbook mẫu.

---
- hosts: webservers
  remote_user: root

  tasks:
  - name: ensure apache is at the latest version
    yum:
      name: httpd
      state: latest
  - name: write the apache config file
    template:
      src: /srv/httpd.j2
      dest: /etc/httpd.conf

- hosts: databases
  remote_user: root

  tasks:
  - name: ensure postgresql is at the latest version
    yum:
      name: postgresql
      state: latest
  - name: ensure that postgresql is started
    service:
      name: postgresql
      state: started

Ansible role

Thường khi làm việc với một system phức tạp, cái file playbook nó sẽ bao gồm rất là nhiều tasks chứ không có simple như những cái ở trên đâu. Do đó người ta tách nhỏ playbook ra thành các role để dễ quản lý playbook. Các role đó có thể reuse được ở nhiều playbook khác nhau.

# roles/example/tasks/main.yml
- name: added in 2.4, previously you used 'include'
  import_tasks: redhat.yml
  when: ansible_facts['os_family']|lower == 'redhat'
- import_tasks: debian.yml
  when: ansible_facts['os_family']|lower == 'debian'

# roles/example/tasks/redhat.yml
- yum:
    name: "httpd"
    state: present

# roles/example/tasks/debian.yml
- apt:
    name: "apache2"
    state: present

Nhu cầu sử dụng Molecule

Mục đích của tool không gì khác ngoài TEST những cái role đã nêu trên. Do những file playbook và role bên trên đều do con người viết ra, mà trong quá trình viết có thể bị xàm thế nào ấy gây ra lỗi dẫn tới việc deploy không được . Thuở trước khi có Molecule đây là cách mà người ta thường dùng để test một ansible role.

  • Step 1 (Set up) : kiếm hoặc tự cài đặt 1 cái máy ảo còn zin.
  • Step 2 (Exercise) : chạy file playbook của bạn trên máy ảo.
  • Step 3 (Verify) : kiểm tra xem các task của playbook có thực sự chạy không hay chỉ là cú lừa (ví dụ như xem có cài đặt đúng version của thư viện không).
  • Step 4 (Tear Down) : nếu bước trên có lỗi thì reset máy ảo lại trạng thái ban đầu rồi làm lại từ bước 1.

Các bạn cứ thử liên tưởng cứ mỗi lần có chỉnh sửa gì đó trong file (thêm 1 task mới chẳng hạn) là mình phải thực hiện cả 4 bước trên để thực thi việc test. Thì để giảm bớt các công đoạn tay chân khổ râm đó cho các bạn, Molecule ra đời. Molecule sẽ biến tất cả các step trên thu bé lại thành một câu lệnh.

Molecule

Cài đặt

Cài đặt thì ez lắm mấy bạn chỉ cần vào https://molecule.readthedocs.io/en/stable/ để xem hướng dẫn cài đặt. Riêng có bạn nào muốn cài trên Windows Linux Sub-system thì đầu tiên, bạn cần đảm bảo là docker trên windows đã được login và đang chạy. Sau đó bạn chạy thêm 2 câu lệnh dưới đây.

export DOCKER_HOST='tcp://0.0.0.0:2375'
source ~/.bashrc

Cách thức hoạt động

Như mình đã nói ở trên, Molecule giúp các bạn thực hiện các bước cần thiết để test một role. Bạn chỉ đơn giản cài molecule rồi chạy ngay trên chính laptop của bạn luôn, không cần đi đâu xa để tìm máy thiệt rồi chọc ngoáy trên đó.

Molecule cung cấp một tập các câu lệnh để thực hiện các bước tương ứng cho việc test một role, dưới đây là các câu lệnh thường được dùng. Nếu bạn không thêm bất kỳ tham số cho các câu lệnh sau thì molecule chỉ chạy với các config mặc định.

Init

Lệnh này được dùng để khởi tạo role hoặc bạn có thể dùng lại role đã có sẵn trong Ansible.

$ molecule init role -r role_name

Sau khi tạo xong Molecule sẽ tạo ra thư mục có cấu trúc như sau :

Trong đây có rất nhiều file nhưng bạn chỉ làm chủ yếu với một vài file thôi (mấy file kia mình chưa xài <(“)) :

  • molecule.yml : file configure của molecule, trong file này bạn sẽ chỉ định role nào chạy trên OS nào : Ubuntu hay CentOS, xài docker hay xài virtual box để tạo môi trường chạy test, bla bla…. Các bạn muốn thêm chi tiết thì vào link này xem thêm.
  • Dockerfile.js2 : file này molecule dùng để build docker container, bạn nào chưa biết gì về docker có thể refer tới bài này.
  • tasks/main.yml : đây là file để chỉ định các task (cài python, cài apache, v.v….) mà bạn sẽ run.
  • tests/test_default.py : file này chứa những test cases để kiểm tra xem các task có thực sự chạy thành công hay không.

Create (Step 1)

Lệnh này dùng để tạo ra môi trường ảo mà bạn sẽ thực thi các task trên đó.

$ molecule create

Converge (Step 2)

Lệnh này để thực thi mấy cái task được define trong tasks/main.yml trên môi trường ảo mới tạo ở trên.

$ molecule converge

Các bạn có thể xem hình bên dưới để hình dung ra 1 task là như lào. Dưới đây mình có sử dụng thêm 1 file nữa là vars/main.yml để chứa biến. Task này để cài 2 package httpd và ansible, simple vậy thôi.

Verify (Step 3)

Lệnh này để chạy những test cases trong tests/test_default.py

$ molecule verify

Lúc này Molecule sẽ dùng một cái tool nho nhỏ được tích hợp bên trong nó gọi là Testinfra để thực thi những test case này. Các test được viết bằng ngôn ngữ Python. Có lỗi lầm gì là nguyên màu đỏ hiện lên ngay. Bên dưới là ví dụ về việc kiểm tra xem ansible có được cài thành công không.

Destroy (Step 4)

Lệnh này dùng để gọi Thanos búng tay bay cái môi trường ảo. Thay vì bạn reset về trạng thái ban đầu thì bạn khai tử luôn cái môi trường này.

$ molecule destroy

Test

Thay vì gõ từng lệnh như trên, bạn dùng lệnh này để chạy từ A-Z.

$ molecule test

Thực sự dùng lệnh này ngoài các step trên có khuyến mãi thêm cho bạn một số step nữa :

scenario:
  name: default
  test_sequence:
    - lint
    - destroy
    - dependency
    - syntax
    - create
    - prepare
    - converge
    - idempotence
    - side_effect
    - verify
    - destroy

Nhưng các bạn có thể ăn bớt vài step bằng cách sau :

scenario:
  name: default
  test_sequence:
    - lint
    - destroy
    # - dependency
    - syntax
    - create
    # - prepare
    - converge
    - idempotence
    # - side_effect
    - verify
    - destroy

Để biết thêm về sequence mấy bạn nghía trong document của tool nhé :D, mình chỉ đưa ra những ví dụ đơn giản thôi.

Kết!

Hi vọng những thông tin trong bài viết này giúp ích cho các bạn đang và chuẩn bị làm việc với Ansible. Đối với các bạn mới mẻ chưa biết gì về Ansible thì cũng đừng lo, ít nhất giờ bạn biết xíu rồi đấy :v.

Mình sẽ cố gắng giới thiệu đến các bạn mấy tool để phục vụ cho testing như này. Đối với người tester, test là quan trọng nhất và để test hiệu quả phải biết dùng đúng tool trong đúng ngữ cảnh.

Quèo, dù gì sau hôm nay các bạn đã biết “Mò Cua”. See ya !!!

Giới thiệu về ReportPortal.io và kết hợp với Katalon Studio (Part-1)

ReportPortal.io có gì hot so với các bạn đồng trang lứa?

AI-powered Test Automation Dashboard

Để giải thích ngắn gọn, ReportPortal.io là một ứng dụng hỗ trợ phân tích kết quả khi chạy Test Automation và áp dụng nền tảng AI. Với các bạn đang làm Test Automation thì thường sẽ gặp khó khăn trong việc quản lý kết quả sau mỗi lần chạy automation cũng như phân tích kết quả đó. Vì vậy, ReportPortal.io ra đời như là một giải pháp để các bạn có thể cảm thấy cuộc sống dễ dàng hơn với những công việc trên. Ngoài ra thì nó còn có kèm theo những tính năng rất hữu ích mà mình sẽ đề cập trong bài viết này ❤

Các tính năng cơ bản

Cung cấp cơ chế hiển thị kết quả khi chạy test automation theo thời gian thực

ReportPortal cung cấp khả năng cập nhật cũng như hiển thị kết quả test và thông tin chi tiết về logs liên tục trong quá trình chạy test automation. Hãy tưởng tượng bạn cần phải chạy một bộ test suite có 200 test scripts và ngay ở những scripts đầu tiên nó đã bị failed do những tác nhân phía môi trường test (Database server không hoạt động, network bị mất kết nối, etc.) , lúc này bạn có thể mở ReportPortal Dashboard lên và biết ngay là hiện tại môi trường đang có gặp những vấn đề nào và cần phải làm gì để giảm thiểu thời gian bị lãng phí.

Quản lý mọi kết quả của những lần chạy test automation và hỗ trợ những thông số để đánh giá chất lượng test script

ReportPortal.io sẽ quản lý toàn bộ test result và hỗ trợ những thông số để giúp cho mọi thành viên trong dự án có thể xem xét và đánh giá về mức độ hữu ích mà test automation mang lại cho dự án. Hãy tưởng tượng cách ReportPortal.io cho các bạn biết mức độ ổn định của 1 test script, thời gian chạy trung bình của 1 test suite, số lượng bugs mà test automation phát hiện được, etc.

Sử dụng AI để phân tích kết quả sau khi chạy của 1 test script

Bạn nào làm nhiều automation thường sẽ bị tình trạng chạy 1 bộ test suite và sau đó ngồi phân tích từng test script bị failed để coi thử rằng liệu nó có bug ở application hay là do những nguyên nhân khác khiến test script bị failed và rồi sau đó phải chạy lại những script đó lần nữa. Đó là 1 quá trình đau khổ và có thể khiến bạn tốn thời gian tới 1 ngày trời. Và từ những điều đó thì ReportPortal.io đã sử dụng AI để tự động phân tích kết quả sau mỗi lần chạy test suite dùm các bạn, nhờ vậy các bạn có thể giảm thiểu thời gian phân tích kết quả đi khá là nhiều, giờ đây thì các bạn sẽ dễ dàng biết được những script nào bị failed là do lỗi môi trường, test script không còn tương thích với version hiện tại của hệ thống.

Hướng dẫn cài đặt ReportPortal.io

Hiện tại thì ReportPortal đã có sẵn file docker-compose.yml, cho nên các bạn cứ theo hướng dẫn bài viết ở trang chủ để có thể cài đặt ReportPortal.io trên máy của mình, ngoài ra bạn nào chưa biết về docker thì có thể tham khảo bài viết dưới đây để nắm rõ nhưng lệnh cơ bản để tiến hành cài đặt ReportPortal.io:

Hướng dẫn các lệnh cơ bản với docker

Ngoài ra thì mình có 1 vài lưu ý nhỏ cho đồng đạo nào đang xài windows mà muốn cài đặt ReportPortal.io:

  • Hiện tại thì docker image cho mongoDB trên Windows đang bị lỗi cho nên nếu các bạn sử dụng file mặc định docker-compose.yml của ReportPortal.io thì các bạn phải xóa value dưới đây ra khỏi file docker-compose:
    volumes:
    – ‘./data/mongo:/data/db’
  • Nếu không sử dụng external volumes cho mongoDB trong ReportPortal.io thì các bạn sẽ không giữ lại được data mỗi khi các bạn restart máy hoặc restart docker
  • Bạn nào sử dụng Windows thì có giải pháp hơi lòng vòng đó là sử dụng virtualbox, cài 1 image Ubuntu và sau đó cài đặt docker và cài đặt ReportPortal.io trong image đó

Hiện tại các bạn có thể làm theo hướng dẫn bài viết này của tụi mình để cài đặt ReportPortal.io trên máy mình.

Part 1 : Tích hợp ReportPortal.io vào Katalon Studio

Đọc tới đây thì chắc các bạn cũng hình dung được ReportPortal.io nó vi diệu như thế nào rồi, giờ tới lúc mình cùng tìm hiểu xem làm sao để “xài” nó, tức làm thế nào để tích hợp nó vào các test framework hoặc các công cụ kiểm thử tự động (automation testing tools).

Ở phần 1 này, mình sẽ giới thiệu cách tích hợp ReportPortal vào Katalon Studio – một công cụ kiểm thử tự động của công ty KMS Technology.

Khâu chuẩn bị

  • Tải và cài đặt Katalon Studio phiên bản mới nhất (chỉ cần giải nén và chạy file .exe). Ngoài lề chỗ này là dạo gần đây không biết vì sao Katalon Studio ra version liên tục như gà đẻ trứng 😦 nên cứ update version mệt mỏi luôn.
  • Làm theo hướng dẫn để dựng lên một server ReportPortal.io của riêng bạn.

P/S :  chuẩn bị thêm tinh thần viết code Groovy nữa nha <(“).

Khâu phân tích và chiêm nghiệm

Đối chiếu các khái niệm của ReportPortal vào Katalon Studio
Launch

Như đã định nghĩa trong tài liệu của ReportPortal.io, launch là một đối tượng lưu dữ liệu của một lần thực thi.

Trong Katalon Studio, khi bạn thực thi (nói trắng ra là bấm nút Run trên IDE ấy) một test suite thì một launch được tạo trên ReportPortal, khi bạn chạy nhiều test suite cùng lúc (dùng tính năng suite collection trong Katalon) thì tương đương nhiều launch sẽ được tạo.

Trên thực tế, một launch được thiết kế để chứa nhiều suite nhưng do cơ chế hoạt động của Katalon khá vi diệu nên một launch sẽ tương ứng với một suite.

Test Item

Một launch tập họp nhiều test item, một test item có thể là một test case, test step hoặc test suite, v.v… nó là gì tùy bạn quyết định. Bản thân một test item có thể chứa nhiều test item bên trong nó, khi đó các test item ở bên trong được gọi là test item con (child test item) và test item chứa các con là test item cha (parent test item).

Ở trên một launch đã tương ứng với một suite, nên theo tính chất bắc cầu thì các test case của một suite được xem là test item của launch và bắc thêm cái cầu nữa thì  các test step của test case sẽ là child của test item đó.

Issue

Trong quá trình thực thi, việc test script bị fail là điều không thể tránh khỏi (cuộc sống mà!), lúc đó mình sẽ ra lệnh ReportPortal đánh các test script đó một “thẹo” (nhiều test step bị fail tương ứng với nhiều thẹo). Mặc định, ReportPortal có sẵn 5 loại thẹo (nhưng bạn có thể chế thêm) :

  • To Investigate  :  đây là những lỗi lạ xảy ra trong quá trình thực thi và đang đợi bạn chẩn đoán.
  • Product bug : lỗi của app (thấy là submit liền tay).
  • Automation bug : lỗi của automation scripts, ví dụ : scripts cũ như chưa từng được cũ.
  • System issue : lỗi hệ thống, ví dụ: bị crash, mạng siêu chậm.
  • No defect : đây là những lỗi xạo, ban đầu báo lỗi nhưng sau quá trình chẩn đoán pháp y các kiểu thì nó không phải là lỗi.

Mình muốn giới thiệu sơ lược về mấy loại thẹo này để khi gặp mấy hình tròn xanh đỏ vàng trên ReportPortal các bạn biết nó là gì.

Và một điều nữa các bạn nên biết là việc đánh thẹo chỉ có tác dụng lên các test item có status là FAILED hoặc SKIPPEDví dụ khi bạn cố đánh thẹo cho một test item có status là PASSED, thì đánh cỡ nào nó cũng không dính.

Khâu hiện thực (và đọc code mẫu)

Cách thực hiện việc integrate

Để tạo một đối tượng launch hay test item, các bạn phải gửi 2 request lên server ReportPortal : một request để khởi tạo (start) đối tượng và một request để dừng (finish) đối tượng đó. Lý do vì sao phải gửi 2 request này là do ReportPortal thích thế <(“).

Trong suốt quá trình một đối tượng được tạo cho đến khi nó dừng, bạn hoàn toàn có quyền ra lệnh ReportPortal làm bất cứ gì với đối tượng bằng cách gửi các request tương ứng cho các tác vụ đó (đánh thẹo cho cái đối tượng đang chạy chẳng hạn). Nhưng một khi đối tượng đã dừng (request finish đã được gửi), bạn không còn quyền tác động đến nó nữa.

Túm lại, luồng hiện thực của chúng ta sẽ như sau :

  1. Gửi request tạo launch (Katalon Suites)
  2. Gửi request tạo test item cha (Katalon Test Cases)
  3. Gửi request tạo test item con (Katalon Test Steps)
  4. Gửi request dừng test item con.
  5. Gửi request dừng test item cha.
  6. Gửi request dừng launch.

Ở các bước gửi request finish các test item (4,5), các request đó phải kèm theo trạng thái (status) của test script (Pass, Fail, v.v..). Trong ReportPortal, có 6 loại trạng thái : PASSED, FAILED, SKIPPED, STOPPED, CANCELLED, INTERRUPTED nhưng trong Katalon chỉ có 3 loại : PASSED, FAILED, ERROR. Do đó ta phải xào nấu nhào nặn để cả Katalon và ReportPortal có chung tiếng nói :

Katalon Studio status ReportPortal status Issue
PASSED PASSED No defect
FAILED FAILED Product bug
ERROR FAILED To investigate

Các bạn theo đường link này để vào xem danh sách các API của ReportPortal để ra lệnh cho nó: https:// [server ReportPortal của bạn]/ui/#api

Tạo Listener

Ở bước này, các bạn cần tạo một class (nằm trong thư mục Keyword) hiện thực ExecutionListenerEventHandler interface (cái này của Katalon), sau đó nhét code của bạn vào phương thức handleListenerEvent của interface đó.

@Override
public void handleListenerEvent(ExecutionListenerEvent event, Object[] testParam) {
    // TODO : your code here
}

Trong đó, event tương đương các giai đoạn của quá trình thực thi, và tùy theo giai đoạn thì tham số testParam nhận vào các giá trị khác nhau (đại loại tham số này có thể giúp bạn lấy tên test script, tên step, v.v…)  :

switch (event) {
        case ExecutionListenerEvent.AFTER_TEST_SUITE:
            endSuite()
            break
        case ExecutionListenerEvent.BEFORE_TEST_CASE:
            startTest()
            break
        case ExecutionListenerEvent.AFTER_TEST_CASE:
            endTest(status)
            break
        case ExecutionListenerEvent.BEFORE_TEST_STEP:
            startStep()
            break
        case ExecutionListenerEvent.AFTER_TEST_STEP:
            endStep(status)
            break
        default:
            break
}
Sử dụng Listener

Chúc mừng bạn, tới đây thì bạn đã có đầy đủ điều kiện để xài ReportPortal với Katalon rồi, công việc còn lại là tìm chỗ để nhét listener vào thôi, nhét đúng chỗ là ReportPortal auto chạy.

Bước này đơn giản lắm, bạn mở suite của Katalon lên ở script mode của suite đó và nhét vào câu lệnh này (nhớ thay cái MyListener bằng tên Listener của mấy bạn nha).

@SetUp(skipped = false)
def setUp() {
    ExecutionEventManager.getInstance().addListenerEventHandle(new MyListener())
}

Tận hưởng thành quả nào !!! Dưới đây là một vài hình ảnh minh họa sau khi tích hợp ReportPortal vào Katalon.

Tham khảo code mẫu

Các bạn có thể tham khảo code mẫu ở link này, giải nén và copy 2 thư mục bên trong vào project Katalon của bạn. Các bước sử dụng code mẫu như sau :

  1. Thay giá trị của các biến trong ReportPortal profile bằng thông tin trên ReportPortal server của bạn :
    • RP_HOST : API host của ReportPortal. Ex : http://127.0.0.1:8080/api/v1
    • RP_TOKEN : ‘Bearer’ + giá trị UUID (bạn có thể tìm thấy giá trị này trong user profile của bạn). Ex : Bearer f974e146-5f90-4912-9332-5b77d7bbd3d8userprofile
    • RP_NAME : tên project của bạn trên ReportPortal.
  2. Vào suite của bạn ở script mode, chèn đoạn code này vào phương thức setUp (nhớ đổi skipped = false). Đoạn code bên dưới có nghĩa nó sẽ tạo ra một launch có tên là API_Sample_Suite mỗi lần bạn chạy cái suite đó.
@SetUp(skipped = false) // Please change skipped to be false to activate this method.
def setUp() {
	// Put your code here.
	ExecutionEventManager.getInstance().addListenerEventHandle(new ReportPortalListener("API_Sample_Suite"))
}

Hết phần 1

Vậy là xong phần 1, các bạn đã biết được làm thế nào để “xài” ReportPortal với Katalon Studio rồi đó. Các phần tiếp mình sẽ giới thiệu cách sử dụng ReportPortal.io với các test framework trên JavaScript như Protractor, CucumberJS, etc.

Chắc sẽ có vài bạn thắc mắc là Katalon Studio có hỗ trợ Katalon Analytics vậy thì sao mình lại còn đi sử dụng ReportPortal.io. Thiệt ra lý do cũng đơn giản thôi nó phụ thuộc vào 3 chữ TTT (Tại Tôi Thích), nói đùa thôi chứ Katalon Analytics mình thấy cũng tốt nhưng nếu so với ReportPortal.io hiện giờ thì nó đang thiếu khá nhiều thứ, từ dashboard ko có nhiều metrics cũng như graph chưa hữu ích cho tới việc vẫn chưa thật sự có AI trong khâu tự động phân tích kết quả (mà mình nghĩ tương lai có khi Katalon Analytics lại có thể xây dựng hệ thống AI thông minh hơn ReportPortal.io, có thể họ sẽ lấy những kết quả của chính các bạn đang sử dụng Katalon Studio để train ra model, chỗ này mình cũng không thích lắm nếu đó là sự thật vì khi đó :)) ai sẽ là người bảo đảm các thông tin nhạy cảm của dự án các bạn được an toàn nè 😀 ).