Need an ARK? I Noah guy.

Component Testing

  1. Check service in isolated infrastructure
  2. Check service contracts
    • Validate response with JSON schema
    • Validate interaction with other services

Mock external services

  1. Wiremock in docker container
    Dockerfile
    FROM platform/xas-base:0.4.4
    
    ARG WM_PACKAGE=wiremock
    ARG WM_VERSION=1.58
    
    ENV APP_NAME $WM_PACKAGE
    # install and run wiremock
    RUN curl -sSL -o $WM_PACKAGE.jar repo_url
                
  2. Control mock via remote api

Execute tests workflow

  1. Pull docker images
  2. Start Mock for MDS
  3. Start Mock for Task Processor
  4. Start ARK
  5. Execute tests
  6. Collect ARK logs
  7. Stop containers

Gradle task

Custom gradle plugin

build.gradle
apply plugin: 'component-tests-plugin'

componentTests {
    useDocker = true

    ark {
        image = project.arkImage
        tag = project.arkImageTag
    }

    emulator {
        image = project.emulatorImage
        tag = project.emulatorImageTag
    }
}
                    

Integration Testing

  1. 119 & 4(+9)
  2. Using RC common libraries
  3. Using ARK mock for exceptional cases
  4. Part of deployment pipeline
  5. Run TestNG(RCTF) with Gradle

RC common libraries

  1. rc-restassured
    • RcRestAssured should receive environment configuration for each test method to use "ToPwrFilter";
    • No configuration -> no filter;
    • Use to override: RedirectFilter() and given(PwrFilter.DISABLED).

RC common libraries

  1. rc-allure
    • ReportNG -> Allure Report;
    • rc-restassured is integrated with rc-allure to provide clear output;
    • Specify aspectjweaver in run configuration;
    • Use Allure CLI to generate and run report;
    • Extend Allure Report with custom plugins.

ARK Mock

  1. Mock behaviour scenarios are stored in api-server repository
  2. They could be easily extended and passed to test with @DataProvider
  3. Scenario is mapped to RCRequestID to resolve parallel execution

ARK Mock

public class ArkEmulatorScenarios {

    private final MockServerClient client;

    public ArkEmulatorScenarios(MockServerClient client) {
        this.client = client;
    }

    public void returnMalformedRequest(String requestId) {
        expectResponse(requestId,
                ArkErrors.MALFORMED_REQUEST.toResponse());
    }
}

ARK Mock

public void checkAndPrepareArkMock() {
    String rcRequestId = UUID.randomUUID().toString();
    MockServerClient mock = new MockServerClient(resolvedArkUri.getHost(),
                resolvedArkUri.getPort());

    ArkEmulatorScenarios scenario = new ArkEmulatorScenarios(mock);
    scenario.dropConnection(rcRequestId);
}

TestNG(RCTF) and Gradle

task integrationTests(type: Test) {
    systemProperties System.getProperties()
    jvmArgs "-javaagent:${configurations.agent.singleFile}"
    systemProperty "log4j.defaultInitOverride", false
    systemProperty 'user.dir', project.projectDir

    useTestNG() {
        suiteXmlBuilder().suite(name: 'ARK Tests') {
            test(name : 'Integration') {
                classes('') {
                    'class'(name: 'com.ringcentral.qa.integration.TestCreateDeviceOrderAsync')
                }
            }
        }
    }
}

TestNG and Gradle

ark-tests:clean integrationTests --info
-Dpod=1 -Dpop=1
-Denvironment.adsEnvId=${ENV_ID}
...

Jenkins

  1. Jobs pipeline
  2. Deploy via ADS
  3. Trigger by commit

Deploy via ADS

1. Python script

http://mercurial.nordigy.ru/platform/tools
deploy.py --env MY-ENV
    --components ark:feature_branch mds:latest
    -v true

2. Jenkins Job

Performance testing

Gatling

  1. High performance
  2. Developer-friendly DSL
  3. Easy integrate with AGS
  4. Ready-to-present HTML reports

"Arm yourself for performance"

Gatling Simulation

class MySimulation extends Simulation {
  val conf = http.baseUrl("http://localhost")

