From 6711cd7111a33d5a3bf641c30a553822b0dd36b9 Mon Sep 17 00:00:00 2001 From: Robin Bastian Date: Wed, 15 Jan 2020 11:43:52 +0700 Subject: [PATCH 1/7] Remove evaluator, bson, and bastianrob reference --- case.go | 20 +++---- enum/onfailure/enum.go | 2 +- expect.go | 6 +- expression.go | 10 ++-- request.go | 8 +-- result.go | 31 +++++----- scenario/scenario.go | 110 ++---------------------------------- scenario/scenario_getter.go | 2 +- scenario/scenario_setter.go | 2 +- 9 files changed, 45 insertions(+), 146 deletions(-) diff --git a/case.go b/case.go index 6d3aaf5..95b6f99 100644 --- a/case.go +++ b/case.go @@ -3,7 +3,7 @@ package restify import ( "regexp" - "github.com/bastianrob/go-restify/enum" + "github.com/Spacestock/go-restify/enum" ) var ( @@ -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"` } diff --git a/enum/onfailure/enum.go b/enum/onfailure/enum.go index 5b5558a..9e5cbbc 100644 --- a/enum/onfailure/enum.go +++ b/enum/onfailure/enum.go @@ -1,6 +1,6 @@ package onfailure -import "github.com/bastianrob/go-restify/enum" +import "github.com/Spacestock/go-restify/enum" //Enumeration constants const ( diff --git a/expect.go b/expect.go index fb6059c..c7f84cc 100644 --- a/expect.go +++ b/expect.go @@ -9,9 +9,9 @@ import ( //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 diff --git a/expression.go b/expression.go index 8d72955..969d86b 100644 --- a/expression.go +++ b/expression.go @@ -2,9 +2,9 @@ package restify //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"` + Object string `json:"object"` + Prop string `json:"prop"` + Operator string `json:"operator"` + Value string `json:"value"` + Description string `json:"description"` } diff --git a/request.go b/request.go index dd85b06..1ae320a 100644 --- a/request.go +++ b/request.go @@ -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{} { diff --git a/result.go b/result.go index 8293f23..f08e3af 100644 --- a/result.go +++ b/result.go @@ -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 diff --git a/scenario/scenario.go b/scenario/scenario.go index b673933..98e65f3 100644 --- a/scenario/scenario.go +++ b/scenario/scenario.go @@ -9,15 +9,10 @@ import ( "io/ioutil" "net/http" "net/http/httptrace" - "strings" "time" - "github.com/buger/jsonparser" - "go.mongodb.org/mongo-driver/bson" - - restify "github.com/bastianrob/go-restify" - "github.com/bastianrob/go-restify/enum/onfailure" - valuator "github.com/bastianrob/go-valuator" + restify "github.com/Spacestock/go-restify" + "github.com/Spacestock/go-restify/enum/onfailure" ) //implementation of restify.Scenario @@ -94,44 +89,6 @@ func (s *scenario) UnmarshalJSON(data []byte) error { return nil } -func (s *scenario) MarshalBSON() ([]byte, error) { - return bson.Marshal(struct { - ID string `bson:"_id"` - Name string `bson:"name"` - Description string `bson:"description"` - Environment string `bson:"environment"` - Cases []restify.TestCase `bson:"cases"` - }{ - ID: s.id, - Name: s.name, - Description: s.description, - Environment: s.environment, - Cases: s.cases, - }) -} - -func (s *scenario) UnmarshalBSON(data []byte) error { - alias := struct { - ID string `bson:"_id"` - Name string `bson:"name"` - Description string `bson:"description"` - Environment string `bson:"environment"` - Cases []restify.TestCase `bson:"cases"` - }{} - - err := bson.Unmarshal(data, &alias) - if err != nil { - return err - } - - s.id = alias.ID - s.name = alias.Name - s.description = alias.Description - s.environment = alias.Environment - s.cases = alias.Cases - return nil -} - //TODO: UGLY AF CODE! TOO EFFIN FAT! NEED TO REFACTOR! func (s *scenario) Run(w io.Writer) []restify.TestResult { io.WriteString(w, fmt.Sprintf( @@ -271,67 +228,7 @@ func (s *scenario) Run(w io.Writer) []restify.TestResult { continue } - //evaluate every rule - valid := true - invalidMsg := "" - for ri, rule := range tc.Expect.Evaluate { - eval, err := valuator.NewValuator(rule.Prop, rule.Operator, rule.Value, rule.Description) - if err != nil && tc.Pipeline.OnFailure == onfailure.Exit { - msg := fmt.Sprintf("%d.%d. Failed to get evaluator: %s\r\n", (i + 1), (ri + 1), err.Error()) - io.WriteString(w, msg) - - tr.Message = msg - testResults = append(testResults, tr) - return testResults - } else if err != nil { - msg := fmt.Sprintf("%d.%d. Failed to get evaluator: %s\r\n", (i + 1), (ri + 1), err.Error()) - io.WriteString(w, msg) - - tr.Message = msg - testResults = append(testResults, tr) - continue - } - - obj := make(map[string]interface{}) - { //parse response body into map and take the evaluation object - if rule.Object == "" { - err = json.Unmarshal(body, &obj) - } else { - paths := strings.Split(rule.Object, ".") - val, _, _, _ := jsonparser.Get(body, paths...) - err = json.Unmarshal(val, &obj) - } - - if err != nil && tc.Pipeline.OnFailure == onfailure.Exit { - msg := fmt.Sprintf("%d. Failed to parse response body into map: %s\r\n", (i + 1), err.Error()) - io.WriteString(w, msg) - - tr.Message = msg - testResults = append(testResults, tr) - return testResults - } else if err != nil { - msg := fmt.Sprintf("%d. Failed to parse response body into map: %s\r\n", (i + 1), err.Error()) - io.WriteString(w, msg) - - tr.Message = msg - testResults = append(testResults, tr) - continue - } - } - - valid = eval.Evaluate(obj) - if !valid { - invalidMsg = fmt.Sprintf("%d.%d. Expectation failed against rule=%+v\r\n", (i + 1), (ri + 1), rule) - io.WriteString(w, invalidMsg) - break - } - } - - if !valid && tc.Pipeline.OnFailure == onfailure.Exit { - tr.Message = invalidMsg - testResults = append(testResults, tr) - return testResults - } + //TODO: Evaluate every rule //cache if needed if tc.Pipeline.Cache { @@ -341,6 +238,7 @@ func (s *scenario) Run(w io.Writer) []restify.TestResult { msg := fmt.Sprintf("%d. Success\r\n", (i + 1)) io.WriteString(w, msg) + tr.Success = true tr.Message = msg testResults = append(testResults, tr) } diff --git a/scenario/scenario_getter.go b/scenario/scenario_getter.go index 29a77f5..bea9e0e 100644 --- a/scenario/scenario_getter.go +++ b/scenario/scenario_getter.go @@ -1,6 +1,6 @@ package scenario -import restify "github.com/bastianrob/go-restify" +import restify "github.com/Spacestock/go-restify" type getter struct { scenario *scenario diff --git a/scenario/scenario_setter.go b/scenario/scenario_setter.go index 359e104..eb55335 100644 --- a/scenario/scenario_setter.go +++ b/scenario/scenario_setter.go @@ -3,7 +3,7 @@ package scenario import ( "sort" - restify "github.com/bastianrob/go-restify" + restify "github.com/Spacestock/go-restify" ) type setter struct { From 62e3a3bdc8c98e6f1a7495226b4fd5b7a0a69701 Mon Sep 17 00:00:00 2001 From: Robin Bastian Date: Wed, 15 Jan 2020 15:54:03 +0700 Subject: [PATCH 2/7] Fix case sensitive reference to SpaceStock repo --- case.go | 2 +- enum/onfailure/enum.go | 2 +- scenario/scenario.go | 4 ++-- scenario/scenario_getter.go | 2 +- scenario/scenario_setter.go | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/case.go b/case.go index 95b6f99..55133d2 100644 --- a/case.go +++ b/case.go @@ -3,7 +3,7 @@ package restify import ( "regexp" - "github.com/Spacestock/go-restify/enum" + "github.com/SpaceStock/go-restify/enum" ) var ( diff --git a/enum/onfailure/enum.go b/enum/onfailure/enum.go index 9e5cbbc..d4f83e3 100644 --- a/enum/onfailure/enum.go +++ b/enum/onfailure/enum.go @@ -1,6 +1,6 @@ package onfailure -import "github.com/Spacestock/go-restify/enum" +import "github.com/SpaceStock/go-restify/enum" //Enumeration constants const ( diff --git a/scenario/scenario.go b/scenario/scenario.go index 98e65f3..07ea4fc 100644 --- a/scenario/scenario.go +++ b/scenario/scenario.go @@ -11,8 +11,8 @@ import ( "net/http/httptrace" "time" - restify "github.com/Spacestock/go-restify" - "github.com/Spacestock/go-restify/enum/onfailure" + restify "github.com/SpaceStock/go-restify" + "github.com/SpaceStock/go-restify/enum/onfailure" ) //implementation of restify.Scenario diff --git a/scenario/scenario_getter.go b/scenario/scenario_getter.go index bea9e0e..10841e4 100644 --- a/scenario/scenario_getter.go +++ b/scenario/scenario_getter.go @@ -1,6 +1,6 @@ package scenario -import restify "github.com/Spacestock/go-restify" +import restify "github.com/SpaceStock/go-restify" type getter struct { scenario *scenario diff --git a/scenario/scenario_setter.go b/scenario/scenario_setter.go index eb55335..8aec38c 100644 --- a/scenario/scenario_setter.go +++ b/scenario/scenario_setter.go @@ -3,7 +3,7 @@ package scenario import ( "sort" - restify "github.com/Spacestock/go-restify" + restify "github.com/SpaceStock/go-restify" ) type setter struct { From 807c33ceb79d769c0893c7b8780cb80ea1c93d38 Mon Sep 17 00:00:00 2001 From: Robin Bastian Date: Mon, 20 Jan 2020 13:01:04 +0700 Subject: [PATCH 3/7] Use JS interpreter to evaluate boolean expression --- README.md | 2 +- expect.go | 42 +++++++++++++++++---------------------- expression.go | 33 +++++++++++++++++++++++++------ expression_test.go | 49 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 31 deletions(-) create mode 100644 expression_test.go diff --git a/README.md b/README.md index c5083a3..d6bb9b4 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Only works for JSON API ## Dependencies ```bash -"github.com/bastianrob/go-valuator" +"github.com/robertkrimen/otto" "github.com/buger/jsonparser" ``` diff --git a/expect.go b/expect.go index c7f84cc..a27a07b 100644 --- a/expect.go +++ b/expect.go @@ -1,12 +1,5 @@ package restify -import ( - "encoding/json" - "strings" - - "github.com/buger/jsonparser" -) - //Expect response expectation type Expect struct { StatusCode int `json:"status_code"` @@ -14,22 +7,23 @@ type Expect struct { 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 +// } +// } +// } diff --git a/expression.go b/expression.go index 969d86b..4e2913b 100644 --- a/expression.go +++ b/expression.go @@ -1,10 +1,31 @@ package restify +import ( + "github.com/robertkrimen/otto" +) + //Expression rule of expected response -type Expression struct { - Object string `json:"object"` - Prop string `json:"prop"` - Operator string `json:"operator"` - Value string `json:"value"` - Description string `json:"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 } diff --git a/expression_test.go b/expression_test.go new file mode 100644 index 0000000..f4d62a6 --- /dev/null +++ b/expression_test.go @@ -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) + } + }) + } +} From 97abf0409430f90b566f28df7e5582cee1685b5c Mon Sep 17 00:00:00 2001 From: hugoiman Date: Wed, 22 Jan 2020 10:45:45 +0700 Subject: [PATCH 4/7] add evaluate every rule --- scenario/scenario.go | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/scenario/scenario.go b/scenario/scenario.go index 07ea4fc..6659f91 100644 --- a/scenario/scenario.go +++ b/scenario/scenario.go @@ -97,6 +97,8 @@ func (s *scenario) Run(w io.Writer) []restify.TestResult { testResults := []restify.TestResult{} httpClient := http.Client{} + + loop: for i, tc := range s.cases { io.WriteString(w, fmt.Sprintf( "%d. Test case: name=%s desc=%s onfail=%s\r\n", @@ -228,7 +230,38 @@ func (s *scenario) Run(w io.Writer) []restify.TestResult { continue } - //TODO: Evaluate every rule + // TODO: Evaluate every rule + pair := map[string]interface{} + json.Unmarshal(body, &pair) // convert []byte to map[string]interface{} + + for _, expr := range tc.Expect.Evaluate { // foreach rule in evaluate + isValid := expr.IsTrue(pair) + if !isValid && expr.Pipeline.OnFailure == onfailure.Exit { + msg := fmt.Sprintf("%d. Expression Failed : Status %t\r\n", (i + 1), isValid) + io.WriteString(w, msg) + + tr.Message = msg + testResults = append(testResults, tr) + + return testResults + } else if !isValid { + msg := fmt.Sprintf("%d. Expression Failed : Status %t\r\n", (i + 1), isValid) + io.WriteString(w, msg) + + tr.Message = msg + testResults = append(testResults, tr) + + continue loop + } else { + msg := fmt.Sprintf("%d. Expression Success: Status %t\r\n", (i + 1), isValid) + io.WriteString(w, msg) + + tr.Message = msg + testResults = append(testResults, tr) + + continue loop + } + } //cache if needed if tc.Pipeline.Cache { From db70c06f33c5ae1c67ef28ec093f07b6a1ff8a59 Mon Sep 17 00:00:00 2001 From: hugoiman Date: Mon, 27 Jan 2020 13:50:06 +0700 Subject: [PATCH 5/7] Test Expression --- scenario/scenario.go | 8 +- scenario_test/scenario_test.go | 155 +++++++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+), 4 deletions(-) create mode 100644 scenario_test/scenario_test.go diff --git a/scenario/scenario.go b/scenario/scenario.go index 6659f91..a4a8784 100644 --- a/scenario/scenario.go +++ b/scenario/scenario.go @@ -108,7 +108,7 @@ func (s *scenario) Run(w io.Writer) []restify.TestResult { //Parse any cache needed tc.Request.Parse(s.cache) - tc.Expect.Parse(s.cache) + // tc.Expect.Parse(s.cache) payload, _ := json.Marshal(tc.Request.Payload) //Setup HTTP request @@ -231,12 +231,12 @@ func (s *scenario) Run(w io.Writer) []restify.TestResult { } // TODO: Evaluate every rule - pair := map[string]interface{} + var pair map[string]interface{} json.Unmarshal(body, &pair) // convert []byte to map[string]interface{} for _, expr := range tc.Expect.Evaluate { // foreach rule in evaluate isValid := expr.IsTrue(pair) - if !isValid && expr.Pipeline.OnFailure == onfailure.Exit { + if !isValid && tc.Pipeline.OnFailure == onfailure.Exit { msg := fmt.Sprintf("%d. Expression Failed : Status %t\r\n", (i + 1), isValid) io.WriteString(w, msg) @@ -259,7 +259,7 @@ func (s *scenario) Run(w io.Writer) []restify.TestResult { tr.Message = msg testResults = append(testResults, tr) - continue loop + continue } } diff --git a/scenario_test/scenario_test.go b/scenario_test/scenario_test.go new file mode 100644 index 0000000..c0a3a5a --- /dev/null +++ b/scenario_test/scenario_test.go @@ -0,0 +1,155 @@ +package restify + +import ( + "os" + "testing" + + restify "github.com/SpaceStock/go-restify" + "github.com/SpaceStock/go-restify/enum/onfailure" + "github.com/SpaceStock/go-restify/scenario" +) + +func Test_Scenario(t *testing.T) { + scn := scenario.New() + results := scn. + Set().ID("").Name("Complex Testing"). + AddCase(restify.TestCase{ + Order: 1, + Name: "Firebase Auth", + Description: "", + Request: restify.Request{ + URL: "https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key=AIzaSyD-HHHsWb82AFmdXtm0t86Nb9uoMJutrU0", + Method: "POST", + Payload: map[string]interface{}{ + "email": "superadmin@spacestock.com", + "password": "admin@123", + "returnSecureToken": true, + }, + }, + Expect: restify.Expect{ + StatusCode: 200, + Evaluate: []restify.Expression{ + "idToken != ''", + }, + }, + Pipeline: restify.Pipeline{ + Cache: true, + CacheAs: "auth", + OnFailure: onfailure.Exit, + }, + }). + AddCase(restify.TestCase{ + Order: 2, + Name: "Get Complex Apartment", + Description: "", + Request: restify.Request{ + URL: "https://stg-satpam.spacestock.com/1.0/complex/apartment?page=1&size=1", + Method: "GET", + Headers: map[string]string{ + "Authorization": "Bearer {auth.idToken}", + }, + Payload: nil, + }, + Expect: restify.Expect{ + StatusCode: 200, + Evaluate: []restify.Expression{}, + }, + Pipeline: restify.Pipeline{ + Cache: true, + CacheAs: "list", + OnFailure: onfailure.Exit, + }, + }). + AddCase(restify.TestCase{ + Order: 3, + Name: "Get One Apartment", + Description: "", + Request: restify.Request{ + URL: "https://stg-satpam.spacestock.com/1.0/complex/apartment/{list.data.[0].id}", + Method: "GET", + Headers: map[string]string{ + "Authorization": "Bearer {auth.idToken}", + }, + Payload: nil, + }, + Expect: restify.Expect{ + StatusCode: 200, + Evaluate: []restify.Expression{ + "id === '{list.data.[0.id]}'", + }, + }, + Pipeline: restify.Pipeline{ + Cache: true, + CacheAs: "oneApt", + OnFailure: onfailure.Exit, + }, + }). + AddCase(restify.TestCase{ + Order: 4, + Name: "Create Apartment", + Description: "", + Request: restify.Request{ + URL: "https://stg-satpam.spacestock.com/1.0/complex/apartment", + Method: "POST", + Headers: map[string]string{ + "Authorization": "Bearer {auth.idToken}", + }, + Payload: nil, + }, + Expect: restify.Expect{ + StatusCode: 201, + Evaluate: []restify.Expression{}, + }, + Pipeline: restify.Pipeline{ + Cache: false, + CacheAs: "aptOne", + OnFailure: onfailure.Exit, + }, + }).End(). + Run(os.Stdout) + + if len(results) <= 0 { + t.Error("No result returned") + } + + if results[0].Success { + t.Error("This case should have failed") + } +} + +func Test_Scenario2(t *testing.T) { + scn := scenario.New() + results := scn. + Set().ID("").Name("Scenario 2"). + AddCase(restify.TestCase{ + Order: 1, + Name: "Test Case 1", + Description: "", + Request: restify.Request{ + URL: "http://jsonplaceholder.typicode.com/posts/1", + Method: "GET", + Payload: nil, + }, + Expect: restify.Expect{ + StatusCode: 200, + Evaluate: []restify.Expression{ + "userId && userId === 5", + "id && id === 6", + }, + }, + Pipeline: restify.Pipeline{ + Cache: true, + CacheAs: "tc1", + OnFailure: onfailure.Exit, + }, + }).End(). + Run(os.Stdout) + + if len(results) <= 0 { + t.Error("No result returned") + } + + if results[0].Success { + t.Error("This case should have failed") + } +} From 623149abc23f8a2ab6aa517219623d9f1c322ad0 Mon Sep 17 00:00:00 2001 From: hugoiman Date: Tue, 28 Jan 2020 11:43:39 +0700 Subject: [PATCH 6/7] Test Expression 2 --- scenario/scenario.go | 9 +-- scenario_test/scenario_test.go | 115 ++++++++++++++++++++++++++++++--- 2 files changed, 110 insertions(+), 14 deletions(-) diff --git a/scenario/scenario.go b/scenario/scenario.go index a4a8784..7f13e78 100644 --- a/scenario/scenario.go +++ b/scenario/scenario.go @@ -98,7 +98,7 @@ func (s *scenario) Run(w io.Writer) []restify.TestResult { testResults := []restify.TestResult{} httpClient := http.Client{} - loop: +loop: for i, tc := range s.cases { io.WriteString(w, fmt.Sprintf( "%d. Test case: name=%s desc=%s onfail=%s\r\n", @@ -232,9 +232,9 @@ func (s *scenario) Run(w io.Writer) []restify.TestResult { // TODO: Evaluate every rule var pair map[string]interface{} - json.Unmarshal(body, &pair) // convert []byte to map[string]interface{} + json.Unmarshal(body, &pair) // convert []byte to map[string]interface{} - for _, expr := range tc.Expect.Evaluate { // foreach rule in evaluate + for _, expr := range tc.Expect.Evaluate { // foreach rule in evaluate isValid := expr.IsTrue(pair) if !isValid && tc.Pipeline.OnFailure == onfailure.Exit { msg := fmt.Sprintf("%d. Expression Failed : Status %t\r\n", (i + 1), isValid) @@ -256,9 +256,6 @@ func (s *scenario) Run(w io.Writer) []restify.TestResult { msg := fmt.Sprintf("%d. Expression Success: Status %t\r\n", (i + 1), isValid) io.WriteString(w, msg) - tr.Message = msg - testResults = append(testResults, tr) - continue } } diff --git a/scenario_test/scenario_test.go b/scenario_test/scenario_test.go index c0a3a5a..3e60ea1 100644 --- a/scenario_test/scenario_test.go +++ b/scenario_test/scenario_test.go @@ -7,6 +7,7 @@ import ( restify "github.com/SpaceStock/go-restify" "github.com/SpaceStock/go-restify/enum/onfailure" "github.com/SpaceStock/go-restify/scenario" + "github.com/stretchr/testify/assert" ) func Test_Scenario(t *testing.T) { @@ -117,6 +118,7 @@ func Test_Scenario(t *testing.T) { } } +// Data True func Test_Scenario2(t *testing.T) { scn := scenario.New() results := scn. @@ -133,8 +135,7 @@ func Test_Scenario2(t *testing.T) { Expect: restify.Expect{ StatusCode: 200, Evaluate: []restify.Expression{ - "userId && userId === 5", - "id && id === 6", + "userId && userId === 1", }, }, Pipeline: restify.Pipeline{ @@ -142,14 +143,112 @@ func Test_Scenario2(t *testing.T) { CacheAs: "tc1", OnFailure: onfailure.Exit, }, + }). + AddCase(restify.TestCase{ + Order: 2, + Name: "Test Case 2", + Description: "", + Request: restify.Request{ + URL: "http://jsonplaceholder.typicode.com/posts/2", + Method: "GET", + Payload: nil, + }, + Expect: restify.Expect{ + StatusCode: 200, + Evaluate: []restify.Expression{ + "userId && userId === 1", + "id && id === 2", + }, + }, + Pipeline: restify.Pipeline{ + Cache: true, + CacheAs: "tc2", + OnFailure: onfailure.Exit, + }, }).End(). Run(os.Stdout) - if len(results) <= 0 { - t.Error("No result returned") - } + assert.NotEqual(t, 0, len(results), "Seharusnya bukan 0") + assert.True(t, results[0].Success) + assert.True(t, results[1].Success) +} - if results[0].Success { - t.Error("This case should have failed") - } +// Data False +func Test_Scenario3(t *testing.T) { + scn := scenario.New() + results := scn. + Set().ID("").Name("Scenario 3"). + AddCase(restify.TestCase{ + Order: 1, + Name: "Test Case 1", + Description: "", + Request: restify.Request{ + URL: "http://jsonplaceholder.typicode.com/posts/1", + Method: "GET", + Payload: nil, + }, + Expect: restify.Expect{ + StatusCode: 200, + Evaluate: []restify.Expression{ + "userId && userId === 1", + "id && id === 1", + }, + }, + Pipeline: restify.Pipeline{ + Cache: true, + CacheAs: "tc1", + OnFailure: onfailure.Exit, + }, + }). + AddCase(restify.TestCase{ + Order: 2, + Name: "Test Case 2", + Description: "", + Request: restify.Request{ + URL: "http://jsonplaceholder.typicode.com/posts/2", + Method: "GET", + Payload: nil, + }, + Expect: restify.Expect{ + StatusCode: 200, + Evaluate: []restify.Expression{ + "userId && userId === 1", + "id && id === 2", + }, + }, + Pipeline: restify.Pipeline{ + Cache: true, + CacheAs: "tc2", + OnFailure: onfailure.Exit, + }, + }). + AddCase(restify.TestCase{ + Order: 3, + Name: "Test Case 3", + Description: "", + Request: restify.Request{ + URL: "http://jsonplaceholder.typicode.com/posts/3", + Method: "GET", + Payload: nil, + }, + Expect: restify.Expect{ + StatusCode: 200, + Evaluate: []restify.Expression{ + "userId && userId === 1", + "id && id === 1", // False + }, + }, + Pipeline: restify.Pipeline{ + Cache: true, + CacheAs: "tc3", + OnFailure: onfailure.Exit, + }, + }).End(). + Run(os.Stdout) + + assert.NotEqual(t, 0, len(results), "Seharusnya bukan 0") + + assert.True(t, results[0].Success) + assert.True(t, results[1].Success) + assert.False(t, results[2].Success) } From 95866f5acaaaa5eb6722f08ce074826888aeaaa6 Mon Sep 17 00:00:00 2001 From: hugoiman Date: Tue, 28 Jan 2020 15:39:24 +0700 Subject: [PATCH 7/7] Unit Test Baru --- scenario_test/scenario_test.go | 117 ++++++++++++++++++++++++++++++--- 1 file changed, 109 insertions(+), 8 deletions(-) diff --git a/scenario_test/scenario_test.go b/scenario_test/scenario_test.go index 3e60ea1..efeb4f8 100644 --- a/scenario_test/scenario_test.go +++ b/scenario_test/scenario_test.go @@ -136,6 +136,7 @@ func Test_Scenario2(t *testing.T) { StatusCode: 200, Evaluate: []restify.Expression{ "userId && userId === 1", + "id && id === 1", }, }, Pipeline: restify.Pipeline{ @@ -157,7 +158,7 @@ func Test_Scenario2(t *testing.T) { StatusCode: 200, Evaluate: []restify.Expression{ "userId && userId === 1", - "id && id === 2", + "id && id === 2", // False }, }, Pipeline: restify.Pipeline{ @@ -165,6 +166,28 @@ func Test_Scenario2(t *testing.T) { CacheAs: "tc2", OnFailure: onfailure.Exit, }, + }). + AddCase(restify.TestCase{ + Order: 3, + Name: "Test Case 3", + Description: "", + Request: restify.Request{ + URL: "http://jsonplaceholder.typicode.com/posts/3", + Method: "GET", + Payload: nil, + }, + Expect: restify.Expect{ + StatusCode: 200, + Evaluate: []restify.Expression{ + "userId && userId === 1", + "id && id === 3", + }, + }, + Pipeline: restify.Pipeline{ + Cache: true, + CacheAs: "tc1", + OnFailure: onfailure.Exit, + }, }).End(). Run(os.Stdout) @@ -173,11 +196,11 @@ func Test_Scenario2(t *testing.T) { assert.True(t, results[1].Success) } -// Data False +// Pipeline.OnFailure=Exit func Test_Scenario3(t *testing.T) { scn := scenario.New() results := scn. - Set().ID("").Name("Scenario 3"). + Set().ID("").Name("Scenario 2"). AddCase(restify.TestCase{ Order: 1, Name: "Test Case 1", @@ -213,7 +236,7 @@ func Test_Scenario3(t *testing.T) { StatusCode: 200, Evaluate: []restify.Expression{ "userId && userId === 1", - "id && id === 2", + "id && id === 3", // False }, }, Pipeline: restify.Pipeline{ @@ -235,7 +258,7 @@ func Test_Scenario3(t *testing.T) { StatusCode: 200, Evaluate: []restify.Expression{ "userId && userId === 1", - "id && id === 1", // False + "id && id === 3", }, }, Pipeline: restify.Pipeline{ @@ -246,9 +269,87 @@ func Test_Scenario3(t *testing.T) { }).End(). Run(os.Stdout) - assert.NotEqual(t, 0, len(results), "Seharusnya bukan 0") + assert.Equal(t, 2, len(results), "Test Case = 2") + assert.True(t, results[0].Success) + assert.False(t, results[1].Success) +} + +// Pipeline.OnFailure=Fallthrough +func Test_Scenario4(t *testing.T) { + scn := scenario.New() + results := scn. + Set().ID("").Name("Scenario 3"). + AddCase(restify.TestCase{ + Order: 1, + Name: "Test Case 1", + Description: "", + Request: restify.Request{ + URL: "http://jsonplaceholder.typicode.com/posts/1", + Method: "GET", + Payload: nil, + }, + Expect: restify.Expect{ + StatusCode: 200, + Evaluate: []restify.Expression{ + "userId && userId === 1", + "id && id === 1", + }, + }, + Pipeline: restify.Pipeline{ + Cache: true, + CacheAs: "tc1", + OnFailure: onfailure.Exit, + }, + }). + AddCase(restify.TestCase{ + Order: 2, + Name: "Test Case 2", + Description: "", + Request: restify.Request{ + URL: "http://jsonplaceholder.typicode.com/posts/2", + Method: "GET", + Payload: nil, + }, + Expect: restify.Expect{ + StatusCode: 200, + Evaluate: []restify.Expression{ + "userId && userId === 1", + "id && id === 1", // False + }, + }, + Pipeline: restify.Pipeline{ + Cache: true, + CacheAs: "tc2", + OnFailure: onfailure.Fallthrough, + }, + }). + AddCase(restify.TestCase{ + Order: 3, + Name: "Test Case 3", + Description: "", + Request: restify.Request{ + URL: "http://jsonplaceholder.typicode.com/posts/3", + Method: "GET", + Payload: nil, + }, + Expect: restify.Expect{ + StatusCode: 200, + Evaluate: []restify.Expression{ + "userId && userId === 1", + "id && id === 3", + }, + }, + Pipeline: restify.Pipeline{ + Cache: true, + CacheAs: "tc3", + OnFailure: onfailure.Exit, + }, + }).End(). + Run(os.Stdout) + + assert.Equal(t, 3, len(results), "Test Case = 3") assert.True(t, results[0].Success) - assert.True(t, results[1].Success) - assert.False(t, results[2].Success) + assert.False(t, results[1].Success) + assert.True(t, results[2].Success) }