Skip to content

adrianwit/golang-e2e-testing

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

22 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Prerequisites

  1. Download the latest secret and endly app

  2. Localhost SSH secrets

Generate pub/private key pair

mkdir $HOME/.secret
ssh-keygen -b 1024 -t rsa -f id_rsa -P "" -f $HOME/.secret/id_rsa
touch ~/.ssh/authorized_keys
cat $HOME/.secret/id_rsa.pub >>  ~/.ssh/authorized_keys 
chmod u+w authorized_keys

Provide credentials for localhost

 $  endly -c=localhost
Enter Username: 
Enter Password: 
  1. Datastore secrets

Generate password for mysql

 $  endly -c=mysql
Enter Username: root
Enter Password:  dev

endly -c=pg
  1. IDE setup (ideally with YAML, JSON, CSV viewer)

a) Atom with tablr plugin (apm install tablr)

b) IntelJ with Database Tools and SQL plugin https://www.jetbrains.com/help/idea/editing-csv-and-tsv-files.html

Typical e2e testing workflow

  1. System preparation
    • Local or remote
    • System services initialization. (RDBM, NoSQL, caching or 3rd party API, docker services)
    • Application container. (Docker, Application server, i,e, tomcat, glassfish)
  2. Application build and deployment
    • Code checkout (local/remote).
    • Application build (with or without docker)
    • Application deployment (with or without docker)
  3. Datastore preparation - loading schema - loading static data
  4. Testing
    • HTTP runner
    • REST runner
    • Selenium runner
    • Application output verification
    • Application persisted data verification
    • Application produced log verification
    • Application with 3rd party API interaction
  5. Cleanup
    • Data cleanup
    • Application shutdown
    • Application system services shutdown

Endly services

Service is actual execution unit, in order to run any workflow's action or piple task you have use specify :

  • service ID
  • action
  • actual action request
    endly -s='*'
    endly -s='storage' -a=copy
    endly -s='exec' -a=run

See more about service

Service action run:

Pipeline
endly -r=hello
endly -r=hello message=greetings

@hello.yaml

defaults:
  target:
    URL: ssh://127.0.0.1
    credentials: localhost
pipeline:
  hello:
    action: "exec:run"
    commands:
      - whoami
      - echo '${params.message} $cmd[0].stdout'

See more about pieeline

Workflow
endly -w=hello
endly -r=hello message=greetings

@hello.csv

Workflow Name Tasks
hello %Tasks
[]Tasks Name Description Actions
greet Run greet task %Greet
[]Greet Description Service Action Request
print greeting message exec run @run.yaml

@run.yaml

target:
  URL: ssh://127.0.0.1
  credentials: localhost
commands:
  - whoami
  - echo '${params.message} $cmd[0].stdout

See more about workflow

Running multiple tasks:
    endly -r=test

@test.yaml

defaults:
  target:
     URL: ssh://127.0.0.1/
     credentials: localhost
