Giter Club home page Giter Club logo

aloe's Introduction

Aloe

Build Status Coverage Status GoDoc Go Report Card

Aloe is a declarative API test framework based on ginkgo, gomega and yaml. It aims to help write and read API test cases simpler.

DISCLAIMER:

  • only json API is supported now
  • avoid using Aloe for extremely complex test, use ginkgo directly instead

Terminology

There are two important concepts in aloe:

  • case: case means a test case, for example, get an endpoint and verify its output.
  • context: to simply put, a context is a group of cases. Usually, context is used to init data in database, so that all test cases will be tested in a determined context.

Getting Started

Following is a getting started example for using Aloe. First, create a directory to put context and case yaml files.

mkdir -p test/testdata

Then, define your context in context.yaml.

# test/testdata/context.yaml
summary: "CRUD Test example"
flow:
- description: "Init a product"
  request:
    api: POST /products
    headers:
      "Content-Type": "application/json"
    body: |
      {
        "id": "1",
        "title": "test"
      }
  response:
    statusCode: 201
  definitions:
  - name: "testProductId"
    selector:
    - "id"

As mentioned above, a context is used to run a group of test cases in a determined environment. In the above example, we define a context which simply sends a POST request to /products with product name test; therefore, all test cases in this context will expect product test exists.

Now with context setup, we can start defining case. Here, we define a test case in test/testdata/get.yaml to get and verify product test.

# test/testdata/get.yaml
description: "Try to GET a product"
flow:
- description: "Get the product with title test"
  request:
    api: GET /products/%{testProductId}
    headers:
      "Content-Type": "application/json"
  response:
    statusCode: 200

Finally, some go codes should be written in test directory to run the test case:

func init() {
	aloe.Init(nil)
}

func RunTEST(t *testing.T) {
	aloe.AppendDataDirs("testdata")
	if err := aloe.Env("host", "localhost:8080"); err != nil {
		fmt.Printf("can't set env host: %v", err)
		os.Exit(1)
	}
	if err := aloe.RegisterCleaner(s); err != nil {
		fmt.Printf("can't register cleaner: %v", err)
		os.Exit(1)
	}
	aloe.Run(t)
}

var _ = ginkgo.BeforeSuite(func() {
    s.Register()
    listener, err := net.Listen("tcp", ":8080")
    if err != nil {
        fmt.Println("can't begin server")
        os.Exit(1)
    }
    go http.Serve(listener, nil)
})

Usage

Variable

Variables can be defined to hold auto-generated value by server (e.g. id). For example:

flow:
- description: "Init a product"
  definitions:
  - name: "testProductId"
    selector:
    - "id"

A variable called testProductId will be defined. The value of testProductId is from the round trip response.

Variable can also be a json snippet.

response:
{
    "id": "111",
    "title": "test",
    "comments":[
        "aaa",
        "bbb"
    ]
}

// id will select value of string
["id"] => 111(without quote)

// empty selector will select whole body
[] => {
    "id": "111",
    "title": "test",
    "comments":[
        "aaa",
        "bbb"
    ]
}

// comments will select partial body
["comments"] => [
    "aaa",
    "bbb"
]

// comments.0 will select first element of array
["comments", "0"] => aaa

If a variables is defined, it can be used in round trip with format %{name}.

Body validator

Body validator is used to validate response fields. Some special validators are predefined, e.g. $regexp

flow:
- description: "Create a product"
  response:
    # validate that id format matches regexp
    # validate that password field is not returned
    body: |
      {
        "id": {
          "$regexp": "[a-zA-Z][a-zA-Z0-9-]{11}"
        },
        "password": {
          "$exists": false,
        },
      }

Now only $regexp and $exists is supported (more special validator will be added in the future).

Cleaner

Cleaner can be used to clean context after all cases in the context are finished.

type Cleaner interface {
    // Name defines cleaner name
    Name() string

    // Clean will be called after all of the cases in the context are
    // finished
    Clean(variables map[string]jsonutil.Variable) error
}

Users can implement their own cleaners and call RegisterCleaner in framework. Then cleaners can be used in context file.

