Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Only works for JSON API
## Dependencies

```bash
"github.com/bastianrob/go-valuator"
"github.com/robertkrimen/otto"
"github.com/buger/jsonparser"
```

Expand Down
20 changes: 10 additions & 10 deletions case.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package restify
import (
"regexp"

"github.com/bastianrob/go-restify/enum"
"github.com/SpaceStock/go-restify/enum"
)

var (
Expand All @@ -12,17 +12,17 @@ var (

//Pipeline test pipeline as what to do with the response object
type Pipeline struct {
Cache bool `json:"cache" bson:"cache"`
CacheAs string `json:"cache_as" bson:"cache_as"`
OnFailure enum.OnFailure `json:"on_failure" bson:"on_failure"`
Cache bool `json:"cache"`
CacheAs string `json:"cache_as"`
OnFailure enum.OnFailure `json:"on_failure"`
}

//TestCase struct
type TestCase struct {
Order uint `json:"order" bson:"order"`
Name string `json:"name" bson:"name"`
Description string `json:"description" bson:"description"`
Request Request `json:"request" bson:"request"`
Expect Expect `json:"expect" bson:"expect"`
Pipeline Pipeline `json:"pipeline" bson:"pipeline"`
Order uint `json:"order"`
Name string `json:"name"`
Description string `json:"description"`
Request Request `json:"request"`
Expect Expect `json:"expect"`
Pipeline Pipeline `json:"pipeline"`
}
2 changes: 1 addition & 1 deletion enum/onfailure/enum.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package onfailure

import "github.com/bastianrob/go-restify/enum"
import "github.com/SpaceStock/go-restify/enum"

//Enumeration constants
const (
Expand Down
48 changes: 21 additions & 27 deletions expect.go
Original file line number Diff line number Diff line change
@@ -1,35 +1,29 @@
package restify

import (
"encoding/json"
"strings"

"github.com/buger/jsonparser"
)

//Expect response expectation
type Expect struct {
StatusCode int `json:"status_code" bson:"status_code"`
Headers map[string]string `json:"headers" bson:"headers"`
Evaluate []Expression `json:"evaluate" bson:"evaluate"`
StatusCode int `json:"status_code"`
Headers map[string]string `json:"headers"`
Evaluate []Expression `json:"evaluate"`
}

//Parse cache into evaluation value
//This will replace {....} with existing value in cache
func (e *Expect) Parse(cache map[string]json.RawMessage) {
for i, exp := range e.Evaluate {
matches := replacable.FindAllStringSubmatch(exp.Value, -1)
for _, match := range matches {
param := match[0]
keys := strings.Split(match[1], ".")
cacheKey := keys[0]
cacheProps := keys[1:]
// TODO: NO LONGER NEEDED
// Parse cache into evaluation value
// This will replace {....} with existing value in cache
// func (e *Expect) Parse(cache map[string]json.RawMessage) {
// for i, exp := range e.Evaluate {
// matches := replacable.FindAllStringSubmatch(exp.Value, -1)
// for _, match := range matches {
// param := match[0]
// keys := strings.Split(match[1], ".")
// cacheKey := keys[0]
// cacheProps := keys[1:]

obj := cache[cacheKey]
strval, _ := jsonparser.GetString(obj, cacheProps...)
// obj := cache[cacheKey]
// strval, _ := jsonparser.GetString(obj, cacheProps...)

exp.Value = strings.Replace(exp.Value, param, strval, 1)
e.Evaluate[i] = exp
}
}
}
// exp.Value = strings.Replace(exp.Value, param, strval, 1)
// e.Evaluate[i] = exp
// }
// }
// }
33 changes: 27 additions & 6 deletions expression.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,31 @@
package restify

import (
"github.com/robertkrimen/otto"
)

//Expression rule of expected response
type Expression struct {
Object string `json:"object" bson:"object"`
Prop string `json:"prop" bson:"prop"`
Operator string `json:"operator" bson:"operator"`
Value string `json:"value" bson:"value"`
Description string `json:"description" bson:"description"`
type Expression string

// IsTrue evaluate given boolean expression whether it is true, or false
// Return false on invalid expression
func (expr Expression) IsTrue(input map[string]interface{}) bool {
jsvm := otto.New()
for key, val := range input {
jsvm.Set(key, val)
}

// jsvm.Set("res", input)
// jsvm.Run("res = JSON.parse(res)")
val, err := jsvm.Run(string(expr))
if err != nil {
return false
}

result, err := val.ToBoolean()
if err != nil {
return false
}

return result
}
49 changes: 49 additions & 0 deletions expression_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package restify

import (
"encoding/json"
"testing"
)

func TestExpression_IsTrue(t *testing.T) {
type args struct {
json string
pair map[string]interface{}
}
tests := []struct {
name string
expr Expression
args args
want bool
}{{
name: "Simple positive case 1",
args: args{json: `{"name": "Mr. Brother"}`}, //We receive this from API call
expr: Expression(`name === "Mr. Brother"`), //We want to test the response with this expression
want: true, //Given such response, against the expr rule, we want the expression result to be true
}, {
name: "Simple positive case 2",
args: args{json: `{"age": 10}`},
expr: Expression(`age >= 10`),
want: true,
}, {
name: "Composite positive case 3",
args: args{json: `{"name": "John", "age": 10}`},
expr: Expression(`name === "John" && age >= 10`),
want: true,
}, {
name: "Complex object positive case 3",
args: args{json: `{"person": {"name": "John", "age": 10} }`},
expr: Expression(`person.name === "John" && person.age >= 10`),
want: true,
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
pair := map[string]interface{}{}
json.Unmarshal([]byte(tt.args.json), &pair)

if got := tt.expr.IsTrue(pair); got != tt.want {
t.Errorf("Expression.IsTrue() = %v, want %v", got, tt.want)
}
})
}
}
8 changes: 4 additions & 4 deletions request.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import (

//Request test object
type Request struct {
URL string `json:"url" bson:"url"`
Method string `json:"method" bson:"method"`
Headers map[string]string `json:"headers" bson:"headers"`
Payload map[string]interface{} `json:"payload" bson:"payload"`
URL string `json:"url"`
Method string `json:"method"`
Headers map[string]string `json:"headers"`
Payload map[string]interface{} `json:"payload"`
}

func recursiveMapParser(obj map[string]interface{}, cache map[string]json.RawMessage) map[string]interface{} {
Expand Down
31 changes: 16 additions & 15 deletions result.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,25 @@ import "time"
//Hopefully de-normalizing the structure can make analytic easier
//Generally immutable, so we don't need ID and just let DB auto gen for us
type TestResult struct {
Timestamp int64 `json:"timestamp" bson:"timestamp"`
ScenarioName string `json:"scenario_name" bson:"scenario_name"`
TestCaseOrder int `json:"test_case_order" bson:"test_case_order"`
TestCaseName string `json:"test_case_name" bson:"test_case_name"`
RequestMethod string `json:"request_method" bson:"request_method"`
RequestURL string `json:"request_url" bson:"request_url"`
Timestamp int64 `json:"timestamp"`
ScenarioName string `json:"scenario_name"`
TestCaseOrder int `json:"test_case_order"`
TestCaseName string `json:"test_case_name"`
RequestMethod string `json:"request_method"`
RequestURL string `json:"request_url"`
//RequestPayload?
ResponseCode int `json:"response_code" bson:"response_code"`
ResponseSize int64 `json:"response_size" bson:"response_size"`
ResponseCode int `json:"response_code"`
ResponseSize int64 `json:"response_size"`
//Response timing
TimingDNS time.Duration `json:"timing_dns" bson:"timing_dns"`
TimingHandshake time.Duration `json:"timing_handshake" bson:"timing_handshake"`
TimingConnected time.Duration `json:"timing_connected" bson:"timing_connected"`
TimingFirstByte time.Duration `json:"timing_first_byte" bson:"timing_first_byte"`
TimingTotal time.Duration `json:"timing_total" bson:"timing_total"`
TimingDNS time.Duration `json:"timing_dns"`
TimingHandshake time.Duration `json:"timing_handshake"`
TimingConnected time.Duration `json:"timing_connected"`
TimingFirstByte time.Duration `json:"timing_first_byte"`
TimingTotal time.Duration `json:"timing_total"`
//ResponsePayload?
ExpectedCode int `json:"expected_code" bson:"expected_code"`
Message string `json:"message" bson:"message"`
Success bool `json:"success"`
ExpectedCode int `json:"expected_code"`
Message string `json:"message"`
}

//NewTestResult from scenario
Expand Down
Loading