pipeline:
  init:
    action: selenium:start
    version: 3.4.0
    port: 8085
    sdk: jdk
    sdkVersion: 1.8
  test:
    action: selenium:run
    browser: firefox
    remoteSelenium:
      URL: http://127.0.0.1:8085
    commands:
      - get(http://play.golang.org/?simple=1)
      - (#code).clear
      - (#code).sendKeys(package main

          import "fmt"

          func main() {
              fmt.Println("Hello Endly!")
          }
        )
      - (#run).click
      - command: output = (#output).text
        exit: $output.Text:/Endly/
        sleepTimeMs: 1000
        repeat: 10
      - close
    expect:
      output:
        Text: /Hello Endly!/

E2E testing workflow generator

Open workflow generator

Generate workflow with the following options

  1. Application

    • Template: "golang: simple web/rest"
    • Name: myapp
  2. Datastore:

    • Engine: MySQL
    • Name: db1
  3. Testing:

    • Selenium runner
    • REST runner
    • setup data per use case
  4. Download

cd app:

    endly -w=manager  -t='?'

Workflow assets:

  myapp
    | - app source code
    | - endly  
    |    |- system.yaml
    |    |- datastore
    |    |    | - $db   
    |    |    |    | - dictionary
    |    |    | - schema.sql
    |    |- datastore.yaml
    |    |- app.yaml
    |    |- regression
    |    |- var
    |    |   |- init.json
    |    |- req
    |    |   |- run.yaml
    |    |- manager.csv         
  myapp
    | - app source code
    | - endly  
    |    |- regression
    |    |     | - regression.csv
    |    |     | - var/
    |    |     |    |- /init.json
    |    |     |    |- /test_init.json    
    |    |     | - req /
    |    |     |    | - data.yaml
    |    |     |                      
    |    |     | - use_cases
    |    |     |    | - 001_xx_case  
    |    |     |    |     | - $db_data.json
    |    |     |    |     | - selenium_test.yaml
    |    |     |    |     | - http_test.json
    |    |     |    |     | - rest_test.json    
    |    |     |    |     | - use_case.txt    
  1. Workflow application and datastore schema
  1. Testing workflow main assets:
  1. Running workflow
cd <Myapp>/endly
endly

WEB pages:

REST endpoint

    
    endly -t='init,test'
    
  1. Adding selenium test
endly -r=test

@test.yaml

defaults:
  target:
     URL: ssh://127.0.0.1/
     credentials: localhost
pipeline:
  init:
    action: selenium:start
    version: 3.4.0
    port: 8085
    sdk: jdk
    sdkVersion: 1.8
  test:
    action: selenium:run
    browser: firefox
    remoteSelenium:
      URL: http://127.0.0.1:8085
    commands:
      - get(http://127.0.0.1:8080/form.html)
      - (#id).clear
      - (#id).sendKeys('111111')
      - (#name).clear
      - (#name).sendKeys('dummy 123')
      - (#typeId).clear()
      - (xpath://SELECT[@id='typeId']/option[text()='type1']).click()
      - (#agree).click      
      - (#submit).click
      - command: CurrentURL = CurrentURL()
        exit: $CurrentURL:/dummy/
        sleepTimeMs: 1000
        repeat: 10
      - PageSource = pageSource()  
    expect:
      PageSource: /dummy 123/
  • Client side validation

@test.yaml

defaults:
  target:
     URL: ssh://127.0.0.1/
     credentials: localhost
pipeline:
  init:
    action: selenium:start
    version: 3.4.0
    port: 8085
    sdk: jdk
    sdkVersion: 1.8
  test:
    action: selenium:run
    browser: firefox
    remoteSelenium:
      URL: http://127.0.0.1:8085
    commands:
      - get(http://127.0.0.1:8080/form.html)
      - (#id).clear()
      - (#id).sendKeys('111111')
      - (#name).clear()
      - (#typeId).clear()
      - (xpath://SELECT[@id='typeId']/option[text()='type1']).click()
      - (#submit).click()
      - name = (xpath://DIV[preceding-sibling::INPUT[@id='name']]).text()
    expect:
      name:
        Text: /Please choose a dummy name/

c) As part of regression workflow

modify regression/use_cases_001_xx_case/selenium_test.json

-- modify Test{1..002} to Test{1..001} to ony work on use case 001
-- make sure that application is up and running (endly -t='init,test'
endly -r='test'
  1. Adding REST test

a) Running a test vi shared action workflow

endly -w=action service='rest/runner' action=send request='@send.json'

@send.json

{

    "Method": "POST",
    "URL": "http://127.0.0.1:8080/v1/api/dummy",
    "Request":{
        "Data":{
            "TypeId":1,
            "Name":"dummy 33333"
        }
    },
	"Expect": {
        "Data": {
            "Name":"dummy 33333"
        }	
	}
}

b) Running as inline workflow

endly -r=test

test.yaml

pipeline:
  task1:
    action: rest/runner:send
    request: "@send.json" 

c) As part of regression workflow

modify regression/use_cases_001_xx_case/rest_test.json

-- modify Test{1..002} to Test{1..001} to ony work on use case 001
-- make sure that application is up and running (endly -t='init,test'
endly -r='test'
  1. Adding HTTP test

a) Running a request vi shared action workflow

endly -w=action service='http/runner' action=send request='@send.json'

@send.json

{
	"Requests": [
		{
			"Method": "POST",
			"URL": "http://127.0.0.1:8080/v1/api/dummy",
			"Body":"{}"
		}
	],
	"Expect": {
      "Responses":[{
          "Code":200,
          "JSONBody": {
              "Status":"error",
              "Error":"data was empty"
          }
        }]	
	}
}

b) Running with as inline workflow

endly -r=test

test.yaml

pipeline:
  task1:
    action: http/runner:send
    request: "@send.json" 

c) As part of regression workflow

modify regression/use_cases_001_xx_case/http_test.json

-- modify Test{1..002} to Test{1..001} to ony work on use case 001
-- make sure that application is up and running (endly -t='init,test'
  1. Adding test with use case data:

a) change regression/use_cases/001_xx_case/db1_data.json to the following

[
  {
    "Table": "dummy",
    "Value": {
      "id": "$seq.dummy",
      "name": "My super dummy 1",
      "type_id": 2
    },
    "PostIncrement": [
      "seq.dummy"
    ],
    "Key": "${tagId}_dummy"
  }
]

b) note that in the regression/var/test_init.json the added record is placed to the context state:

so that it can be reference as $dummy.

[
  {
    "Name": "dummy",
    "From": "<-dsunit.${tagId}_dummy"
  }
]
endly -t=test

c) modify regression/use_cases_001_xx_case/rest_test.json

@send.json

{

    "Method": "GET",
    "URL": "http://127.0.0.1:8080/v1/api/dummy/${dummy.id}",
    "Request":{},
	"Expect": {
        "Data": {
            "Id":"$dummy.id",
            "Name":"$dummy.name",
            "TypeId":"${dummy.type_id}"
        }	
	}
}

Validation

clone this project to run the following examples:

endly -s=validator -a=assert

endly -r=run

@run.yaml

pipeline:
  build:
    action: workflow:print
    message: building app ...
  test:
    workflow: assert
    actual:
      key1: value1
      key2: value20
      key3: value30
    expected:
      key1: value1
      key2: value2
      key3: value3
      key4: value4     
endly -w=assert -t='?'
endly -w assert -p -f=yaml

Simple validation

endly -w=assert actual A expected B

Data structure validation

endly -w=assert actual '@actual1.json' expected '@expected1.json'

Data structure transformation validation

endly -d=true -w=assert actual '@actual2.json' expected '@expected2.json'

Data structure alternative transformation validation (switch/case)

endly -d=true -w=assert actual '@actual3.json' expected '@expected3.json'

See more about validation expression

About

golang end to end testing with endly

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published