  val scn = scenario("Gatling")
      .exec(http("index").get("/"))
      .feed(AccountFeeder())
      .during(10 minutes) {
        exec(
          http("json").get("/json")
            .check(jsonPath("$.id")
            .saveAs("id"))
        )
      }
  setUp(scn.inject(atOnceUsers(1)))
      .protocols(conf)
}

Integrate with AGS

object AccountFeeder {
  val accountService: AccountService = new AccountService()

  def apply(): RecordSeqFeederBuilder[String] = {
    return accountService.getAccounts(50).circular
  }
}

High Availability Testing

If you don't have high availability

you're gonna have a bad time

High Availability Testing

Recipe Like Grandma Used to Make

  • L - Load with Gatling
  • O - Orchestrate with Ansible
  • M - Monitor with Zabbix/Marathon

Ansible

is a fictional machine capable of instantaneous or superluminal communication

  • Manage your inventory in simple text files
  • Playbooks: a simple + powerful automation language
  • Parallel task execution

Ansible Pros & Cons

  • (+) Easy to start to use, good for small environments;
  • (-) Requires a solid SSH connection, need to be reconfigured after full deployments;
  • (-) Doesn't fail fast... it bombs, because of bare minimum of syntax checks;
  • (-) Large playbooks are hard to be maintained.

Ansible

Inventory

[pladis-pas]
pla01-t04-pas[01:03]

[pladis-mds]
pla01-t04-mds[01:02]

marathon ansible_host=10.62.3.250

[pladis-pwr]
pla01-t04-pwr01

Ansible

Playbook to manage ARK in Marathon

- hosts: localhost
  tasks:
    - name: make request to marathon api
      tags:
        - get_ark_status
      uri:
        url: http://{{ hostvars['marathon']['ansible_host']  }}:8080/v2/apps?id=pla01-t04-ark
        method: GET
        user: marathon
        password: marathon
        force_basic_auth: yes
      register: restdata
    - debug: msg="{{ restdata.json.apps[0].id }}:{{ restdata.json.apps[0].tasksRunning }}:{{ restdata.json.apps[0].tasksHealthy }}:{{restdata.json.apps[0].tasksUnhealthy}} {{ restdata.json.apps[1].id }}:{{ restdata.json.apps[1].tasksRunning }}:{{ restdata.json.apps[1].tasksHealthy }}:{{restdata.json.apps[1].tasksUnhealthy}}"
      tags:
        - get_ark_status
    - debug: msg="No errors for ark01 and ark02"
      tags:
        - get_ark_status
      when: restdata.json.apps[0].tasksUnhealthy==0 and restdata.json.apps[1].tasksUnhealthy==0

Ansible

Playbook to manage ARK in Marathon

    - name: ARK kill ark01
      tags:
        - kill_ark01
      uri:
        url: http://{{ hostvars['marathon']['ansible_host']  }}:8080/v2/apps/pla01-t04-ark01/tasks?scale=true
        method: DELETE
        user: marathon
        password: marathon
        force_basic_auth: yes
      register: ark01_restdata
    - debug: msg="{{ ark01_restdata.msg }}"
      tags:
        - kill_ark01

Ansible

Execute tasks

# ansible pladis-pas -m shell -a "service pas status"
pla01-t04-pas02 | SUCCESS | rc=0 >>
pas (pid 8322) is running...

pla01-t04-pas03 | SUCCESS | rc=0 >>
pas (pid 9299) is running...

pla01-t04-pas01 | SUCCESS | rc=0 >>
pas (pid 23079) is running...

Ansible

Execute tasks

# ansible-playbook marathon.yaml -t get_ark_status

PLAY [localhost] ***************************************************************

TASK [setup] *******************************************************************
ok: [localhost]

TASK [make request to marathon api] ********************************************
ok: [localhost]

TASK [debug] *******************************************************************
ok: [localhost] => {
    "msg": "/pla01-t04-ark01:3:3:0 /pla01-t04-ark02:3:3:0"
}

TASK [debug] *******************************************************************
ok: [localhost] => {
    "msg": "No errors for ark01 and ark02"
}