# test/testdata/get.yaml
summary: "Create a product"
flow:
- description: "Create a product"
  request:
    api: POST /products
  response:
    statusCode: 201
cleaner: "productCleaner"

Presetter

Presetter can be used to preset all RoundTrips in the context.

// Presetter defines presetter
type Presetter interface {
    // Name defines name of presetter
    Name() string

    // Preset parse args and set roundtrip template
    Preset(rt *types.RoundTrip, args map[string]string) (*types.RoundTrip,
    error)
}

Users can implement their own presetters and call RegisterPresetter in framework. Then presetters can be used in context file.

# test/testdata/get.yaml
summary: "Create a product"
presetter:
- name: "header"
  args:
    content-type: application/json
flow:
- description: "Create a product"
  request:
    api: POST /products
  response:
    statusCode: 201

Nested context

Context can be nested just like directory. Child context will see all setup in parent context.

tests
└── testdata
    ├── _context.yaml
    ├── basic
    │   ├── _context.yaml
    │   ├── create.yaml
    │   └── update.yaml
    ├── failure
    │   ├── _context.yaml
    │   └── create.yaml
    └── list
        ├── _context.yaml
        └── list_all.yaml

Examples

For more examples, see:

aloe's People

Contributors

bbbmj avatar caicloud-bot avatar jimexist avatar liubog2008 avatar mouuii avatar pendoragon avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

aloe's Issues

Add random key word

Is this a BUG REPORT or FEATURE REQUEST?:

Uncomment only one, leave it on its own

/kind feature

What happened:

sometimes a random string or int is needed to generate different context

What you expected to happen:

  1. add random key word

How to reproduce it (as minimally and precisely as possible):

Anything else we need to know?:

Headers doesn's work

Is this a BUG REPORT or FEATURE REQUEST?:

/kind feature

What happened:

flow:
- description: "Get user info in info.yaml"
  request:
    api: GET /user
    headers:
      "Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NjY0NTgxNjAsImlzcyI6IkRpMjMwOXNsa2Q5OGE5OGFkaWFzZGxmMDlzZGdka2YyMWtqZ3Nka2YiLCJ1aWQiOjEwMDAwMDd9.Xff-abmUDYejaGMKI5r1gBEUSeLYu5ARboAAcjoEZ2g"
  response:
    statusCode: 200

What you expected to happen:

statusCode:200

Acture result

statusCode:400

Anything else we need to know?:
Is my headers set right or not?

print pretty json data when test failed

• Failure [100.219 seconds]

/Users/admin/go/src/github.com/caicloud/tenant-admin/vendor/github.com/caicloud/aloe/framework.go:48
  create.yaml: Test create a partition eventually create corresponding namespace and quota [It]
  /Users/admin/go/src/github.com/caicloud/tenant-admin/vendor/github.com/caicloud/aloe/framework.go:84

  Timed out after 100.001s.
  Expected
      <string>: 
  to match response: {
  status code is not matched, expected: 200, actual: 404
  api status: {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"resourcequotas \"test-partition-123\" not found","reason":"NotFound","details":{"name":"test-partition-123","kind":"resourcequotas"},"code":404}
  
  }

should be print api real response when test fail

Support tls config

Is this a BUG REPORT or FEATURE REQUEST?:

Uncomment only one, leave it on its own line:

/kind bug
/kind feature

/kind feature

What happened:

Sometimes we need to call API of different hosts with different tls config

What you expected to happen:

Different tls configs for different cases should be supported.

How to reproduce it (as minimally and precisely as possible):

Anything else we need to know?:

Something else like tls config in http.Client also need to be supported.

should be print every test cases description

i afraid my testcases not executed

➜  test git:(e2e_testcases) ✗ go test -v
=== RUN   TestPartitionAPI
Running Suite: API Suite
========================
Random Seed: 1514432621
Will run 1 of 1 specs

clean successfully
•
Ran 1 of 1 Specs in 0.267 seconds
SUCCESS! -- 1 Passed | 0 Failed | 0 Pending | 0 Skipped --- PASS: TestPartitionAPI (0.27s)
PASS
ok  	github.com/caicloud/tenant-admin/test	0.350s

Add description of aloe

What is the issue about:

  • add description

What happened:

What you expected to happen:

