123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351 |
- /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package base
- import (
- "context"
- "crypto/tls"
- "fmt"
- "io/ioutil"
- "net"
- "net/http"
- "os/exec"
- "strconv"
- "strings"
- "time"
- "github.com/gavv/httpexpect/v2"
- . "github.com/onsi/ginkgo/v2"
- "github.com/stretchr/testify/assert"
- "github.com/tidwall/gjson"
- )
- var (
- token string
- UpstreamIp = "upstream"
- UpstreamGrpcIp = "upstream_grpc"
- UpstreamHTTPBinIp = "upstream_httpbin"
- APISIXHost = "http://127.0.0.1:9080"
- APISIXAdminAPIHost = "http://127.0.0.1:9180"
- APISIXInternalUrl = "http://apisix:9080"
- APISIXSingleWorkerHost = "http://127.0.0.1:9081"
- ManagerAPIHost = "http://127.0.0.1:9000"
- PrometheusExporter = "http://127.0.0.1:9091"
- )
- func GetToken() string {
- if token != "" {
- return token
- }
- requestBody := `{
- "username": "admin",
- "password": "admin"
- }`
- url := ManagerAPIHost + "/apisix/admin/user/login"
- body, _, err := HttpPost(url, nil, requestBody)
- if err != nil {
- panic(err)
- }
- respond := gjson.ParseBytes(body)
- token = respond.Get("data.token").String()
- return token
- }
- func getTestingHandle() httpexpect.LoggerReporter {
- return GinkgoT()
- }
- func ManagerApiExpect() *httpexpect.Expect {
- return httpexpect.New(GinkgoT(), ManagerAPIHost)
- }
- func APISIXExpect() *httpexpect.Expect {
- return httpexpect.New(GinkgoT(), APISIXHost)
- }
- func APISIXAdminAPIExpect() *httpexpect.Expect {
- return httpexpect.New(GinkgoT(), APISIXAdminAPIHost)
- }
- func APISIXStreamProxyExpect(port uint16, sni string) *httpexpect.Expect {
- if port == 0 {
- port = 10090
- }
- if sni != "" {
- addr := net.JoinHostPort(sni, strconv.Itoa(int(port)))
- return httpexpect.WithConfig(httpexpect.Config{
- BaseURL: "https://" + addr,
- Reporter: httpexpect.NewAssertReporter(GinkgoT()),
- Client: &http.Client{
- Transport: &http.Transport{
- TLSClientConfig: &tls.Config{
- // accept any certificate; for testing only!
- InsecureSkipVerify: true,
- },
- DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
- addr = net.JoinHostPort("127.0.0.1", strconv.Itoa(int(port)))
- dialer := &net.Dialer{}
- return dialer.DialContext(ctx, network, addr)
- },
- },
- },
- })
- } else {
- return httpexpect.New(GinkgoT(), "http://"+net.JoinHostPort("127.0.0.1", strconv.Itoa(int(port))))
- }
- }
- func PrometheusExporterExpect() *httpexpect.Expect {
- return httpexpect.New(GinkgoT(), PrometheusExporter)
- }
- func APISIXHTTPSExpect() *httpexpect.Expect {
- e := httpexpect.WithConfig(httpexpect.Config{
- BaseURL: "https://www.test2.com:9443",
- Reporter: httpexpect.NewAssertReporter(GinkgoT()),
- Client: &http.Client{
- Transport: &http.Transport{
- TLSClientConfig: &tls.Config{
- // accept any certificate; for testing only!
- InsecureSkipVerify: true,
- },
- DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
- if addr == "www.test2.com:9443" {
- addr = "127.0.0.1:9443"
- }
- dialer := &net.Dialer{}
- return dialer.DialContext(ctx, network, addr)
- },
- },
- },
- })
- return e
- }
- var SleepTime = 300 * time.Millisecond
- type HttpTestCase struct {
- Desc string
- Object *httpexpect.Expect
- Method string
- Path string
- Query string
- Body string
- Headers map[string]string
- Headers_test map[string]interface{}
- ExpectStatus int
- ExpectCode int
- ExpectMessage string
- ExpectBody interface{}
- UnexpectBody interface{}
- ExpectHeaders map[string]string
- Sleep time.Duration //ms
- }
- func RunTestCase(tc HttpTestCase) {
- //init
- expectObj := tc.Object
- var req *httpexpect.Request
- switch tc.Method {
- case http.MethodGet:
- req = expectObj.GET(tc.Path)
- case http.MethodPut:
- req = expectObj.PUT(tc.Path)
- case http.MethodPost:
- req = expectObj.POST(tc.Path)
- case http.MethodDelete:
- req = expectObj.DELETE(tc.Path)
- case http.MethodPatch:
- req = expectObj.PATCH(tc.Path)
- case http.MethodOptions:
- req = expectObj.OPTIONS(tc.Path)
- default:
- }
- if req == nil {
- panic("fail to init request")
- }
- if tc.Sleep != 0 {
- time.Sleep(tc.Sleep)
- } else {
- time.Sleep(time.Duration(50) * time.Millisecond)
- }
- if tc.Query != "" {
- req.WithQueryString(tc.Query)
- }
- // set header
- setContentType := false
- for key, val := range tc.Headers {
- req.WithHeader(key, val)
- if strings.ToLower(key) == "content-type" {
- setContentType = true
- }
- }
- // set default content-type
- if !setContentType {
- req.WithHeader("Content-Type", "application/json")
- }
- // set body
- if tc.Body != "" {
- req.WithText(tc.Body)
- }
- // respond check
- resp := req.Expect()
- // match http status
- if tc.ExpectStatus != 0 {
- resp.Status(tc.ExpectStatus)
- }
- // match headers
- if tc.ExpectHeaders != nil {
- for key, val := range tc.ExpectHeaders {
- resp.Header(key).Equal(val)
- }
- }
- // match body
- if tc.ExpectBody != nil {
- //assert.Contains(t, []string{"string", "[]string"}, reflect.TypeOf(tc.ExpectBody).String())
- if body, ok := tc.ExpectBody.(string); ok {
- if body == "" {
- // "" indicates the body is expected to be empty
- resp.Body().Empty()
- } else {
- resp.Body().Contains(body)
- }
- } else if bodies, ok := tc.ExpectBody.([]string); ok && len(bodies) != 0 {
- for _, b := range bodies {
- resp.Body().Contains(b)
- }
- }
- }
- // match UnexpectBody
- if tc.UnexpectBody != nil {
- //assert.Contains(t, []string{"string", "[]string"}, reflect.TypeOf(tc.UnexpectBody).String())
- if body, ok := tc.UnexpectBody.(string); ok {
- // "" indicates the body is expected to be non empty
- if body == "" {
- resp.Body().NotEmpty()
- } else {
- resp.Body().NotContains(body)
- }
- } else if bodies, ok := tc.UnexpectBody.([]string); ok && len(bodies) != 0 {
- for _, b := range bodies {
- resp.Body().NotContains(b)
- }
- }
- }
- }
- func ReadAPISIXErrorLog() string {
- cmd := exec.Command("pwd")
- pwdByte, err := cmd.CombinedOutput()
- pwd := string(pwdByte)
- pwd = strings.Replace(pwd, "\n", "", 1)
- pwd = pwd[:strings.Index(pwd, "/e2e")]
- bytes, err := ioutil.ReadFile(pwd + "/docker/apisix_logs/error.log")
- assert.Nil(GinkgoT(), err)
- logContent := string(bytes)
- return logContent
- }
- func CleanAPISIXErrorLog() {
- cmd := exec.Command("pwd")
- pwdByte, err := cmd.CombinedOutput()
- pwd := string(pwdByte)
- pwd = strings.Replace(pwd, "\n", "", 1)
- pwd = pwd[:strings.Index(pwd, "/e2e")]
- cmdStr := "echo | sudo tee " + pwd + "/docker/apisix_logs/error.log"
- cmd = exec.Command("bash", "-c", cmdStr)
- _, err = cmd.Output()
- if err != nil {
- fmt.Println("cmd error:", err.Error())
- }
- assert.Nil(GinkgoT(), err)
- }
- func GetResourceList(resource string) string {
- body, _, err := HttpGet(ManagerAPIHost+"/apisix/admin/"+resource, map[string]string{"Authorization": GetToken()})
- assert.Nil(GinkgoT(), err)
- return string(body)
- }
- func CleanResource(resource string) {
- resources := GetResourceList(resource)
- list := gjson.Get(resources, "data.rows").Value().([]interface{})
- for _, item := range list {
- resourceObj := item.(map[string]interface{})
- tc := HttpTestCase{
- Desc: "delete " + resource + "/" + resourceObj["id"].(string),
- Object: ManagerApiExpect(),
- Method: http.MethodDelete,
- Path: "/apisix/admin/" + resource + "/" + resourceObj["id"].(string),
- Headers: map[string]string{"Authorization": GetToken()},
- }
- RunTestCase(tc)
- }
- time.Sleep(SleepTime)
- }
- func CleanAllResource() {
- CleanResource("routes")
- CleanResource("upstreams")
- CleanResource("consumers")
- CleanResource("services")
- CleanResource("global_rules")
- CleanResource("plugin_configs")
- CleanResource("proto")
- CleanResource("ssl")
- CleanResource("stream_routes")
- }
- func RestartManagerAPI() {
- e := exec.Command("docker", "restart", "docker_managerapi")
- e.Run()
- }
- var jwtToken string
- func GetJwtToken(userKey string) string {
- if jwtToken != "" {
- return jwtToken
- }
- time.Sleep(SleepTime)
- body, status, err := HttpGet(APISIXHost+"/apisix/plugin/jwt/sign?key="+userKey, nil)
- assert.Nil(GinkgoT(), err)
- assert.Equal(GinkgoT(), http.StatusOK, status)
- jwtToken = string(body)
- return jwtToken
- }
|