Anything else we need to know:

Add condition and loop key word in the flow

Is this a BUG REPORT or FEATURE REQUEST?:

Uncomment only one, leave it on its own line:

/kind feature

What happened:

round trip flow should support condition and loop control

What you expected to happen:

  1. add key word when
  2. and key word loop

How to reproduce it (as minimally and precisely as possible):

Anything else we need to know?:

Add labels to run the selected test case

Is this a BUG REPORT or FEATURE REQUEST?:

Uncomment only one, leave it on its own line:

/kind bug
/kind feature

/kind feature

What happened:

Now test case can not be selected, all test cases should be run every time

What you expected to happen:

e.g.
go test --skip "time=slow"
go test --pick "type=get"

How to reproduce it (as minimally and precisely as possible):

Anything else we need to know?:

Register clean and preset function

Is this a BUG REPORT or FEATURE REQUEST?:

Uncomment only one, leave it on its own line:

/kind bug
/kind feature

/kind feature

What happened:

Now only one clean function can be used to clean up context

What you expected to happen:

  1. each context can define its own clean function
  2. each context can define its own preset function

How to reproduce it (as minimally and precisely as possible):

Anything else we need to know?:

use cases:

  1. We only want to clean up the namespace which is created in the context
  2. We want to get token and set into header for all requests in the context

About unclear test failure messages

This issue is used for recording unclear failure messages

Template

expected or advice:

StatusCode is 404, expected is 200

actual:

StatusCode is 404

optional messages:

(log, picture, or anything else)

how to set resp body data to dininitions

/kind feature

What happened:
my test workflow:
1.user login return token
2.get the token for next request
my body struct :

{
    "success": true,
    "code": 0,
    "msg": "",
    "data": {
        "uid": 1000007,
        "login_name": "86:15810362016:3",
        "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NjgxMTYzNDEsImlzcyI6IkRpMjMwOXNsa2Q5OGE5OGFkaWFzZGxmMDlzZGdka2YyMWtqZ3Nka2YiLCJ1aWQiOjEwMDAwMDd9.VOLfK19uaRJuldeVPVe2wndpSZm1tpCxP65CRNUgyUk"
    }
}

What you expected to happen:
I want to set the token to definition.
how can i set ?

Call function in template should be refactor

Is this a BUG REPORT or FEATURE REQUEST?:

Uncomment only one, leave it on its own line:

/kind bug
/kind feature

What happened:

Call function in template is supported(e.g. ${ random(`regexp`) }) but the code is mess

What you expected to happen:

  1. move all internal functions into one dir
  2. support custom functions

How to reproduce it (as minimally and precisely as possible):

Anything else we need to know?:

change to go mod ?

Is this a BUG REPORT or FEATURE REQUEST?:

Uncomment only one, leave it on its own line:

/kind bug
/kind feature

What happened:

What you expected to happen:

How to reproduce it (as minimally and precisely as possible):

Anything else we need to know?:

match is no strict

when i list partition, this should be items, but follow testcases run successfully.

- description: "Try get partition eventually status"
  request:
    api: GET /api/v1/proxy/namespaces/default/services/tenant-admin:8080/apis/tenant.caicloud.io/v1alpha1/clusters/84984e39-57a7-4b8f-955e-127da0e46427/partitions
    headers:
      "Content-Type": "application/json"
    body: |
      {  
        "spec":{  
          "quota":{  
            "limits.cpu":"10m",
            "limits.memory":"10Mi",
            "requests.cpu":"10m",
            "requests.memory":"10Mi"
          },
          "tenant":"test-1234"
        },
        "status":{  
          "conditions":[  
            {  
              "status":"False",
              "type":"ExceedsQuota"
            }
          ],
          "hard":{
            "limits.cpu":"10m",
            "limits.memory":"180Mi",
            "requests.cpu":"10m",
            "requests.memory":"10Mi"
          },
          "phase":"Active",
          "used":{  
            "limits.cpu":"0",
            "limits.memory":"0",
            "requests.cpu":"0",
            "requests.memory":"0"
          }
        }
      }
  response:
    statusCode: 200
    eventually:
      timeout: "60s"
      interval: "1s"```

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.