From f2d1820662a567341b359125cf746e7bc337b725 Mon Sep 17 00:00:00 2001 From: levy liu Date: Wed, 10 May 2023 15:32:46 +0800 Subject: [PATCH] feat: disable route export openapi func --- .../handler/data_loader/route_export.go | 511 ---- .../handler/data_loader/route_export_test.go | 2405 ---------------- api/internal/route.go | 1 - api/test/e2e/route/route_export_test.go | 2543 ----------------- docs/en/latest/api/api.md | 19 - 5 files changed, 5479 deletions(-) delete mode 100644 api/internal/handler/data_loader/route_export.go delete mode 100644 api/internal/handler/data_loader/route_export_test.go delete mode 100644 api/test/e2e/route/route_export_test.go diff --git a/api/internal/handler/data_loader/route_export.go b/api/internal/handler/data_loader/route_export.go deleted file mode 100644 index a61d5d1ed5..0000000000 --- a/api/internal/handler/data_loader/route_export.go +++ /dev/null @@ -1,511 +0,0 @@ -/* - * 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 data_loader - -import ( - "encoding/json" - "fmt" - "net/http" - "reflect" - "strconv" - "strings" - - "github.com/getkin/kin-openapi/openapi3" - "github.com/gin-gonic/gin" - "github.com/shiningrush/droplet" - "github.com/shiningrush/droplet/data" - "github.com/shiningrush/droplet/wrapper" - wgin "github.com/shiningrush/droplet/wrapper/gin" - - "github.com/apisix/manager-api/internal/core/entity" - "github.com/apisix/manager-api/internal/core/store" - "github.com/apisix/manager-api/internal/handler" - "github.com/apisix/manager-api/internal/log" - "github.com/apisix/manager-api/internal/utils" - "github.com/apisix/manager-api/internal/utils/consts" -) - -type Handler struct { - routeStore store.Interface - upstreamStore store.Interface - serviceStore store.Interface - consumerStore store.Interface -} - -func NewHandler() (handler.RouteRegister, error) { - return &Handler{ - routeStore: store.GetStore(store.HubKeyRoute), - upstreamStore: store.GetStore(store.HubKeyUpstream), - serviceStore: store.GetStore(store.HubKeyService), - consumerStore: store.GetStore(store.HubKeyConsumer), - }, nil -} - -func (h *Handler) ApplyRoute(r *gin.Engine) { - r.GET("/apisix/admin/export/routes/:ids", wgin.Wraps(h.ExportRoutes, - wrapper.InputType(reflect.TypeOf(ExportInput{})))) - r.GET("/apisix/admin/export/routes", wgin.Wraps(h.ExportAllRoutes)) -} - -type ExportInput struct { - IDs string `auto_read:"ids,path"` -} - -//ExportRoutes Export data by passing route ID, such as "R1" or multiple route parameters, such as "R1,R2" -func (h *Handler) ExportRoutes(c droplet.Context) (interface{}, error) { - input := c.Input().(*ExportInput) - - if input.IDs == "" { - return nil, consts.ErrParameterID - } - - ids := strings.Split(input.IDs, ",") - routes := []*entity.Route{} - - for _, id := range ids { - route, err := h.routeStore.Get(c.Context(), id) - if err != nil { - if err == data.ErrNotFound { - return nil, fmt.Errorf(consts.IDNotFound, "upstream", id) - } - return nil, err - } - routes = append(routes, route.(*entity.Route)) - } - - swagger, err := h.RouteToOpenAPI3(c, routes) - if err != nil { - return nil, err - } - return swagger, nil -} - -type AuthType string - -const ( - BasicAuth AuthType = "basic-auth" - KeyAuth AuthType = "key-auth" - JWTAuth AuthType = "jwt-auth" -) - -var ( - openApi = "3.0.0" - title = "RoutesExport" - service interface{} - err error - routeMethods []string - _allHTTPMethods = []string{http.MethodGet, http.MethodPost, http.MethodPut, http.MethodDelete, http.MethodPatch, http.MethodHead, http.MethodConnect, http.MethodTrace, http.MethodOptions} -) - -//ExportAllRoutes All routes can be directly exported without passing parameters -func (h *Handler) ExportAllRoutes(c droplet.Context) (interface{}, error) { - routelist, err := h.routeStore.List(c.Context(), store.ListInput{}) - - if err != nil { - return nil, err - } - - if len(routelist.Rows) < 1 { - return nil, consts.ErrRouteData - } - - routes := []*entity.Route{} - - for _, route := range routelist.Rows { - routes = append(routes, route.(*entity.Route)) - } - - swagger, err := h.RouteToOpenAPI3(c, routes) - if err != nil { - return nil, err - } - return swagger, nil -} - -//RouteToOpenAPI3 Pass in route list parameter: []*entity.Route, convert route data to openapi3 and export processing function -func (h *Handler) RouteToOpenAPI3(c droplet.Context, routes []*entity.Route) (*openapi3.Swagger, error) { - paths := openapi3.Paths{} - paramsRefs := []*openapi3.ParameterRef{} - requestBody := &openapi3.RequestBody{} - components := &openapi3.Components{} - secSchemas := openapi3.SecuritySchemes{} - _pathNumber := GetPathNumber() - - for _, route := range routes { - extensions := make(map[string]interface{}) - servicePlugins := make(map[string]interface{}) - plugins := make(map[string]interface{}) - serviceLabels := make(map[string]string) - - pathItem := &openapi3.PathItem{} - path := openapi3.Operation{} - path.Summary = route.Desc - path.OperationID = route.Name - - if route.ServiceID != nil { - serviceID := utils.InterfaceToString(route.ServiceID) - service, err = h.serviceStore.Get(c.Context(), serviceID) - if err != nil { - if err == data.ErrNotFound { - return nil, fmt.Errorf(consts.IDNotFound, "service", route.ServiceID) - } - return nil, err - } - - _service := service.(*entity.Service) - servicePlugins = _service.Plugins - serviceLabels = _service.Labels - } - - //Parse upstream - _upstream, err := h.ParseRouteUpstream(c, route) - - if err != nil { - log.Errorf("ParseRouteUpstream err: ", err) - return nil, err - } else if _upstream != nil { - extensions["x-apisix-upstream"] = _upstream - } - - if route.Host != "" { - extensions["x-apisix-host"] = route.Host - } - - if route.Hosts != nil { - extensions["x-apisix-hosts"] = route.Hosts - } - - //Parse Labels - labels, err := ParseLabels(route, serviceLabels) - if err != nil { - log.Errorf("parseLabels err: ", err) - return nil, err - } - - if labels != nil { - extensions["x-apisix-labels"] = labels - } - - if route.RemoteAddr != "" { - extensions["x-apisix-remote_addr"] = route.RemoteAddr - } - - if route.RemoteAddrs != nil { - extensions["x-apisix-remote_addrs"] = route.RemoteAddrs - } - - if route.FilterFunc != "" { - extensions["x-apisix-filter_func"] = route.FilterFunc - } - - if route.Script != nil { - extensions["x-apisix-script"] = route.Script - } - - if route.ServiceProtocol != "" { - extensions["x-apisix-service_protocol"] = route.ServiceProtocol - } - - if route.Vars != nil { - extensions["x-apisix-vars"] = route.Vars - } - - if route.ID != nil { - extensions["x-apisix-id"] = route.ID - } - - // Parse Route URIs - paths, paramsRefs = ParseRouteUris(route, paths, paramsRefs, pathItem, _pathNumber()) - - //Parse Route Plugins - path, secSchemas, paramsRefs, plugins, err = ParseRoutePlugins(route, paramsRefs, plugins, path, servicePlugins, secSchemas, requestBody) - - if err != nil { - log.Errorf("parseRoutePlugins err: ", err) - return nil, err - } - - if len(plugins) > 0 { - extensions["x-apisix-plugins"] = plugins - } - - extensions["x-apisix-priority"] = route.Priority - extensions["x-apisix-status"] = route.Status - extensions["x-apisix-enable_websocket"] = route.EnableWebsocket - path.Extensions = extensions - path.Parameters = paramsRefs - path.RequestBody = &openapi3.RequestBodyRef{Value: requestBody} - path.Responses = openapi3.NewResponses() - - if route.Methods != nil && len(route.Methods) > 0 { - routeMethods = route.Methods - } else { - routeMethods = _allHTTPMethods - } - - for i := range routeMethods { - switch strings.ToUpper(routeMethods[i]) { - case http.MethodGet: - pathItem.Get = ParsePathItem(path, http.MethodGet) - case http.MethodPost: - pathItem.Post = ParsePathItem(path, http.MethodPost) - case http.MethodPut: - pathItem.Put = ParsePathItem(path, http.MethodPut) - case http.MethodDelete: - pathItem.Delete = ParsePathItem(path, http.MethodDelete) - case http.MethodPatch: - pathItem.Patch = ParsePathItem(path, http.MethodPatch) - case http.MethodHead: - pathItem.Head = ParsePathItem(path, http.MethodHead) - case http.MethodConnect: - pathItem.Connect = ParsePathItem(path, http.MethodConnect) - case http.MethodTrace: - pathItem.Trace = ParsePathItem(path, http.MethodTrace) - case http.MethodOptions: - pathItem.Options = ParsePathItem(path, http.MethodOptions) - } - } - } - - components.SecuritySchemes = secSchemas - swagger := openapi3.Swagger{ - OpenAPI: openApi, - Info: &openapi3.Info{Title: title, Version: openApi}, - Paths: paths, - Components: *components, - } - return &swagger, nil -} - -//ParseLabels When service and route have labels at the same time, use route's label. -//When route has no label, service sometimes uses service's label. This function is used to process this logic -func ParseLabels(route *entity.Route, serviceLabels map[string]string) (map[string]string, error) { - if route.Labels != nil { - return route.Labels, nil - } else if route.ServiceID != nil { - return serviceLabels, nil - } - return nil, nil -} - -//ParsePathItem Convert data in route to openapi3 -func ParsePathItem(path openapi3.Operation, routeMethod string) *openapi3.Operation { - _path := &openapi3.Operation{ - ExtensionProps: path.ExtensionProps, - Tags: path.Tags, - Summary: path.Summary, - Description: path.Description, - OperationID: path.OperationID + routeMethod, - Parameters: path.Parameters, - RequestBody: path.RequestBody, - Responses: path.Responses, - Callbacks: path.Callbacks, - Deprecated: path.Deprecated, - Security: path.Security, - Servers: path.Servers, - ExternalDocs: path.ExternalDocs, - } - return _path -} - -// ParseRoutePlugins Merge service with plugin in route -func ParseRoutePlugins(route *entity.Route, paramsRefs []*openapi3.ParameterRef, plugins map[string]interface{}, path openapi3.Operation, servicePlugins map[string]interface{}, secSchemas openapi3.SecuritySchemes, requestBody *openapi3.RequestBody) (openapi3.Operation, openapi3.SecuritySchemes, []*openapi3.ParameterRef, map[string]interface{}, error) { - if route.Plugins != nil { - param := &openapi3.Parameter{} - secReq := &openapi3.SecurityRequirements{} - - // analysis plugins - for key, value := range route.Plugins { - // analysis request-validation plugin - if key == "request-validation" { - if valueMap, ok := value.(map[string]interface{}); ok { - if hsVal, ok := valueMap["header_schema"]; ok { - param.In = "header" - requestValidation := &entity.RequestValidation{} - reqBytes, _ := json.Marshal(&hsVal) - err := json.Unmarshal(reqBytes, requestValidation) - if err != nil { - log.Errorf("json marshal failed: %s", err) - } - for key1, value1 := range requestValidation.Properties.(map[string]interface{}) { - for _, arr := range requestValidation.Required { - if arr == key1 { - param.Required = true - } - } - param.Name = key1 - typeStr := value1.(map[string]interface{}) - schema := &openapi3.Schema{Type: typeStr["type"].(string)} - param.Schema = &openapi3.SchemaRef{Value: schema} - paramsRefs = append(paramsRefs, &openapi3.ParameterRef{Value: param}) - } - } - - if bsVal, ok := valueMap["body_schema"]; ok { - m := map[string]*openapi3.MediaType{} - reqBytes, _ := json.Marshal(&bsVal) - schema := &openapi3.Schema{} - err := json.Unmarshal(reqBytes, schema) - if err != nil { - log.Errorf("json marshal failed: %s", err) - } - // In the swagger format conversion, there are many cases of content type data format - // Such as (application/json, application/xml, text/xml) and more. - // There are many matching methods, such as equal, inclusive and so on. - // Therefore, the current processing method is to use "*/*" to match all - m["*/*"] = &openapi3.MediaType{Schema: &openapi3.SchemaRef{Value: schema}} - requestBody.Content = m - } - } - continue - } - // analysis security plugins - securityEnv := &openapi3.SecurityRequirement{} - switch key { - case string(KeyAuth): - secSchemas["api_key"] = &openapi3.SecuritySchemeRef{Value: openapi3.NewCSRFSecurityScheme()} - securityEnv.Authenticate("api_key", " ") - secReq.With(*securityEnv) - continue - case string(BasicAuth): - secSchemas["basicAuth"] = &openapi3.SecuritySchemeRef{Value: &openapi3.SecurityScheme{ - Type: "basicAuth", - Name: "basicAuth", - In: "header", - }} - securityEnv.Authenticate("basicAuth", " ") - secReq.With(*securityEnv) - continue - case string(JWTAuth): - secSchemas["bearerAuth"] = &openapi3.SecuritySchemeRef{Value: openapi3.NewJWTSecurityScheme()} - securityEnv.Authenticate("bearerAuth", " ") - secReq.With(*securityEnv) - continue - } - plugins[key] = value - } - path.Security = secReq - - if route.ServiceID != nil && servicePlugins != nil { - _servicePlugins, err := json.Marshal(servicePlugins) - if err != nil { - log.Errorf("MapToJson err: ", err) - return path, nil, nil, nil, err - } - _plugins, err := json.Marshal(plugins) - if err != nil { - log.Errorf("MapToJson err: ", err) - return path, nil, nil, nil, err - } - bytePlugins, err := utils.MergeJson(_servicePlugins, _plugins) - if err != nil { - log.Errorf("Plugins MergeJson err: ", err) - return path, nil, nil, nil, err - } - err = json.Unmarshal(bytePlugins, &plugins) - if err != nil { - log.Errorf("JsonToMapDemo err: ", err) - return path, nil, nil, nil, err - } - } - } else if route.Plugins == nil && route.ServiceID != nil { - plugins = servicePlugins - } - return path, secSchemas, paramsRefs, plugins, nil -} - -// ParseRouteUris The URI and URIs of route are converted to paths URI in openapi3 -func ParseRouteUris(route *entity.Route, paths openapi3.Paths, paramsRefs []*openapi3.ParameterRef, pathItem *openapi3.PathItem, _pathNumber int) (openapi3.Paths, []*openapi3.ParameterRef) { - routeURIs := []string{} - if route.URI != "" { - routeURIs = append(routeURIs, route.URI) - } - - if route.Uris != nil { - routeURIs = route.Uris - } - - for _, uri := range routeURIs { - if strings.Contains(uri, "*") { - if _, ok := paths[strings.Split(uri, "*")[0]+"{params}"]; !ok { - paths[strings.Split(uri, "*")[0]+"{params}"] = pathItem - } else { - paths[strings.Split(uri, "*")[0]+"{params}"+"-APISIX-REPEAT-URI-"+strconv.Itoa(_pathNumber)] = pathItem - } - // add params introduce - paramsRefs = append(paramsRefs, &openapi3.ParameterRef{ - Value: &openapi3.Parameter{ - In: "path", - Name: "params", - Required: true, - Description: "params in path", - Schema: &openapi3.SchemaRef{Value: &openapi3.Schema{Type: "string"}}}}) - } else { - if _, ok := paths[uri]; !ok { - paths[uri] = pathItem - } else { - paths[uri+"-APISIX-REPEAT-URI-"+strconv.Itoa(_pathNumber)] = pathItem - } - } - } - return paths, paramsRefs -} - -// ParseRouteUpstream Processing the upstream in service and route -func (h *Handler) ParseRouteUpstream(c droplet.Context, route *entity.Route) (interface{}, error) { - // The upstream data of route has the highest priority. - // If there is one, it will be used directly. - // If there is no route, the upstream data of service will be used. - // If there is no route, the upstream data of service will not be used normally. - if route.Upstream != nil { - return route.Upstream, nil - } else if route.UpstreamID != nil && route.Upstream == nil { - upstreamID := utils.InterfaceToString(route.UpstreamID) - upstream, err := h.upstreamStore.Get(c.Context(), upstreamID) - if err != nil { - if err == data.ErrNotFound { - return nil, fmt.Errorf(consts.IDNotFound, "upstream", route.UpstreamID) - } - return nil, err - } - return upstream, nil - } else if route.UpstreamID == nil && route.Upstream == nil && route.ServiceID != nil { - _service := service.(*entity.Service) - if _service.Upstream != nil { - return _service.Upstream, nil - } else if _service.Upstream == nil && _service.UpstreamID != nil { - upstreamID := utils.InterfaceToString(_service.UpstreamID) - upstream, err := h.upstreamStore.Get(c.Context(), upstreamID) - if err != nil { - if err == data.ErrNotFound { - return nil, fmt.Errorf(consts.IDNotFound, "upstream", _service.UpstreamID) - } - return nil, err - } - return upstream, nil - } - } - return nil, nil -} - -func GetPathNumber() func() int { - i := 0 - return func() int { - i++ - return i - } -} diff --git a/api/internal/handler/data_loader/route_export_test.go b/api/internal/handler/data_loader/route_export_test.go deleted file mode 100644 index ad397f25e9..0000000000 --- a/api/internal/handler/data_loader/route_export_test.go +++ /dev/null @@ -1,2405 +0,0 @@ -/* - * 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 data_loader - -import ( - "encoding/json" - "errors" - "strings" - "testing" - - "github.com/apisix/manager-api/internal/core/entity" - "github.com/apisix/manager-api/internal/core/store" - "github.com/shiningrush/droplet" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" -) - -// 1.Export data as the route of URIs Hosts -func TestExportRoutes1(t *testing.T) { - input := &ExportInput{IDs: "1"} - //*entity.Route - r1 := `{ - "name": "aaaa", - "labels": { - "build":"16", - "env":"production", - "version":"v2" - }, - "plugins": { - "limit-count": { - "count": 2, - "time_window": 60, - "rejected_code": 503, - "key": "remote_addr" - } - }, - "status": 1, - "uris": ["/hello_"], - "hosts": ["foo.com", "*.bar.com"], - "methods": ["GET", "POST"], - "upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - }` - - exportR1 := `{ - "components": {}, - "info": { - "title": "RoutesExport", - "version": "3.0.0" - }, - "openapi": "3.0.0", - "paths": { - "/hello_": { - "get": { - "operationId": "aaaaGET", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "security": [], - "x-apisix-enable_websocket": false, - "x-apisix-hosts": ["foo.com", "*.bar.com"], - "x-apisix-labels": { - "build": "16", - "env": "production", - "version": "v2" - }, - "x-apisix-plugins": { - "limit-count": { - "count": 2, - "key": "remote_addr", - "rejected_code": 503, - "time_window": 60 - } - }, - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - }, - "post": { - "operationId": "aaaaPOST", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "security": [], - "x-apisix-enable_websocket": false, - "x-apisix-hosts": ["foo.com", "*.bar.com"], - "x-apisix-labels": { - "build": "16", - "env": "production", - "version": "v2" - }, - "x-apisix-plugins": { - "limit-count": { - "count": 2, - "key": "remote_addr", - "rejected_code": 503, - "time_window": 60 - } - }, - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - } - } - } - }` - var route *entity.Route - err := json.Unmarshal([]byte(r1), &route) - mStore := &store.MockInterface{} - mStore.On("Get", mock.Anything).Run(func(args mock.Arguments) { - }).Return(route, nil) - - h := Handler{routeStore: mStore} - ctx := droplet.NewContext() - ctx.SetInput(input) - - ret, err := h.ExportRoutes(ctx) - assert.Nil(t, err) - ret1, err := json.Marshal(ret) - assert.Nil(t, err) - assert.Equal(t, replaceStr(exportR1), string(ret1)) - assert.NotNil(t, ret1) -} - -// 2.Export data as the route of URI host -func TestExportRoutes2(t *testing.T) { - input := &ExportInput{IDs: "1"} - //*entity.Route - r2 := `{ - "name": "aaaa2", - "labels": { - "build":"16", - "env":"production", - "version":"v2" - }, - "plugins": { - "limit-count": { - "count": 2, - "time_window": 60, - "rejected_code": 503, - "key": "remote_addr" - } - }, - "status": 1, - "uri": "/hello2", - "host": "*.bar.com", - "methods": ["GET", "POST"], - "upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - }` - - exportR2 := `{ - "components": {}, - "info": { - "title": "RoutesExport", - "version": "3.0.0" - }, - "openapi": "3.0.0", - "paths": { - "/hello2": { - "get": { - "operationId": "aaaa2GET", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "security": [], - "x-apisix-enable_websocket": false, - "x-apisix-host": "*.bar.com", - "x-apisix-labels": { - "build": "16", - "env": "production", - "version": "v2" - }, - "x-apisix-plugins": { - "limit-count": { - "count": 2, - "key": "remote_addr", - "rejected_code": 503, - "time_window": 60 - } - }, - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - }, - "post": { - "operationId": "aaaa2POST", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "security": [], - "x-apisix-enable_websocket": false, - "x-apisix-host": "*.bar.com", - "x-apisix-labels": { - "build": "16", - "env": "production", - "version": "v2" - }, - "x-apisix-plugins": { - "limit-count": { - "count": 2, - "key": "remote_addr", - "rejected_code": 503, - "time_window": 60 - } - }, - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - } - } - } - }` - var route *entity.Route - err := json.Unmarshal([]byte(r2), &route) - mStore := &store.MockInterface{} - mStore.On("Get", mock.Anything).Run(func(args mock.Arguments) { - }).Return(route, nil) - - h := Handler{routeStore: mStore} - ctx := droplet.NewContext() - ctx.SetInput(input) - - ret, err := h.ExportRoutes(ctx) - assert.Nil(t, err) - ret1, err := json.Marshal(ret) - assert.Nil(t, err) - assert.Equal(t, replaceStr(exportR2), string(ret1)) - assert.NotNil(t, ret1) -} - -// 3.Create a service that contains complete data and use the service_id create route -func TestExportRoutesCreateByServiceId(t *testing.T) { - input := &ExportInput{IDs: "1"} - //*entity.Route - r := `{ - "methods": ["GET"], - "uri": "/hello", - "service_id": "s1" - }` - - s := `{ - "id": "s1", - "name": "testservice", - "desc": "testservice_desc", - "labels": { - "build":"16", - "env":"production", - "version":"v2" - }, - "enable_websocket":true, - "plugins": { - "limit-count": { - "count": 100, - "time_window": 60, - "rejected_code": 503, - "key": "remote_addr" - } - }, - "upstream": { - "type": "roundrobin", - "nodes": [{ - "host": "172.16.238.20", - "port": 1980, - "weight": 1 - }] - } - }` - - exportR := `{ - "components": {}, - "info": { - "title": "RoutesExport", - "version": "3.0.0" - }, - "openapi": "3.0.0", - "paths": { - "/hello": { - "get": { - "operationId": "GET", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "x-apisix-enable_websocket": false, - "x-apisix-labels": { - "build": "16", - "env": "production", - "version": "v2" - }, - "x-apisix-plugins": { - "limit-count": { - "count": 100, - "key": "remote_addr", - "rejected_code": 503, - "time_window": 60 - } - }, - "x-apisix-priority": 0, - "x-apisix-status": 0, - "x-apisix-upstream": { - "nodes": [{ - "host": "172.16.238.20", - "port": 1980, - "weight": 1 - }], - "type": "roundrobin" - } - } - } - } - }` - var route *entity.Route - var service *entity.Service - err := json.Unmarshal([]byte(r), &route) - err = json.Unmarshal([]byte(s), &service) - mStore := &store.MockInterface{} - mStore.On("Get", mock.Anything).Run(func(args mock.Arguments) { - }).Return(route, nil) - mStoreService := &store.MockInterface{} - mStoreService.On("Get", mock.Anything).Run(func(args mock.Arguments) { - }).Return(service, nil) - - h := Handler{routeStore: mStore, serviceStore: mStoreService} - ctx := droplet.NewContext() - ctx.SetInput(input) - - ret, err := h.ExportRoutes(ctx) - assert.Nil(t, err) - _ret, err := json.Marshal(ret) - assert.Nil(t, err) - assert.Equal(t, replaceStr(exportR), string(_ret)) - assert.NotNil(t, _ret) -} - -// 4.Create a service containing plugin and a route containing plugin to test the fusion of exported data -func TestExportRoutesCreateByServiceId2(t *testing.T) { - input := &ExportInput{IDs: "1"} - //*entity.Route - r := `{ - "methods": ["GET"], - "uri": "/hello", - "service_id": "s1", - "enable_websocket":false, - "plugins": { - "prometheus": { - "disable": false - } - }, - "upstream": { - "type": "roundrobin", - "nodes": [{ - "host": "172.16.238.20", - "port": 1980, - "weight": 1 - }] - } - }` - - s := `{ - "id": "s1", - "name": "testservice", - "desc": "testservice_desc", - "labels": { - "build":"16", - "env":"production", - "version":"v2" - }, - "enable_websocket":true, - "plugins": { - "limit-count": { - "count": 100, - "time_window": 60, - "rejected_code": 503, - "key": "remote_addr" - } - }, - "upstream": { - "type": "roundrobin", - "nodes": [{ - "host": "172.16.238.20", - "port": 1980, - "weight": 1 - }] - } - }` - - exportR := `{ - "components": {}, - "info": { - "title": "RoutesExport", - "version": "3.0.0" - }, - "openapi": "3.0.0", - "paths": { - "/hello": { - "get": { - "operationId": "GET", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "security": [], - "x-apisix-enable_websocket": false, - "x-apisix-labels": { - "build": "16", - "env": "production", - "version": "v2" - }, - "x-apisix-plugins": { - "limit-count": { - "count": 100, - "key": "remote_addr", - "rejected_code": 503, - "time_window": 60 - }, - "prometheus": { - "disable": false - } - }, - "x-apisix-priority": 0, - "x-apisix-status": 0, - "x-apisix-upstream": { - "nodes": [{ - "host": "172.16.238.20", - "port": 1980, - "weight": 1 - }], - "type": "roundrobin" - } - } - } - } - }` - var route *entity.Route - var service *entity.Service - err := json.Unmarshal([]byte(r), &route) - err = json.Unmarshal([]byte(s), &service) - mStore := &store.MockInterface{} - mStore.On("Get", mock.Anything).Run(func(args mock.Arguments) { - }).Return(route, nil) - mStoreService := &store.MockInterface{} - mStoreService.On("Get", mock.Anything).Run(func(args mock.Arguments) { - }).Return(service, nil) - - h := Handler{routeStore: mStore, serviceStore: mStoreService} - ctx := droplet.NewContext() - ctx.SetInput(input) - - ret, err := h.ExportRoutes(ctx) - assert.Nil(t, err) - _ret, err := json.Marshal(ret) - assert.Nil(t, err) - assert.Equal(t, replaceStr(exportR), string(_ret)) - assert.NotNil(t, _ret) -} - -// 5.Create a service according to the upstream ID and a route according to the service ID -func TestExportRoutesCreateByServiceId3(t *testing.T) { - input := &ExportInput{IDs: "1"} - us := `{ - "id": "u1", - "nodes": [ - { - "host": "172.16.238.20", - "port": 1980, - "weight": 1 - } - ], - "type": "roundrobin" - }` - - s := `{ - "id": "s1", - "name": "testservice", - "desc": "testservice_desc", - "labels": { - "build":"16", - "env":"production", - "version":"v2" - }, - "enable_websocket":true, - "plugins": { - "limit-count": { - "count": 100, - "time_window": 60, - "rejected_code": 503, - "key": "remote_addr" - } - }, - "upstream_id": "u1" - }` - - r := `{ - "methods": ["GET"], - "uri": "/hello", - "service_id": "s1", - "enable_websocket":false, - "plugins": { - "prometheus": { - "disable": false - } - }, - "upstream": { - "type": "roundrobin", - "nodes": [{ - "host": "172.16.238.20", - "port": 1981, - "weight": 1 - }] - } - }` - - exportR := `{ - "components": {}, - "info": { - "title": "RoutesExport", - "version": "3.0.0" - }, - "openapi": "3.0.0", - "paths": { - "/hello": { - "get": { - "operationId": "GET", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "security": [], - "x-apisix-enable_websocket": false, - "x-apisix-labels": { - "build": "16", - "env": "production", - "version": "v2" - }, - "x-apisix-plugins": { - "limit-count": { - "count": 100, - "key": "remote_addr", - "rejected_code": 503, - "time_window": 60 - }, - "prometheus": { - "disable": false - } - }, - "x-apisix-priority": 0, - "x-apisix-status": 0, - "x-apisix-upstream": { - "nodes": [{ - "host": "172.16.238.20", - "port": 1981, - "weight": 1 - }], - "type": "roundrobin" - } - } - } - } - }` - var route *entity.Route - var service *entity.Service - var upstream *entity.Upstream - err := json.Unmarshal([]byte(r), &route) - err = json.Unmarshal([]byte(s), &service) - err = json.Unmarshal([]byte(us), &upstream) - - mStore := &store.MockInterface{} - mStore.On("Get", mock.Anything).Run(func(args mock.Arguments) { - }).Return(route, nil) - - mStoreService := &store.MockInterface{} - mStoreService.On("Get", mock.Anything).Run(func(args mock.Arguments) { - }).Return(service, nil) - - mStoreUpstream := &store.MockInterface{} - mStoreUpstream.On("Get", mock.Anything).Run(func(args mock.Arguments) { - }).Return(upstream, nil) - - h := Handler{routeStore: mStore, serviceStore: mStoreService, upstreamStore: mStoreUpstream} - ctx := droplet.NewContext() - ctx.SetInput(input) - - ret, err := h.ExportRoutes(ctx) - assert.Nil(t, err) - _ret, err := json.Marshal(ret) - assert.Nil(t, err) - assert.Equal(t, replaceStr(exportR), string(_ret)) - assert.NotNil(t, _ret) -} - -// 6.Create and export route according to upstream ID -func TestExportRoutesCreateByUpstreamId(t *testing.T) { - input := &ExportInput{IDs: "1"} - us := `{ - "id": "u1", - "nodes": [ - { - "host": "172.16.238.20", - "port": 1980, - "weight": 1 - } - ], - "type": "roundrobin" - }` - - r := `{ - "methods": ["GET"], - "uri": "/hello", - "enable_websocket":false, - "plugins": { - "prometheus": { - "disable": false - } - }, - "upstream_id": "u1" - }` - - exportR := `{ - "components": {}, - "info": { - "title": "RoutesExport", - "version": "3.0.0" - }, - "openapi": "3.0.0", - "paths": { - "/hello": { - "get": { - "operationId": "GET", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "security": [], - "x-apisix-enable_websocket": false, - "x-apisix-plugins": { - "prometheus": { - "disable": false - } - }, - "x-apisix-priority": 0, - "x-apisix-status": 0, - "x-apisix-upstream": { - "id": "u1", - "nodes": [{ - "host": "172.16.238.20", - "port": 1980, - "weight": 1 - }], - "type": "roundrobin" - } - } - } - } - }` - var route *entity.Route - var upstream *entity.Upstream - err := json.Unmarshal([]byte(r), &route) - err = json.Unmarshal([]byte(us), &upstream) - - mStore := &store.MockInterface{} - mStore.On("Get", mock.Anything).Run(func(args mock.Arguments) { - }).Return(route, nil) - - mStoreUpstream := &store.MockInterface{} - mStoreUpstream.On("Get", mock.Anything).Run(func(args mock.Arguments) { - }).Return(upstream, nil) - - h := Handler{routeStore: mStore, upstreamStore: mStoreUpstream} - ctx := droplet.NewContext() - ctx.SetInput(input) - - ret, err := h.ExportRoutes(ctx) - assert.Nil(t, err) - _ret, err := json.Marshal(ret) - assert.Nil(t, err) - assert.Equal(t, replaceStr(exportR), string(_ret)) - assert.NotNil(t, _ret) -} - -// 7.Create route according to upstream ID and service ID -func TestExportRoutesCreateByUpstreamIdandServiceId(t *testing.T) { - input := &ExportInput{IDs: "1"} - us := `{ - "id": "u1", - "nodes": [ - { - "host": "172.16.238.20", - "port": 1980, - "weight": 1 - } - ], - "type": "roundrobin" - }` - - s := `{ - "id": "s1", - "name": "testservice", - "desc": "testservice_desc", - "labels": { - "build":"16", - "env":"production", - "version":"v2" - }, - "enable_websocket":true, - "plugins": { - "limit-count": { - "count": 100, - "time_window": 60, - "rejected_code": 503, - "key": "remote_addr" - } - }, - "upstream_id": "u1" - }` - - r := `{ - "name": "route_all", - "desc": "所有", - "status": 1, - "methods": ["GET"], - "priority": 0, - "service_id": "s1", - "labels": { - "test": "1", - "API_VERSION": "v1" - }, - "vars": [ - ["arg_name", "==", "test"] - ], - "uri": "/hello", - "enable_websocket":false, - "plugins": { - "prometheus": { - "disable": false - } - }, - "upstream_id": "u1" - }` - - exportR := `{ - "components": {}, - "info": { - "title": "RoutesExport", - "version": "3.0.0" - }, - "openapi": "3.0.0", - "paths": { - "/hello": { - "get": { - "operationId": "route_allGET", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "security": [], - "summary": "所有", - "x-apisix-enable_websocket": false, - "x-apisix-labels": { - "API_VERSION": "v1", - "test": "1" - }, - "x-apisix-plugins": { - "limit-count": { - "count": 100, - "key": "remote_addr", - "rejected_code": 503, - "time_window": 60 - }, - "prometheus": { - "disable": false - } - }, - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "id": "u1", - "nodes": [{ - "host": "172.16.238.20", - "port": 1980, - "weight": 1 - }], - "type": "roundrobin" - }, - "x-apisix-vars": [ - ["arg_name", "==", "test"] - ] - } - } - } - }` - var route *entity.Route - var service *entity.Service - var upstream *entity.Upstream - err := json.Unmarshal([]byte(r), &route) - err = json.Unmarshal([]byte(s), &service) - err = json.Unmarshal([]byte(us), &upstream) - - mStore := &store.MockInterface{} - mStore.On("Get", mock.Anything).Run(func(args mock.Arguments) { - }).Return(route, nil) - - mStoreUpstream := &store.MockInterface{} - mStoreUpstream.On("Get", mock.Anything).Run(func(args mock.Arguments) { - }).Return(upstream, nil) - - mStoreService := &store.MockInterface{} - mStoreService.On("Get", mock.Anything).Run(func(args mock.Arguments) { - }).Return(service, nil) - - h := Handler{routeStore: mStore, upstreamStore: mStoreUpstream, serviceStore: mStoreService} - ctx := droplet.NewContext() - ctx.SetInput(input) - - ret, err := h.ExportRoutes(ctx) - assert.Nil(t, err) - _ret, err := json.Marshal(ret) - assert.Nil(t, err) - assert.Equal(t, replaceStr(exportR), string(_ret)) - assert.NotNil(t, _ret) -} - -// 8.Creating route using service ID does not contain upstream data -func TestExportRoutesCreateByServiceIdNoUpstream(t *testing.T) { - input := &ExportInput{IDs: "1"} - us := `{ - "id": "u1", - "nodes": [ - { - "host": "172.16.238.20", - "port": 1980, - "weight": 1 - } - ], - "type": "roundrobin" - }` - - s := `{ - "name": "testservice", - "desc": "testservice_desc", - "enable_websocket":true, - "upstream_id": "6" - }` - - r := `{ - "name": "route_all", - "desc": "所有", - "status": 1, - "methods": ["GET"], - "priority": 0, - "service_id": "s5", - "labels": { - "test": "1", - "API_VERSION": "v1" - }, - "vars": [ - ["arg_name", "==", "test"] - ], - "uri": "/hello", - "enable_websocket":false, - "plugins": { - "prometheus": { - "disable": false - } - } - }` - - exportR := `{ - "components": {}, - "info": { - "title": "RoutesExport", - "version": "3.0.0" - }, - "openapi": "3.0.0", - "paths": { - "/hello": { - "get": { - "operationId": "route_allGET", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "security": [], - "summary": "所有", - "x-apisix-enable_websocket": false, - "x-apisix-labels": { - "API_VERSION": "v1", - "test": "1" - }, - "x-apisix-plugins": { - "prometheus": { - "disable": false - } - }, - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "id": "u1", - "nodes": [{ - "host": "172.16.238.20", - "port": 1980, - "weight": 1 - }], - "type": "roundrobin" - }, - "x-apisix-vars": [ - ["arg_name", "==", "test"] - ] - } - } - } - }` - var route *entity.Route - var service *entity.Service - var upstream *entity.Upstream - err := json.Unmarshal([]byte(r), &route) - err = json.Unmarshal([]byte(s), &service) - err = json.Unmarshal([]byte(us), &upstream) - - mStore := &store.MockInterface{} - mStore.On("Get", mock.Anything).Run(func(args mock.Arguments) { - }).Return(route, nil) - - mStoreUpstream := &store.MockInterface{} - mStoreUpstream.On("Get", mock.Anything).Run(func(args mock.Arguments) { - }).Return(upstream, nil) - - mStoreService := &store.MockInterface{} - mStoreService.On("Get", mock.Anything).Run(func(args mock.Arguments) { - }).Return(service, nil) - - h := Handler{routeStore: mStore, upstreamStore: mStoreUpstream, serviceStore: mStoreService} - ctx := droplet.NewContext() - ctx.SetInput(input) - - ret, err := h.ExportRoutes(ctx) - assert.Nil(t, err) - _ret, err := json.Marshal(ret) - assert.Nil(t, err) - assert.Equal(t, replaceStr(exportR), string(_ret)) - assert.NotNil(t, _ret) -} - -// 9.Create a service with label data and a route with label data, and export the route. -// Label is the original data of the route -func TestExportRoutesCreateByLabel(t *testing.T) { - input := &ExportInput{IDs: "1"} - s := `{ - "name": "testservice", - "desc": "testservice_desc", - "enable_websocket":true, - "labels": { - "build": "10" - } - }` - - r := `{ - "name": "route_all", - "desc": "所有", - "status": 1, - "methods": ["GET"], - "service_id": "s1", - "labels": { - "test": "1", - "API_VERSION": "v1" - }, - "uri": "/hello", - "enable_websocket":false, - "upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - }` - - exportR := `{ - "components": {}, - "info": { - "title": "RoutesExport", - "version": "3.0.0" - }, - "openapi": "3.0.0", - "paths": { - "/hello": { - "get": { - "operationId": "route_allGET", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "summary": "所有", - "x-apisix-enable_websocket": false, - "x-apisix-labels": { - "API_VERSION": "v1", - "test": "1" - }, - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - } - } - } - }` - var route *entity.Route - var service *entity.Service - err := json.Unmarshal([]byte(r), &route) - err = json.Unmarshal([]byte(s), &service) - - mStore := &store.MockInterface{} - mStore.On("Get", mock.Anything).Run(func(args mock.Arguments) { - }).Return(route, nil) - - mStoreService := &store.MockInterface{} - mStoreService.On("Get", mock.Anything).Run(func(args mock.Arguments) { - }).Return(service, nil) - - h := Handler{routeStore: mStore, serviceStore: mStoreService} - ctx := droplet.NewContext() - ctx.SetInput(input) - - ret, err := h.ExportRoutes(ctx) - assert.Nil(t, err) - _ret, err := json.Marshal(ret) - assert.Nil(t, err) - assert.Equal(t, replaceStr(exportR), string(_ret)) - assert.NotNil(t, _ret) -} - -// 10.Create a service with label data and a route without label data, and export the route. -// Label is the data of the service -func TestExportRoutesCreateByLabel2(t *testing.T) { - input := &ExportInput{IDs: "1"} - s := `{ - "name": "testservice", - "desc": "testservice_desc", - "enable_websocket":true, - "labels": { - "build": "16", - "env": "production", - "version": "v2" - } - }` - - r := `{ - "name": "route_all", - "desc": "所有", - "status": 1, - "methods": ["GET"], - "service_id": "s2", - "vars": [ - ["arg_name", "==", "test"] - ], - "uri": "/hello" - }` - - exportR := `{ - "components": {}, - "info": { - "title": "RoutesExport", - "version": "3.0.0" - }, - "openapi": "3.0.0", - "paths": { - "/hello": { - "get": { - "operationId": "route_allGET", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "summary": "所有", - "x-apisix-enable_websocket": false, - "x-apisix-labels": { - "build": "16", - "env": "production", - "version": "v2" - }, - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-vars": [ - ["arg_name", "==", "test"] - ] - } - } - } - }` - var route *entity.Route - var service *entity.Service - err := json.Unmarshal([]byte(r), &route) - err = json.Unmarshal([]byte(s), &service) - - mStore := &store.MockInterface{} - mStore.On("Get", mock.Anything).Run(func(args mock.Arguments) { - }).Return(route, nil) - - mStoreService := &store.MockInterface{} - mStoreService.On("Get", mock.Anything).Run(func(args mock.Arguments) { - }).Return(service, nil) - - h := Handler{routeStore: mStore, serviceStore: mStoreService} - ctx := droplet.NewContext() - ctx.SetInput(input) - - ret, err := h.ExportRoutes(ctx) - assert.Nil(t, err) - _ret, err := json.Marshal(ret) - assert.Nil(t, err) - assert.Equal(t, replaceStr(exportR), string(_ret)) - assert.NotNil(t, _ret) -} - -// 11.Test export route request_ validation data correctness -func TestExportRoutesCreateByRequestValidation(t *testing.T) { - input := &ExportInput{IDs: "1"} - r := `{ - "uris": ["/test-test"], - "name": "route_all", - "desc": "所有", - "methods": ["GET"], - "hosts": ["test.com"], - "plugins": { - "request-validation": { - "body_schema": { - "properties": { - "boolean_payload": { - "type": "boolean" - }, - "required_payload": { - "type": "string" - } - }, - "required": ["required_payload"], - "type": "object" - }, - "disable": false, - "header_schema": { - "properties": { - "test": { - "enum": "test-enum", - "type": "string" - } - }, - "type": "string" - } - } - }, - "status": 1 - }` - - exportR := `{ - "components": {}, - "info": { - "title": "RoutesExport", - "version": "3.0.0" - }, - "openapi": "3.0.0", - "paths": { - "/test-test": { - "get": { - "operationId": "route_allGET", - "parameters": [{ - "in": "header", - "name": "test", - "schema": { - "type": "string" - } - }], - "requestBody": { - "content": { - "*/*": { - "schema": { - "properties": { - "boolean_payload": { - "type": "boolean" - }, - "required_payload": { - "type": "string" - } - }, - "required": ["required_payload"], - "type": "object" - } - } - } - }, - "responses": { - "default": { - "description": "" - } - }, - "security": [], - "summary": "所有", - "x-apisix-enable_websocket": false, - "x-apisix-hosts": ["test.com"], - "x-apisix-priority": 0, - "x-apisix-status": 1 - } - } - } - }` - var route *entity.Route - err := json.Unmarshal([]byte(r), &route) - - mStore := &store.MockInterface{} - mStore.On("Get", mock.Anything).Run(func(args mock.Arguments) { - }).Return(route, nil) - - h := Handler{routeStore: mStore} - ctx := droplet.NewContext() - ctx.SetInput(input) - - ret, err := h.ExportRoutes(ctx) - assert.Nil(t, err) - _ret, err := json.Marshal(ret) - assert.Nil(t, err) - assert.Equal(t, replaceStr(exportR), string(_ret)) - assert.NotNil(t, _ret) -} - -// 12.Export route create by jwt-auth plugin -func TestExportRoutesCreateByJWTAuth(t *testing.T) { - input := &ExportInput{IDs: "1"} - r := `{ - "uri": "/hello", - "methods": ["Get"], - "plugins": { - "jwt-auth": {} - }, - "upstream": { - "type": "roundrobin", - "nodes": [{ - "host": "172.16.238.20", - "port": 1980, - "weight": 1 - }] - } - }` - - c := `{ - "username": "jack", - "plugins": { - "jwt-auth": { - "key": "user-key", - "secret": "my-secret-key", - "algorithm": "HS256" - } - }, - "desc": "test description" - }` - - exportR := `{ - "components": { - "securitySchemes": { - "bearerAuth": { - "bearerFormat": "JWT", - "scheme": "bearer", - "type": "http" - } - } - }, - "info": { - "title": "RoutesExport", - "version": "3.0.0" - }, - "openapi": "3.0.0", - "paths": { - "/hello": { - "get": { - "operationId": "GET", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "security": [{ - "bearerAuth": [""] - }], - "x-apisix-enable_websocket": false, - "x-apisix-priority": 0, - "x-apisix-status": 0, - "x-apisix-upstream": { - "nodes": [{ - "host": "172.16.238.20", - "port": 1980, - "weight": 1 - }], - "type": "roundrobin" - } - } - } - } - }` - - var route *entity.Route - var consumer *entity.Consumer - err := json.Unmarshal([]byte(r), &route) - err = json.Unmarshal([]byte(c), &consumer) - - mStore := &store.MockInterface{} - mStore.On("Get", mock.Anything).Run(func(args mock.Arguments) { - }).Return(route, nil) - - mStoreConsumer := &store.MockInterface{} - mStoreConsumer.On("Get", mock.Anything).Run(func(args mock.Arguments) { - }).Return(consumer, nil) - - h := Handler{routeStore: mStore, consumerStore: mStoreConsumer} - ctx := droplet.NewContext() - ctx.SetInput(input) - - ret, err := h.ExportRoutes(ctx) - assert.Nil(t, err) - _ret, err := json.Marshal(ret) - assert.Nil(t, err) - assert.Equal(t, replaceStr(exportR), strings.Replace(string(_ret), " ", "", -1)) - assert.NotNil(t, _ret) -} - -// 13.Export route create by apikey-auth plugin basic-auth plugin -func TestExportRoutesCreateByKeyAuthAndBasicAuth(t *testing.T) { - input := &ExportInput{IDs: "1"} - r := `{ - "uri": "/hello", - "methods": ["Get"], - "plugins": { - "key-auth": {}, - "basic-auth": {} - }, - "upstream": { - "type": "roundrobin", - "nodes": [{ - "host": "172.16.238.20", - "port": 1980, - "weight": 1 - }] - } - }` - - c := `{ - "username": "jack", - "plugins": { - "key-auth": { - "key": "auth-one" - }, - "basic-auth": { - "username": "jack", - "password": "123456" - } - }, - "desc": "test description" - }` - - exportR := `{ - "components": { - "securitySchemes": { - "api_key": { - "in": "header", - "name": "X-XSRF-TOKEN", - "type": "apiKey" - }, - "basicAuth": { - "in": "header", - "name": "basicAuth", - "type": "basicAuth" - } - } - }, - "info": { - "title": "RoutesExport", - "version": "3.0.0" - }, - "openapi": "3.0.0", - "paths": { - "/hello": { - "get": {` - - var route *entity.Route - var consumer *entity.Consumer - err := json.Unmarshal([]byte(r), &route) - err = json.Unmarshal([]byte(c), &consumer) - - mStore := &store.MockInterface{} - mStore.On("Get", mock.Anything).Run(func(args mock.Arguments) { - }).Return(route, nil) - - mStoreConsumer := &store.MockInterface{} - mStoreConsumer.On("Get", mock.Anything).Run(func(args mock.Arguments) { - }).Return(consumer, nil) - - h := Handler{routeStore: mStore, consumerStore: mStoreConsumer} - ctx := droplet.NewContext() - ctx.SetInput(input) - - ret, err := h.ExportRoutes(ctx) - assert.Nil(t, err) - _ret, err := json.Marshal(ret) - assert.Nil(t, err) - assert.NotNil(t, _ret) - assert.Contains(t, strings.Replace(string(_ret), " ", "", -1), replaceStr(exportR)) -} - -// 14.Export all routes -func TestExportRoutesAll(t *testing.T) { - input := &store.ListInput{} - //*entity.Route - r1 := `{ - "name": "aaaa", - "status": 1, - "uri": "/hello_", - "host": "*.bar.com", - "methods": [ "POST"], - "upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - }` - - r2 := `{ - "name": "aaaa2", - "status": 1, - "uris": ["/hello_2"], - "hosts": ["foo.com", "*.bar.com"], - "methods": ["GET"], - "upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - }` - - exportR1 := `{ - "components": {}, - "info": { - "title": "RoutesExport", - "version": "3.0.0" - }, - "openapi": "3.0.0", - "paths": { - "/hello_": { - "post": { - "operationId": "aaaaPOST", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "x-apisix-enable_websocket": false, - "x-apisix-host": "*.bar.com", - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - } - }, - "/hello_2": { - "get": { - "operationId": "aaaa2GET", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "x-apisix-enable_websocket": false, - "x-apisix-hosts": ["foo.com", "*.bar.com"], - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - } - } - } - }` - var route *entity.Route - var route2 *entity.Route - var routes []*entity.Route - err := json.Unmarshal([]byte(r1), &route) - err = json.Unmarshal([]byte(r2), &route2) - mStore := &store.MockInterface{} - getCalled := false - - routes = append(routes, route) - routes = append(routes, route2) - - mStore.On("List", mock.Anything).Run(func(args mock.Arguments) { - getCalled = true - }).Return(func(input store.ListInput) *store.ListOutput { - var returnData []interface{} - for _, c := range routes { - returnData = append(returnData, c) - } - return &store.ListOutput{ - Rows: returnData, - TotalSize: len(returnData), - } - }, nil) - - h := Handler{routeStore: mStore} - ctx := droplet.NewContext() - ctx.SetInput(input) - - ret, err := h.ExportAllRoutes(ctx) - assert.Nil(t, err) - ret1, err := json.Marshal(ret) - assert.Nil(t, err) - assert.Equal(t, replaceStr(exportR1), strings.Replace(string(ret1), " ", "", -1)) - assert.NotNil(t, ret1) - assert.True(t, getCalled) -} - -//15.Create service according to upstream1 ID -// Create route according to upstream2 ID and service ID -func TestExportRoutesCreateByUpstreamIDAndServiceID2(t *testing.T) { - input := &ExportInput{IDs: "1"} - us := `{ - "id": "u1", - "nodes": [ - { - "host": "172.16.238.20", - "port": 1980, - "weight": 1 - } - ], - "type": "roundrobin" - }` - - us2 := `{ - "id": "u2", - "nodes": [ - { - "host": "172.16.238.20", - "port": 1981, - "weight": 1 - } - ], - "type": "roundrobin" - }` - - s := `{ - "id": "s1", - "name": "testservice", - "desc": "testservice_desc", - "enable_websocket":true, - "upstream_id": "u2" - }` - - r := `{ - "name": "route_all", - "desc": "所有", - "status": 1, - "methods": ["GET"], - "priority": 0, - "service_id": "s1", - "labels": { - "test": "1", - "API_VERSION": "v1" - }, - "vars": [ - ["arg_name", "==", "test"] - ], - "uri": "/hello", - "enable_websocket":false, - "plugins": { - "prometheus": { - "disable": false - } - }, - "upstream_id": "u1" - }` - - exportR := `{ - "components": {}, - "info": { - "title": "RoutesExport", - "version": "3.0.0" - }, - "openapi": "3.0.0", - "paths": { - "/hello": { - "get": { - "operationId": "route_allGET", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "security": [], - "summary": "所有", - "x-apisix-enable_websocket": false, - "x-apisix-labels": { - "API_VERSION": "v1", - "test": "1" - }, - "x-apisix-plugins": { - "prometheus": { - "disable": false - } - }, - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "id": "u1", - "nodes": [{ - "host": "172.16.238.20", - "port": 1980, - "weight": 1 - }], - "type": "roundrobin" - }, - "x-apisix-vars": [ - ["arg_name", "==", "test"] - ] - } - } - } - }` - var route *entity.Route - var service *entity.Service - var upstream *entity.Upstream - var upstream2 *entity.Upstream - var upstreams []*entity.Upstream - - err := json.Unmarshal([]byte(r), &route) - err = json.Unmarshal([]byte(s), &service) - err = json.Unmarshal([]byte(us), &upstream) - err = json.Unmarshal([]byte(us2), &upstream2) - - mStore := &store.MockInterface{} - mStore.On("Get", mock.Anything).Run(func(args mock.Arguments) { - }).Return(route, nil) - - upstreams = append(upstreams, upstream) - upstreams = append(upstreams, upstream2) - getCalled := true - - mStoreUpstream := &store.MockInterface{} - mStoreUpstream.On("Get", mock.Anything).Run(func(args mock.Arguments) { - }).Return(upstream, nil) - - mStoreUpstream.On("List", mock.Anything).Run(func(args mock.Arguments) { - getCalled = true - }).Return(func(input store.ListInput) *store.ListOutput { - var returnData []interface{} - for _, c := range upstreams { - returnData = append(returnData, c) - } - return &store.ListOutput{ - Rows: returnData, - TotalSize: len(returnData), - } - }, nil) - - mStoreService := &store.MockInterface{} - mStoreService.On("Get", mock.Anything).Run(func(args mock.Arguments) { - }).Return(service, nil) - - h := Handler{routeStore: mStore, upstreamStore: mStoreUpstream, serviceStore: mStoreService} - ctx := droplet.NewContext() - ctx.SetInput(input) - - ret, err := h.ExportRoutes(ctx) - assert.Nil(t, err) - _ret, err := json.Marshal(ret) - assert.Nil(t, err) - assert.Equal(t, replaceStr(exportR), string(_ret)) - assert.NotNil(t, _ret) - assert.True(t, getCalled) -} - -// 16.Add suffix when testing the same URI export "APISIX-REPEAT-URI-" + Millisecond time stamp: "APISIX-REPEAT-URI-1257894000000" -func TestExportRoutesSameURI(t *testing.T) { - input := &store.ListInput{} - //*entity.Route - r1 := `{ - "uris": ["/test-test"], - "name": "route_all", - "desc": "所有", - "methods": ["GET"], - "hosts": ["test.com"], - "status": 1, - "upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } -}` - - r2 := `{ - "uris": ["/test-test"], - "name": "route_all", - "desc": "所有1", - "methods": ["GET"], - "hosts": ["test.com"], - "status": 1, - "upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } -}` - - r3 := `{ - "uris": ["/test-test"], - "name": "route_all", - "desc": "所有2", - "methods": ["GET"], - "hosts": ["test.com"], - "status": 1, - "upstream": { - "nodes": { - "172.16.238.20:1981": 1 - }, - "type": "roundrobin" - } -}` - - exportR1 := `{ - "components": {}, - "info": { - "title": "RoutesExport", - "version": "3.0.0" - }, - "openapi": "3.0.0", - "paths": { - "/test-test": { - "get": { - "operationId": "route_allGET", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "summary": "所有", - "x-apisix-enable_websocket": false, - "x-apisix-hosts": ["test.com"], - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - } - }, - "/test-test-APISIX-REPEAT-URI-2": { - "get": { - "operationId": "route_allGET", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "summary": "所有1", - "x-apisix-enable_websocket": false, - "x-apisix-hosts": ["test.com"], - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - } - }, - "/test-test-APISIX-REPEAT-URI-3": { - "get": { - "operationId": "route_allGET", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "summary": "所有2", - "x-apisix-enable_websocket": false, - "x-apisix-hosts": ["test.com"], - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "172.16.238.20:1981": 1 - }, - "type": "roundrobin" - } - } - } - } - }` - var route *entity.Route - var route2 *entity.Route - var route3 *entity.Route - var routes []*entity.Route - err := json.Unmarshal([]byte(r1), &route) - err = json.Unmarshal([]byte(r2), &route2) - err = json.Unmarshal([]byte(r3), &route3) - mStore := &store.MockInterface{} - getCalled := false - - routes = append(routes, route) - routes = append(routes, route2) - routes = append(routes, route3) - - mStore.On("List", mock.Anything).Run(func(args mock.Arguments) { - getCalled = true - }).Return(func(input store.ListInput) *store.ListOutput { - var returnData []interface{} - for _, c := range routes { - returnData = append(returnData, c) - } - return &store.ListOutput{ - Rows: returnData, - TotalSize: len(returnData), - } - }, nil) - - h := Handler{routeStore: mStore} - ctx := droplet.NewContext() - ctx.SetInput(input) - - ret, err := h.ExportAllRoutes(ctx) - assert.Nil(t, err) - ret1, err := json.Marshal(ret) - assert.Nil(t, err) - assert.Equal(t, replaceStr(exportR1), string(ret1)) - assert.NotNil(t, ret1) - assert.True(t, getCalled) -} - -func TestExportRoutesParameterEmpty(t *testing.T) { - // Error test when pass parameter is null - h := Handler{} - - exportInput := &ExportInput{} - exportInput.IDs = "" - - ctx := droplet.NewContext() - ctx.SetInput(exportInput) - - _, err1 := h.ExportRoutes(ctx) - assert.Equal(t, errors.New("Parameter IDs cannot be empty"), err1) -} - -func TestExportAllRoutesDataEmpty(t *testing.T) { - // When there is no route data in the database, export route - input := &store.ListInput{} - mStore := &store.MockInterface{} - getCalled := false - - mStore.On("List", mock.Anything).Run(func(args mock.Arguments) { - getCalled = true - }).Return(func(input store.ListInput) *store.ListOutput { - var returnData []interface{} - return &store.ListOutput{ - Rows: returnData, - TotalSize: 0, - } - }, nil) - - h := Handler{routeStore: mStore} - ctx := droplet.NewContext() - ctx.SetInput(input) - - _, err := h.ExportAllRoutes(ctx) - assert.Equal(t, errors.New("Route data is empty, cannot be exported"), err) - assert.True(t, getCalled) -} - -func TestExportRoutesMethodsFeildEmpty(t *testing.T) { - input := &ExportInput{IDs: "1"} - //*entity.Route - r1 := `{ - "uris": ["/test-test"], - "name": "route", - "methods": [], - "hosts": ["test.com"], - "status": 1, - "upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } -}` - - exportR1 := `{ - "components": {}, - "info": { - "title": "RoutesExport", - "version": "3.0.0" - }, - "openapi": "3.0.0", - "paths": { - "/test-test": { - "connect": { - "operationId": "routeCONNECT", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "x-apisix-enable_websocket": false, - "x-apisix-hosts": ["test.com"], - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - }, - "delete": { - "operationId": "routeDELETE", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "x-apisix-enable_websocket": false, - "x-apisix-hosts": ["test.com"], - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - }, - "get": { - "operationId": "routeGET", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "x-apisix-enable_websocket": false, - "x-apisix-hosts": ["test.com"], - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - }, - "head": { - "operationId": "routeHEAD", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "x-apisix-enable_websocket": false, - "x-apisix-hosts": ["test.com"], - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - }, - "options": { - "operationId": "routeOPTIONS", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "x-apisix-enable_websocket": false, - "x-apisix-hosts": ["test.com"], - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - }, - "patch": { - "operationId": "routePATCH", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "x-apisix-enable_websocket": false, - "x-apisix-hosts": ["test.com"], - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - }, - "post": { - "operationId": "routePOST", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "x-apisix-enable_websocket": false, - "x-apisix-hosts": ["test.com"], - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - }, - "put": { - "operationId": "routePUT", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "x-apisix-enable_websocket": false, - "x-apisix-hosts": ["test.com"], - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - }, - "trace": { - "operationId": "routeTRACE", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "x-apisix-enable_websocket": false, - "x-apisix-hosts": ["test.com"], - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - } - } - } - }` - var route *entity.Route - err := json.Unmarshal([]byte(r1), &route) - - mStore := &store.MockInterface{} - mStore.On("Get", mock.Anything).Run(func(args mock.Arguments) { - }).Return(route, nil) - h := Handler{routeStore: mStore} - ctx := droplet.NewContext() - ctx.SetInput(input) - - ret, err := h.ExportRoutes(ctx) - assert.Nil(t, err) - ret1, err := json.Marshal(ret) - assert.Nil(t, err) - assert.Equal(t, replaceStr(exportR1), strings.Replace(string(ret1), " ", "", -1)) - assert.NotNil(t, ret1) -} - -func TestExportRoutesMethodsFeildNil(t *testing.T) { - input := &ExportInput{IDs: "1"} - //*entity.Route - r1 := `{ - "uris": ["/test-test"], - "name": "route", - "hosts": ["test.com"], - "status": 1, - "upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } -}` - - exportR1 := `{ - "components": {}, - "info": { - "title": "RoutesExport", - "version": "3.0.0" - }, - "openapi": "3.0.0", - "paths": { - "/test-test": { - "connect": { - "operationId": "routeCONNECT", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "x-apisix-enable_websocket": false, - "x-apisix-hosts": ["test.com"], - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - }, - "delete": { - "operationId": "routeDELETE", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "x-apisix-enable_websocket": false, - "x-apisix-hosts": ["test.com"], - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - }, - "get": { - "operationId": "routeGET", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "x-apisix-enable_websocket": false, - "x-apisix-hosts": ["test.com"], - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - }, - "head": { - "operationId": "routeHEAD", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "x-apisix-enable_websocket": false, - "x-apisix-hosts": ["test.com"], - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - }, - "options": { - "operationId": "routeOPTIONS", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "x-apisix-enable_websocket": false, - "x-apisix-hosts": ["test.com"], - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - }, - "patch": { - "operationId": "routePATCH", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "x-apisix-enable_websocket": false, - "x-apisix-hosts": ["test.com"], - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - }, - "post": { - "operationId": "routePOST", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "x-apisix-enable_websocket": false, - "x-apisix-hosts": ["test.com"], - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - }, - "put": { - "operationId": "routePUT", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "x-apisix-enable_websocket": false, - "x-apisix-hosts": ["test.com"], - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - }, - "trace": { - "operationId": "routeTRACE", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "x-apisix-enable_websocket": false, - "x-apisix-hosts": ["test.com"], - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "172.16.238.20:1980": 1 - }, - "type": "roundrobin" - } - } - } - } - }` - var route *entity.Route - err := json.Unmarshal([]byte(r1), &route) - - mStore := &store.MockInterface{} - mStore.On("Get", mock.Anything).Run(func(args mock.Arguments) { - }).Return(route, nil) - h := Handler{routeStore: mStore} - ctx := droplet.NewContext() - ctx.SetInput(input) - - ret, err := h.ExportRoutes(ctx) - assert.Nil(t, err) - ret1, err := json.Marshal(ret) - assert.Nil(t, err) - assert.Equal(t, replaceStr(exportR1), strings.Replace(string(ret1), " ", "", -1)) - assert.NotNil(t, ret1) -} - -func replaceStr(str string) string { - str = strings.Replace(str, "\n", "", -1) - str = strings.Replace(str, "\t", "", -1) - str = strings.Replace(str, " ", "", -1) - return str -} diff --git a/api/internal/route.go b/api/internal/route.go index 37015dd5a9..0368663232 100644 --- a/api/internal/route.go +++ b/api/internal/route.go @@ -86,7 +86,6 @@ func SetUpRouter() *gin.Engine { global_rule.NewHandler, server_info.NewHandler, label.NewHandler, - data_loader.NewHandler, data_loader.NewImportHandler, tool.NewHandler, plugin_config.NewHandler, diff --git a/api/test/e2e/route/route_export_test.go b/api/test/e2e/route/route_export_test.go deleted file mode 100644 index 49ef9e2c6c..0000000000 --- a/api/test/e2e/route/route_export_test.go +++ /dev/null @@ -1,2543 +0,0 @@ -/* - * 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 route_test - -import ( - "net/http" - "strings" - "time" - - . "github.com/onsi/ginkgo/v2" - "github.com/stretchr/testify/assert" - - "github.com/apisix/manager-api/test/e2e/base" -) - -var _ = Describe("Route", func() { - Context("test route export data empty", func() { - It("Export route when data is empty", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodGet, - Path: "/apisix/admin/export/routes", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - ExpectBody: `{"code":10000,"message":"Route data is empty, cannot be exported","data":null`, - }) - }) - }) - - Context("test route export", func() { - // 1.Export data as the route of URIs Hosts - exportStrR1 := ` - "/hello_": { - "get": { - "operationId": "aaaaGET", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "security": [], - "x-apisix-enable_websocket": false, - "x-apisix-hosts": ["foo.com", "*.bar.com"], - "x-apisix-id":"r1", - "x-apisix-labels": { - "build": "16", - "env": "production", - "version": "v2" - }, - "x-apisix-plugins": { - "limit-count": { - "count": 2, - "key": "remote_addr", - "policy": "local", - "rejected_code": 503, - "time_window": 60 - } - }, - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "` + base.UpstreamIp + `:1980": 1 - }, - "type": "roundrobin" - } - }, - "post": { - "operationId": "aaaaPOST", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "security": [], - "x-apisix-enable_websocket": false, - "x-apisix-hosts": ["foo.com", "*.bar.com"], - "x-apisix-id":"r1", - "x-apisix-labels": { - "build": "16", - "env": "production", - "version": "v2" - }, - "x-apisix-plugins": { - "limit-count": { - "count": 2, - "key": "remote_addr", - "policy": "local", - "rejected_code": 503, - "time_window": 60 - } - }, - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "` + base.UpstreamIp + `:1980": 1 - }, - "type": "roundrobin" - } - } - }` - exportStrR1 = replaceStr(exportStrR1) - It("hit route that not exist", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.APISIXExpect(), - Method: http.MethodGet, - Path: "/hello_", - Headers: map[string]string{"Host": "foo.com"}, - ExpectStatus: http.StatusNotFound, - ExpectBody: `{"error_msg":"404 Route Not Found"}`, - }) - }) - It("create route with uris and hosts to test whether the uris parsing is correct", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/routes/r1", - Body: `{ - "name": "aaaa", - "labels": { - "build":"16", - "env":"production", - "version":"v2" - }, - "plugins": { - "limit-count": { - "count": 2, - "time_window": 60, - "rejected_code": 503, - "key": "remote_addr", - "policy": "local" - } - }, - "status": 1, - "uris": ["/hello_"], - "hosts": ["foo.com", "*.bar.com"], - "methods": ["GET", "POST"], - "upstream": { - "nodes": { - "` + base.UpstreamIp + `:1980": 1 - }, - "type": "roundrobin" - } - }`, - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - }) - }) - - It("export route", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodGet, - Path: "/apisix/admin/export/routes/r1", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - ExpectBody: `{"components":{},"info":{"title":"RoutesExport","version":"3.0.0"},"openapi":"3.0.0","paths":{` + exportStrR1 + "}}", - }) - }) - // 2.Export data as the route of URI host - exportStrR2 := ` - "/hello2": { - "get": { - "operationId": "aaaa2GET", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "security": [], - "x-apisix-enable_websocket": false, - "x-apisix-host": "*.bar.com", - "x-apisix-id":"r2", - "x-apisix-labels": { - "build": "16", - "env": "production", - "version": "v2" - }, - "x-apisix-plugins": { - "limit-count": { - "count": 2, - "key": "remote_addr", - "policy": "local", - "rejected_code": 503, - "time_window": 60 - } - }, - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "` + base.UpstreamIp + `:1980": 1 - }, - "type": "roundrobin" - } - }, - "post": { - "operationId": "aaaa2POST", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "security": [], - "x-apisix-enable_websocket": false, - "x-apisix-host": "*.bar.com", - "x-apisix-id":"r2", - "x-apisix-labels": { - "build": "16", - "env": "production", - "version": "v2" - }, - "x-apisix-plugins": { - "limit-count": { - "count": 2, - "key": "remote_addr", - "policy": "local", - "rejected_code": 503, - "time_window": 60 - } - }, - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "` + base.UpstreamIp + `:1980": 1 - }, - "type": "roundrobin" - } - } - }` - exportStrR2 = replaceStr(exportStrR2) - - It("hit route2 that not exist", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.APISIXExpect(), - Method: http.MethodGet, - Path: "/hello2", - Headers: map[string]string{"Host": "bar.com"}, - ExpectStatus: http.StatusNotFound, - ExpectBody: `{"error_msg":"404 Route Not Found"}`, - }) - }) - It("create route2 with uri and host to test whether the uri parsing is correct", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/routes/r2", - Body: `{ - "name": "aaaa2", - "labels": { - "build":"16", - "env":"production", - "version":"v2" - }, - "plugins": { - "limit-count": { - "count": 2, - "time_window": 60, - "rejected_code": 503, - "key": "remote_addr", - "policy": "local" - } - }, - "status": 1, - "uri": "/hello2", - "host": "*.bar.com", - "methods": ["GET", "POST"], - "upstream": { - "nodes": { - "` + base.UpstreamIp + `:1980": 1 - }, - "type": "roundrobin" - } - }`, - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - }) - }) - It("export route2", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodGet, - Path: "/apisix/admin/export/routes/r2", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - ExpectBody: `{"components":{},"info":{"title":"RoutesExport","version":"3.0.0"},"openapi":"3.0.0","paths":{` + exportStrR2 + "}}", - }) - }) - It("export route and route2", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodGet, - Path: "/apisix/admin/export/routes/r1,r2", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - ExpectBody: `{"components":{},"info":{"title":"RoutesExport","version":"3.0.0"},"openapi":"3.0.0","paths":{` + exportStrR2 + "," + exportStrR1 + "}}", - }) - }) - It("use the exportall interface to export all routes", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodGet, - Path: "/apisix/admin/export/routes", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - ExpectBody: `{"components":{},"info":{"title":"RoutesExport","version":"3.0.0"},"openapi":"3.0.0","paths":{` + exportStrR2 + "," + exportStrR1 + "}}", - }) - }) - It("delete the route just created", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodDelete, - Path: "/apisix/admin/routes/r1", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - }) - }) - It("hit the route just deleted", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.APISIXExpect(), - Method: http.MethodGet, - Path: "/hello_", - Headers: map[string]string{"Host": "bar.com"}, - ExpectStatus: http.StatusNotFound, - ExpectBody: `{"error_msg":"404 Route Not Found"}`, - Sleep: base.SleepTime, - }) - }) - It("delete the route2 just created", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodDelete, - Path: "/apisix/admin/routes/r2", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - }) - }) - It("hit the route2 just deleted", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.APISIXExpect(), - Method: http.MethodGet, - Path: "/hello2", - Headers: map[string]string{"Host": "bar.com"}, - ExpectStatus: http.StatusNotFound, - ExpectBody: `{"error_msg":"404 Route Not Found"}`, - Sleep: base.SleepTime, - }) - }) - // 4.Create a service that contains complete data and use the service_ id create route - serviceStrS1 := ` - "name": "testservice", - "desc": "testservice_desc", - "upstream": { - "nodes": [{ - "host": "` + base.UpstreamIp + `", - "port": 1980, - "weight": 1 - }], - "type": "roundrobin" - }, - "plugins": { - "limit-count": { - "count": 100, - "key": "remote_addr", - "policy": "local", - "rejected_code": 503, - "time_window": 60 - } - }, - "labels": { - "build": "16", - "env": "production", - "version": "v2" - }, - "enable_websocket": true - ` - serviceStrS1 = replaceStr(serviceStrS1) - - exportStrR3 := ` - "components": {}, - "info": { - "title": "RoutesExport", - "version": "3.0.0" - }, - "openapi": "3.0.0", - "paths": { - "/hello3": { - "get": { - "operationId": "route3GET", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "x-apisix-enable_websocket": false, - "x-apisix-id":"r3", - "x-apisix-labels": { - "build": "16", - "env": "production", - "version": "v2" - }, - "x-apisix-plugins": { - "limit-count": { - "count": 100, - "key": "remote_addr", - "policy": "local", - "rejected_code": 503, - "time_window": 60 - } - }, - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": [{ - "host": "` + base.UpstreamIp + `", - "port": 1980, - "weight": 1 - }], - "type": "roundrobin" - } - } - } - }` - exportStrR3 = replaceStr(exportStrR3) - - It("create service with all options", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/services/s1", - Headers: map[string]string{"Authorization": base.GetToken()}, - Body: `{ - "name": "testservice", - "desc": "testservice_desc", - "labels": { - "build":"16", - "env":"production", - "version":"v2" - }, - "enable_websocket":true, - "plugins": { - "limit-count": { - "count": 100, - "time_window": 60, - "policy": "local", - "rejected_code": 503, - "key": "remote_addr" - } - }, - "upstream": { - "type": "roundrobin", - "create_time":1602883670, - "update_time":1602893670, - "nodes": [{ - "host": "` + base.UpstreamIp + `", - "port": 1980, - "weight": 1 - }] - } - }`, - ExpectStatus: http.StatusOK, - }) - }) - It("get the service s1", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodGet, - Path: "/apisix/admin/services/s1", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectCode: http.StatusOK, - ExpectBody: serviceStrS1, - }) - }) - It("create route3 using the service id just created", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/routes/r3", - Body: `{ - "name": "route3", - "methods": ["GET"], - "uri": "/hello3", - "service_id": "s1" - }`, - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectCode: http.StatusOK, - Sleep: base.SleepTime, - }) - }) - It("export route3", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodGet, - Path: "/apisix/admin/export/routes/r3", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectCode: http.StatusOK, - ExpectBody: exportStrR3, - }) - }) - It("delete the route3 just created", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodDelete, - Path: "/apisix/admin/routes/r3", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectCode: http.StatusOK, - }) - }) - It("hit the route3 just deleted", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.APISIXExpect(), - Method: http.MethodGet, - Path: "/hello3", - ExpectStatus: http.StatusNotFound, - Sleep: base.SleepTime, - }) - }) - It("delete the service1", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodDelete, - Path: "/apisix/admin/services/s1", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - Sleep: base.SleepTime, - }) - }) - // 5.Create a service containing plugin and a route containing plugin to test the fusion of exported data - // This test case tests the creation of a complete service. - // And create a complete route, export rules as route upstream data for high priority, direct use. - // However, if the data in the service plugins does not exist in the route, it will be fused and exported. - // If it exists, the data in route will be used first - serviceStrS2 := ` - "name": "testservice", - "desc": "testservice_desc", - "upstream": { - "nodes": [{ - "host": "` + base.UpstreamIp + `", - "port": 1980, - "weight": 1 - }], - "type": "roundrobin" - }, - "plugins": { - "limit-count": { - "count": 100, - "key": "remote_addr", - "policy": "local", - "rejected_code": 503, - "time_window": 60 - } - }, - "labels": { - "build": "16", - "env": "production", - "version": "v2" - }, - "enable_websocket": true` - serviceStrS2 = replaceStr(serviceStrS2) - - exportStrR4 := ` - "components": {}, - "info": { - "title": "RoutesExport", - "version": "3.0.0" - }, - "openapi": "3.0.0", - "paths": { - "/hello": { - "get": { - "operationId": "route4GET", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "security": [], - "x-apisix-enable_websocket": false, - "x-apisix-id":"r4", - "x-apisix-labels": { - "build": "16", - "env": "production", - "version": "v2" - }, - "x-apisix-plugins": { - "limit-count": { - "count": 100, - "key": "remote_addr", - "policy": "local", - "rejected_code": 503, - "time_window": 60 - }, - "prometheus": { - "disable": false - } - }, - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": [{ - "host": "` + base.UpstreamIp + `", - "port": 1980, - "weight": 1 - }], - "type": "roundrobin" - } - } - } - }` - exportStrR4 = replaceStr(exportStrR4) - - It("create service with all options", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/services/s2", - Headers: map[string]string{"Authorization": base.GetToken()}, - Body: `{ - "name": "testservice", - "desc": "testservice_desc", - "labels": { - "build":"16", - "env":"production", - "version":"v2" - }, - "enable_websocket":true, - "plugins": { - "limit-count": { - "count": 100, - "time_window": 60, - "rejected_code": 503, - "key": "remote_addr", - "policy": "local" - } - }, - "upstream": { - "type": "roundrobin", - "create_time":1602883670, - "update_time":1602893670, - "nodes": [{ - "host": "` + base.UpstreamIp + `", - "port": 1980, - "weight": 1 - }] - } - }`, - ExpectStatus: http.StatusOK, - }) - }) - It("get the service s2", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodGet, - Path: "/apisix/admin/services/s2", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - ExpectBody: serviceStrS2, - }) - }) - It("Create Route4 and test the priority merging function of upstream, label and plugin when both service and route are included", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/routes/r4", - Body: `{ - "name": "route4", - "methods": ["GET"], - "uri": "/hello", - "service_id": "s2", - "enable_websocket":false, - "plugins": { - "prometheus": { - "disable": false - } - }, - "upstream": { - "type": "roundrobin", - "nodes": [{ - "host": "` + base.UpstreamIp + `", - "port": 1980, - "weight": 1 - }] - } - }`, - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - Sleep: base.SleepTime, - }) - }) - It("export route4", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodGet, - Path: "/apisix/admin/export/routes/r4", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - ExpectBody: exportStrR4, - }) - }) - It("delete the route4 just created", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodDelete, - Path: "/apisix/admin/routes/r4", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - }) - }) - It("hit the route4 just deleted", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.APISIXExpect(), - Method: http.MethodGet, - Path: "/hello", - ExpectStatus: http.StatusNotFound, - ExpectBody: `{"error_msg":"404 Route Not Found"}`, - }) - }) - It("delete the service2", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodDelete, - Path: "/apisix/admin/services/s2", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - Sleep: base.SleepTime, - }) - }) - // 6.Create a service according to the upstream ID and a route according to the service ID. - // The test export also contains the upstream. - // Use the upstream of route. - serviceStrS3 := ` - "name": "testservice", - "desc": "testservice_desc", - "upstream_id": "1", - "plugins": { - "limit-count": { - "count": 100, - "key": "remote_addr", - "policy": "local", - "rejected_code": 503, - "time_window": 60 - } - }, - "labels": { - "build": "16", - "env": "production", - "version": "v2" - }, - "enable_websocket": true` - serviceStrS3 = replaceStr(serviceStrS3) - - exportStrR5 := ` - "components": {}, - "info": { - "title": "RoutesExport", - "version": "3.0.0" - }, - "openapi": "3.0.0", - "paths": { - "/hello5": { - "get": { - "operationId": "route5GET", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "security": [], - "x-apisix-enable_websocket": false, - "x-apisix-id":"r5", - "x-apisix-labels": { - "build": "16", - "env": "production", - "version": "v2" - }, - "x-apisix-plugins": { - "limit-count": { - "count": 100, - "key": "remote_addr", - "policy": "local", - "rejected_code": 503, - "time_window": 60 - }, - "prometheus": { - "disable": false - } - }, - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": [{ - "host": "` + base.UpstreamIp + `", - "port": 1981, - "weight": 1 - }], - "type": "roundrobin" - } - } - } - }` - exportStrR5 = replaceStr(exportStrR5) - It("create upstream", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/upstreams/1", - Headers: map[string]string{"Authorization": base.GetToken()}, - Body: `{ - "nodes": [ - { - "host": "` + base.UpstreamIp + `", - "port": 1980, - "weight": 1 - } - ], - "type": "roundrobin" - }`, - ExpectStatus: http.StatusOK, - }) - }) - It("create service with upstream id", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/services/s3", - Headers: map[string]string{"Authorization": base.GetToken()}, - Body: `{ - "name": "testservice", - "desc": "testservice_desc", - "labels": { - "build":"16", - "env":"production", - "version":"v2" - }, - "enable_websocket":true, - "plugins": { - "limit-count": { - "count": 100, - "time_window": 60, - "rejected_code": 503, - "key": "remote_addr", - "policy": "local" - } - }, - "upstream_id": "1" - }`, - ExpectStatus: http.StatusOK, - }) - }) - It("get the service s3", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodGet, - Path: "/apisix/admin/services/s3", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - ExpectBody: serviceStrS3, - }) - }) - It("Create a route5 with the id of the service3 created with upstream id", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/routes/r5", - Body: `{ - "name": "route5", - "methods": ["GET"], - "uri": "/hello5", - "service_id": "s3", - "enable_websocket":false, - "plugins": { - "prometheus": { - "disable": false - } - }, - "upstream": { - "type": "roundrobin", - "nodes": [{ - "host": "` + base.UpstreamIp + `", - "port": 1981, - "weight": 1 - }] - } - }`, - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - Sleep: base.SleepTime, - }) - }) - It("export route5", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodGet, - Path: "/apisix/admin/export/routes/r5", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - ExpectBody: exportStrR5, - }) - }) - It("delete the route5 just created", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodDelete, - Path: "/apisix/admin/routes/r5", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - }) - }) - It("hit the route5 just deleted", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.APISIXExpect(), - Method: http.MethodGet, - Path: "/hello5", - ExpectBody: `{"error_msg":"404 Route Not Found"}`, - Sleep: base.SleepTime, - }) - }) - It("delete the service3", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodDelete, - Path: "/apisix/admin/services/s3", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - Sleep: base.SleepTime, - }) - }) - It("remove upstream", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodDelete, - Path: "/apisix/admin/upstreams/1", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - }) - }) - // 8.Create and export route according to upstream ID - exportStrR8 := ` - "components": {}, - "info": { - "title": "RoutesExport", - "version": "3.0.0" - }, - "openapi": "3.0.0", - "paths": { - "/hello": { - "get": { - "operationId": "route8GET", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "security": [], - "x-apisix-enable_websocket": false, - "x-apisix-id":"r8", - "x-apisix-plugins": { - "prometheus": { - "disable": false - } - }, - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "id": "3" - ` - exportStrR8 = replaceStr(exportStrR8) - - It("create upstream3", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/upstreams/3", - Body: `{ - "nodes": [ - { - "host": "` + base.UpstreamIp + `", - "port": 1980, - "weight": 1 - } - ], - "type": "roundrobin" - }`, - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - }) - }) - It("Create a route8 using upstream id", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/routes/r8", - Body: `{ - "name": "route8", - "methods": ["GET"], - "uri": "/hello", - "enable_websocket":false, - "plugins": { - "prometheus": { - "disable": false - } - }, - "upstream_id": "3" - }`, - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - Sleep: base.SleepTime, - }) - }) - It("export route8", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodGet, - Path: "/apisix/admin/export/routes/r8", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - ExpectBody: exportStrR8, - }) - }) - It("delete the route8 just created", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodDelete, - Path: "/apisix/admin/routes/r8", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - }) - }) - It("hit the route8 just deleted", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.APISIXExpect(), - Method: http.MethodGet, - Path: "/hello", - ExpectStatus: http.StatusNotFound, - ExpectBody: `{"error_msg":"404 Route Not Found"}`, - Sleep: base.SleepTime, - }) - }) - It("remove upstream3", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodDelete, - Path: "/apisix/admin/upstreams/3", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - }) - }) - - // 9.Create service according to upstream1 ID - // Create route according to upstream2 ID and service ID - // Export route - serviceStrS4 := ` - "name": "testservice", - "desc": "testservice_desc", - "upstream_id": "4", - "enable_websocket": true` - serviceStrS4 = replaceStr(serviceStrS4) - - exportStrR9 := ` - "components": {}, - "info": { - "title": "RoutesExport", - "version": "3.0.0" - }, - "openapi": "3.0.0", - "paths": { - "/hello": { - "get": { - "operationId": "route_allGET", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "security": [], - "summary": "所有", - "x-apisix-enable_websocket": false, - "x-apisix-id":"r9", - "x-apisix-labels": { - "API_VERSION": "v1", - "test": "1" - }, - "x-apisix-plugins": { - "prometheus": { - "disable": false - } - }, - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "id": "5" - ` - exportStrR9 = replaceStr(exportStrR9) - - It("create upstream4", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/upstreams/4", - Body: `{ - "nodes": [ - { - "host": "` + base.UpstreamIp + `", - "port": 1980, - "weight": 1 - } - ], - "type": "roundrobin" - }`, - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - }) - }) - It("create upstream5", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/upstreams/5", - Body: `{ - "name": "upstream5", - "nodes": [ - { - "host": "` + base.UpstreamIp + `", - "port": 1981, - "weight": 1 - } - ], - "type": "roundrobin" - }`, - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - }) - }) - It("create service", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/services/s4", - Body: `{ - "name": "testservice", - "desc": "testservice_desc", - "enable_websocket":true, - "upstream_id": "4" - }`, - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - }) - }) - It("get the service s4", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodGet, - Path: "/apisix/admin/services/s4", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - ExpectBody: serviceStrS4, - }) - }) - It("Create a route9 using upstream id and service id", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/routes/r9", - Body: `{ - "name": "route_all", - "desc": "所有", - "status": 1, - "methods": ["GET"], - "priority": 0, - "service_id": "s4", - "labels": { - "test": "1", - "API_VERSION": "v1" - }, - "vars": [ - ["arg_name", "==", "test"] - ], - "uri": "/hello", - "enable_websocket":false, - "plugins": { - "prometheus": { - "disable": false - } - }, - "upstream_id": "5" - }`, - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - Sleep: base.SleepTime, - }) - }) - It("export route9", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodGet, - Path: "/apisix/admin/export/routes/r9", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - ExpectBody: exportStrR9, - }) - }) - It("delete the route9 just created", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodDelete, - Path: "/apisix/admin/routes/r9", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - }) - }) - It("hit the route9 just deleted", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.APISIXExpect(), - Method: http.MethodGet, - Path: "/hello", - ExpectStatus: http.StatusNotFound, - ExpectBody: `{"error_msg":"404 Route Not Found"}`, - Sleep: base.SleepTime, - }) - }) - It("delete the service4", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodDelete, - Path: "/apisix/admin/services/s4", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - Sleep: base.SleepTime, - }) - }) - It("remove upstream4", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodDelete, - Path: "/apisix/admin/upstreams/4", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - }) - }) - It("remove upstream5", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodDelete, - Path: "/apisix/admin/upstreams/5", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - }) - }) - - // 10.Creating route10 using service ID does not contain upstream data - serviceStrS5 := ` - "name": "testservice", - "desc": "testservice_desc", - "upstream_id": "6", - "enable_websocket": true` - serviceStrS5 = replaceStr(serviceStrS5) - - exportStrR10 := ` - "components": {}, - "info": { - "title": "RoutesExport", - "version": "3.0.0" - }, - "openapi": "3.0.0", - "paths": { - "/hello": { - "get": { - "operationId": "route_allGET", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "security": [], - "summary": "所有", - "x-apisix-enable_websocket": false, - "x-apisix-id":"r10", - "x-apisix-labels": { - "API_VERSION": "v1", - "test": "1" - }, - "x-apisix-plugins": { - "prometheus": { - "disable": false - } - }, - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "id": "6" - ` - exportStrR10 = replaceStr(exportStrR10) - It("create upstream6", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/upstreams/6", - Body: `{ - "nodes": [ - { - "host": "` + base.UpstreamIp + `", - "port": 1980, - "weight": 1 - } - ], - "type": "roundrobin" - }`, - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - }) - }) - It("create service", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/services/s5", - Body: `{ - "name": "testservice", - "desc": "testservice_desc", - "enable_websocket":true, - "upstream_id": "6" - }`, - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - }) - }) - It("get the service s5", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodGet, - Path: "/apisix/admin/services/s5", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - ExpectBody: serviceStrS5, - }) - }) - It("Creating route10 using service ID does not contain upstream data", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/routes/r10", - Body: `{ - "name": "route_all", - "desc": "所有", - "status": 1, - "methods": ["GET"], - "priority": 0, - "service_id": "s5", - "labels": { - "test": "1", - "API_VERSION": "v1" - }, - "vars": [ - ["arg_name", "==", "test"] - ], - "uri": "/hello", - "enable_websocket":false, - "plugins": { - "prometheus": { - "disable": false - } - } - }`, - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - Sleep: base.SleepTime, - }) - }) - It("export route10", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodGet, - Path: "/apisix/admin/export/routes/r10", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - ExpectBody: exportStrR10, - }) - }) - It("delete the route10 just created", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodDelete, - Path: "/apisix/admin/routes/r10", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - }) - }) - It("hit the route10 just deleted", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.APISIXExpect(), - Method: http.MethodGet, - Path: "/hello", - ExpectStatus: http.StatusNotFound, - ExpectBody: `{"error_msg":"404 Route Not Found"}`, - Sleep: base.SleepTime, - }) - }) - It("delete the service5", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodDelete, - Path: "/apisix/admin/services/s5", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - Sleep: base.SleepTime, - }) - }) - It("remove upstream6", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodDelete, - Path: "/apisix/admin/upstreams/6", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - }) - }) - }) - Context("test export route with jwt plugin", func() { - It("make sure the route is not created", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.APISIXExpect(), - Method: http.MethodGet, - Path: "/hello", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusNotFound, - ExpectBody: `{"error_msg":"404 Route Not Found"}`, - }) - }) - It("create route", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/routes/r1", - Body: `{ - "name": "route1", - "uri": "/hello", - "plugins": { - "jwt-auth": {} - }, - "upstream": { - "type": "roundrobin", - "nodes": [{ - "host": "` + base.UpstreamIp + `", - "port": 1980, - "weight": 1 - }] - } - }`, - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - ExpectBody: `"code":0`, - }) - }) - It("make sure the consumer is not created", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodGet, - Path: "/apisix/admin/consumers/jack", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusNotFound, - }) - }) - It("create consumer", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/consumers", - Body: `{ - "username": "jack", - "plugins": { - "jwt-auth": { - "key": "user-key", - "secret": "my-secret-key", - "algorithm": "HS256" - } - }, - "desc": "test description" - }`, - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - }) - }) - - It("create public api for JWT sign", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/routes/jwt-sign", - Body: `{ - "name": "jwt-auth", - "uri": "/apisix/plugin/jwt/sign", - "plugins": { - "public-api": {} - }, - "upstream": { - "type": "roundrobin", - "nodes": [{ - "host": "` + base.UpstreamIp + `", - "port": 1980, - "weight": 1 - }] - } - }`, - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - ExpectBody: `"code":0`, - }) - }) - - jwtToken := "" - exportStrJWT := "" - It("sign jwt token", func() { - time.Sleep(base.SleepTime) - // sign jwt token - body, status, err := base.HttpGet(base.APISIXHost+"/apisix/plugin/jwt/sign?key=user-key", nil) - assert.Nil(GinkgoT(), err) - assert.Equal(GinkgoT(), http.StatusOK, status) - jwtToken = string(body) - - // sign jwt token with not exists key - _, status, err = base.HttpGet(base.APISIXHost+"/apisix/plugin/jwt/sign?key=not-exist-key", nil) - assert.Nil(GinkgoT(), err) - assert.Equal(GinkgoT(), http.StatusNotFound, status) - - exportStrJWT = ` - "components": { - "securitySchemes": { - "bearerAuth": { - "bearerFormat": "JWT", - "scheme": "bearer", - "type": "http" - } - } - }, - "info": { - "title": "RoutesExport", - "version": "3.0.0" - }, - "openapi": "3.0.0", - ` - exportStrJWT = replaceStr(exportStrJWT) - // verify token and clean test data - }) - It("verify route with correct jwt token", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.APISIXExpect(), - Method: http.MethodGet, - Path: "/hello", - Headers: map[string]string{"Authorization": jwtToken}, - ExpectStatus: http.StatusOK, - ExpectBody: "hello world", - Sleep: base.SleepTime, - }) - }) - It("export route", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodGet, - Path: "/apisix/admin/export/routes/r1", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - ExpectBody: exportStrJWT, - }) - }) - It("delete consumer", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodDelete, - Path: "/apisix/admin/consumers/jack", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - }) - }) - It("verify route with the jwt token from just deleted consumer", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.APISIXExpect(), - Method: http.MethodGet, - Path: "/hello", - Headers: map[string]string{"Authorization": jwtToken}, - ExpectStatus: http.StatusUnauthorized, - ExpectBody: `{"message":"Missing related consumer"}`, - Sleep: base.SleepTime, - }) - }) - It("delete route", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodDelete, - Path: "/apisix/admin/routes/r1", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - }) - }) - It("verify the deleted route", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.APISIXExpect(), - Method: http.MethodGet, - Path: "/hello", - ExpectBody: `{"error_msg":"404 Route Not Found"}`, - ExpectStatus: http.StatusNotFound, - Sleep: base.SleepTime, - }) - }) - exportStrJWTNoAlgorithm := ` - "components": { - "securitySchemes": { - "bearerAuth": { - "bearerFormat": "JWT", - "scheme": "bearer", - "type": "http" - } - } - }, - "info": { - "title": "RoutesExport", - "version": "3.0.0" - }, - "openapi": "3.0.0", - ` - exportStrJWTNoAlgorithm = replaceStr(exportStrJWTNoAlgorithm) - - It("create consumer with jwt (no algorithm)", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/consumers", - Body: `{ - "username":"consumer_1", - "desc": "test description", - "plugins":{ - "jwt-auth":{ - "exp":86400, - "key":"user-key", - "secret":"my-secret-key" - } - } - }`, - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectBody: `"code":0`, - ExpectStatus: http.StatusOK, - Sleep: base.SleepTime, - }) - }) - It("get the consumer", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodGet, - Path: "/apisix/admin/consumers/consumer_1", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - ExpectBody: `"username":"consumer_1"`, - Sleep: base.SleepTime, - }) - }) - It("create the route", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/routes/r1", - Body: `{ - "name": "route1", - "uri": "/hello", - "plugins": { - "jwt-auth": {} - }, - "upstream": { - "type": "roundrobin", - "nodes": [{ - "host": "` + base.UpstreamIp + `", - "port": 1980, - "weight": 1 - }] - } - }`, - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - Sleep: base.SleepTime, - }) - }) - - jwttoken := "" - It("sign jwt token", func() { - // sign jwt token - body, status, err := base.HttpGet(base.APISIXHost+"/apisix/plugin/jwt/sign?key=user-key", nil) - assert.Nil(GinkgoT(), err) - assert.Equal(GinkgoT(), http.StatusOK, status) - jwttoken = string(body) - }) - It("hit route with jwt token", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.APISIXExpect(), - Method: http.MethodGet, - Path: "/hello", - Headers: map[string]string{"Authorization": jwttoken}, - ExpectStatus: http.StatusOK, - ExpectBody: "hello world", - Sleep: base.SleepTime, - }) - }) - It("export route", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodGet, - Path: "/apisix/admin/export/routes/r1", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - ExpectBody: exportStrJWTNoAlgorithm, - }) - }) - It("delete consumer", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodDelete, - Path: "/apisix/admin/consumers/consumer_1", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - ExpectBody: `"code":0`, - }) - }) - It("after delete consumer verify it again", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodGet, - Path: "/apisix/admin/consumers/jack", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusNotFound, - Sleep: base.SleepTime, - }) - }) - It("delete the route", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodDelete, - Path: "/apisix/admin/routes/r1", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - }) - }) - }) - - Context("test export route with auth plugin", func() { - It("make sure the route is not created", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.APISIXExpect(), - Method: http.MethodGet, - Path: "/hello", - ExpectBody: `{"error_msg":"404 Route Not Found"}`, - ExpectStatus: http.StatusNotFound, - }) - }) - It("create route", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/routes/r1", - Body: `{ - "name": "route1", - "uri": "/hello", - "plugins": { - "key-auth": {}, - "basic-auth": {} - }, - "upstream": { - "type": "roundrobin", - "nodes": [{ - "host": "` + base.UpstreamIp + `", - "port": 1980, - "weight": 1 - }] - } - }`, - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectBody: `"code":0`, - ExpectStatus: http.StatusOK, - }) - }) - It("make sure the consumer is not created", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodGet, - Path: "/apisix/admin/consumers/jack", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusNotFound, - }) - }) - It("create consumer", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/consumers", - Body: `{ - "username": "jack", - "plugins": { - "key-auth": { - "key": "auth-one" - }, - "basic-auth": { - "username": "jack", - "password": "123456" - } - }, - "desc": "test description" - }`, - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - }) - }) - - time.Sleep(base.SleepTime) - - exportStrAuth := ` - "components": { - "securitySchemes": { - "api_key": { - "in": "header", - "name": "X-XSRF-TOKEN", - "type": "apiKey" - }, - "basicAuth": { - "in": "header", - "name": "basicAuth", - "type": "basicAuth" - } - } - }, - "info": { - "title": "RoutesExport", - "version": "3.0.0" - }, - "openapi": "3.0.0"` - time.Sleep(base.SleepTime) - - exportStrAuth = replaceStr(exportStrAuth) - - It("verify route with correct basic-auth and key-auth token", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.APISIXExpect(), - Method: http.MethodGet, - Path: "/hello", - Headers: map[string]string{"Authorization": "Basic amFjazoxMjM0NTYKIA==", "apikey": "auth-one"}, - ExpectStatus: http.StatusOK, - ExpectBody: "hello world", - Sleep: base.SleepTime, - }) - }) - It("export route", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodGet, - Path: "/apisix/admin/export/routes/r1", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - ExpectBody: exportStrAuth, - }) - }) - It("delete consumer", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodDelete, - Path: "/apisix/admin/consumers/jack", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - }) - }) - It("verify route with the basic-auth and key-auth token from just deleted consumer", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.APISIXExpect(), - Method: http.MethodGet, - Path: "/hello", - Headers: map[string]string{"Authorization": "Basic amFjazoxMjM0NTYKIA==", "apikey": "auth-one"}, - ExpectStatus: http.StatusUnauthorized, - ExpectBody: `{"message":"Missing related consumer"}`, - Sleep: base.SleepTime, - }) - }) - It("delete route", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodDelete, - Path: "/apisix/admin/routes/r1", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - }) - }) - It("verify the deleted route", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.APISIXExpect(), - Method: http.MethodGet, - Path: "/hello", - ExpectStatus: http.StatusNotFound, - ExpectBody: `{"error_msg":"404 Route Not Found"}`, - Sleep: base.SleepTime, - }) - }) - }) - Context("test route export label", func() { - // 10.Create a service with label data and a route with label data, and export the route. - // Label is the original data of the route - serviceStrS1 := ` - "name": "testservice", - "desc": "testservice_desc", - "labels": { - "build": "10" - }, - "enable_websocket": true` - serviceStrS1 = replaceStr(serviceStrS1) - - exportStrR1 := ` - "components": {}, - "info": { - "title": "RoutesExport", - "version": "3.0.0" - }, - "openapi": "3.0.0", - "paths": { - "/hello": { - "get": { - "operationId": "route_allGET", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "summary": "所有", - "x-apisix-enable_websocket": false, - "x-apisix-id":"r1", - "x-apisix-labels": { - "build": "16", - "env": "production", - "version": "v2" - }, - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-vars":[ - [ - "arg_name", - "==", - "test" - ] - ] - }` - exportStrR1 = replaceStr(exportStrR1) - - It("create service", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/services/s1", - Headers: map[string]string{"Authorization": base.GetToken()}, - Body: `{ - "name": "testservice", - "desc": "testservice_desc", - "enable_websocket":true, - "labels": { - "build": "10" - } - }`, - ExpectStatus: http.StatusOK, - }) - }) - It("get the service s1", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodGet, - Path: "/apisix/admin/services/s1", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectCode: http.StatusOK, - ExpectBody: serviceStrS1, - }) - }) - It("Create a service with label data and a route with label data", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/routes/r1", - Body: `{ - "name": "route_all", - "desc": "所有", - "status": 1, - "methods": ["GET"], - "service_id": "s1", - "labels": { - "build": "16", - "env": "production", - "version": "v2" - }, - "vars": [ - ["arg_name", "==", "test"] - ], - "uri": "/hello" - }`, - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectCode: http.StatusOK, - Sleep: base.SleepTime, - }) - }) - It("export route1", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodGet, - Path: "/apisix/admin/export/routes/r1", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectCode: http.StatusOK, - ExpectBody: exportStrR1, - }) - }) - It("delete the route1 just created", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodDelete, - Path: "/apisix/admin/routes/r1", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectCode: http.StatusOK, - }) - }) - It("hit the route1 just deleted", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.APISIXExpect(), - Method: http.MethodGet, - Path: "/hello", - ExpectStatus: http.StatusNotFound, - ExpectBody: `{"error_msg":"404 Route Not Found"}`, - Sleep: base.SleepTime, - }) - }) - It("delete the service1", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodDelete, - Path: "/apisix/admin/services/s1", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - Sleep: base.SleepTime, - }) - }) - - // 11.Create a service with label data and a route without label data, and export the route. - // Label is the data of the service - serviceStrS2 := ` - "name": "testservice", - "desc": "testservice_desc", - "labels": { - "build": "16", - "env": "production", - "version": "v2" - }, - "enable_websocket": true` - serviceStrS2 = replaceStr(serviceStrS2) - - exportStrR2 := ` - "components": {}, - "info": { - "title": "RoutesExport", - "version": "3.0.0" - }, - "openapi": "3.0.0", - "paths": { - "/hello": { - "get": { - "operationId": "route_allGET", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "summary": "所有", - "x-apisix-enable_websocket": false, - "x-apisix-id":"r2", - "x-apisix-labels": { - "build": "16", - "env": "production", - "version": "v2" - }, - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-vars":[ - [ - "arg_name", - "==", - "test" - ] - ] - }` - exportStrR2 = replaceStr(exportStrR2) - - It("create service", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/services/s2", - Headers: map[string]string{"Authorization": base.GetToken()}, - Body: `{ - "name": "testservice", - "desc": "testservice_desc", - "enable_websocket":true, - "labels": { - "build": "16", - "env": "production", - "version": "v2" - } - }`, - ExpectStatus: http.StatusOK, - }) - }) - It("get the service s2", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodGet, - Path: "/apisix/admin/services/s2", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectBody: serviceStrS2, - ExpectStatus: http.StatusOK, - }) - }) - It("Create a service with label data and a route without label data", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/routes/r2", - Body: `{ - "name": "route_all", - "desc": "所有", - "status": 1, - "methods": ["GET"], - "service_id": "s2", - "vars": [ - ["arg_name", "==", "test"] - ], - "uri": "/hello" - }`, - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - Sleep: base.SleepTime, - }) - }) - It("export route2", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodGet, - Path: "/apisix/admin/export/routes/r2", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectBody: exportStrR2, - ExpectStatus: http.StatusOK, - }) - }) - It("delete the route2 just created", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodDelete, - Path: "/apisix/admin/routes/r2", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - }) - }) - It("hit the route2 just deleted", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.APISIXExpect(), - Method: http.MethodGet, - Path: "/hello", - ExpectStatus: http.StatusNotFound, - ExpectBody: "{\"error_msg\":\"404 Route Not Found\"}\n", - Sleep: base.SleepTime, - }) - }) - It("delete the service2", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodDelete, - Path: "/apisix/admin/services/s2", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - Sleep: base.SleepTime, - }) - }) - }) - Context("test route export request validation", func() { - // 12.Test export route request_ validation data correctness - exportStrR1 := ` - "components": {}, - "info": { - "title": "RoutesExport", - "version": "3.0.0" - }, - "openapi": "3.0.0", - "paths": { - "/test-test": { - "get": { - "operationId": "route_allGET", - "parameters": [{ - "in": "header", - "name": "test", - "schema": { - "type": "string" - } - }], - "requestBody": { - "content": { - "*/*": { - "schema": { - "properties": { - "boolean_payload": { - "type": "boolean" - }, - "required_payload": { - "type": "string" - } - }, - "required": ["required_payload"], - "type": "object" - } - } - } - }, - "responses": { - "default": { - "description": "" - } - }, - "security": [], - "summary": "所有", - "x-apisix-enable_websocket": false, - "x-apisix-hosts": ["test.com"], - "x-apisix-id":"r1", - "x-apisix-priority": 0, - "x-apisix-status": 1 - } - } - }` - exportStrR1 = replaceStr(exportStrR1) - - It("Create a route containing request_ validation data", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/routes/r1", - Body: `{ - "uris": ["/test-test"], - "name": "route_all", - "desc": "所有", - "methods": ["GET"], - "hosts": ["test.com"], - "plugins": { - "request-validation": { - "body_schema": { - "properties": { - "boolean_payload": { - "type": "boolean" - }, - "required_payload": { - "type": "string" - } - }, - "required": ["required_payload"], - "type": "object" - }, - "disable": false, - "header_schema": { - "properties": { - "test": { - "enum": "test-enum", - "type": "string" - } - }, - "type": "string" - } - } - }, - "status": 1 - }`, - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - Sleep: base.SleepTime, - }) - }) - It("export route1", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodGet, - Path: "/apisix/admin/export/routes/r1", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - ExpectBody: exportStrR1, - }) - }) - It("delete the route1 just created", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodDelete, - Path: "/apisix/admin/routes/r1", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - }) - }) - It("hit the route1 just deleted", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.APISIXExpect(), - Method: http.MethodGet, - Path: "/hello", - ExpectStatus: http.StatusNotFound, - ExpectBody: `{"error_msg":"404 Route Not Found"}`, - Sleep: base.SleepTime, - }) - }) - }) - Context("test route export equal uri", func() { - // 13.Add suffix when testing the same URI export - exportStrAll := ` - "components": {}, - "info": { - "title": "RoutesExport", - "version": "3.0.0" - }, - "openapi": "3.0.0", - "paths": { - "/test-test": { - "get": { - "operationId": "route_allGET", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "summary": "所有", - "x-apisix-enable_websocket": false, - "x-apisix-hosts": ["test.com"], - "x-apisix-id":"r1", - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "` + base.UpstreamIp + `:1980": 1 - }, - "type": "roundrobin" - } - } - }, - "/test-test-APISIX-REPEAT-URI-2": { - "get": { - "operationId": "route_all2GET", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "summary": "所有1", - "x-apisix-enable_websocket": false, - "x-apisix-hosts": ["test.com"], - "x-apisix-id":"r2", - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "` + base.UpstreamIp + `:1980": 1 - }, - "type": "roundrobin" - } - } - }, - "/test-test-APISIX-REPEAT-URI-3": { - "get": { - "operationId": "route_all3GET", - "requestBody": {}, - "responses": { - "default": { - "description": "" - } - }, - "summary": "所有2", - "x-apisix-enable_websocket": false, - "x-apisix-hosts": ["test.com"], - "x-apisix-id":"r3", - "x-apisix-priority": 0, - "x-apisix-status": 1, - "x-apisix-upstream": { - "nodes": { - "` + base.UpstreamIp + `:1981": 1 - }, - "type": "roundrobin" - } - } - } - }` - exportStrAll = replaceStr(exportStrAll) - - It("Create a route", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/routes/r1", - Body: `{ - "uris": ["/test-test"], - "name": "route_all", - "desc": "所有", - "methods": ["GET"], - "hosts": ["test.com"], - "status": 1, - "upstream": { - "nodes": { - "` + base.UpstreamIp + `:1980": 1 - }, - "type": "roundrobin" - } - }`, - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - Sleep: base.SleepTime, - }) - }) - It("Create a route2", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/routes/r2", - Body: `{ - "uris": ["/test-test"], - "name": "route_all2", - "desc": "所有1", - "methods": ["GET"], - "hosts": ["test.com"], - "status": 1, - "upstream": { - "nodes": { - "` + base.UpstreamIp + `:1980": 1 - }, - "type": "roundrobin" - } - }`, - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - Sleep: base.SleepTime, - }) - }) - It("Create a route3", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodPut, - Path: "/apisix/admin/routes/r3", - Body: `{ - "uris": ["/test-test"], - "name": "route_all3", - "desc": "所有2", - "methods": ["GET"], - "hosts": ["test.com"], - "status": 1, - "upstream": { - "nodes": { - "` + base.UpstreamIp + `:1981": 1 - }, - "type": "roundrobin" - } - }`, - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - Sleep: base.SleepTime, - }) - }) - It("use the exportall interface to export all routes", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodGet, - Path: "/apisix/admin/export/routes/r1,r2,r3", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - ExpectBody: exportStrAll, - }) - }) - It("delete the route1 just created", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodDelete, - Path: "/apisix/admin/routes/r1", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - }) - }) - It("hit the route1 just deleted", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.APISIXExpect(), - Method: http.MethodGet, - Path: "/hello", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectBody: `{"error_msg":"404 Route Not Found"}`, - Sleep: base.SleepTime, - }) - }) - It("delete the route2 just created", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.ManagerApiExpect(), - Method: http.MethodDelete, - Path: "/apisix/admin/routes/r2", - Headers: map[string]string{"Authorization": base.GetToken()}, - ExpectStatus: http.StatusOK, - }) - }) - It("hit the route2 just deleted", func() { - base.RunTestCase(base.HttpTestCase{ - Object: base.APISIXExpect(), - Method: http.MethodGet, - Path: "/hello", - ExpectStatus: http.StatusNotFound, - ExpectBody: `{"error_msg":"404 Route Not Found"}`, - Sleep: base.SleepTime, - }) - }) - }) -}) - -func replaceStr(str string) string { - str = strings.Replace(str, "\n", "", -1) - str = strings.Replace(str, "\t", "", -1) - str = strings.Replace(str, " ", "", -1) - return str -} diff --git a/docs/en/latest/api/api.md b/docs/en/latest/api/api.md index 2b43da6321..b270c4e8fd 100644 --- a/docs/en/latest/api/api.md +++ b/docs/en/latest/api/api.md @@ -200,25 +200,6 @@ Return the service list according to the specified page number and page size, an | 0 | list response | [ [service](#service) ] | | default | unexpected error | [ApiError](#ApiError) | -### /apisix/admin/export/routes/{ids} - -#### Summary - -Export specific or all routes as OpenAPI schema. - -##### Parameters - -| Name | Located in | Description | Required | Schema | -|------------|------------|---------------------------------------------------------------------------------------------------------------------------------------------| -------- | ------- | -| ids | path | To export specific routes, please provide the route IDs separated by commas. If you leave the ids field empty, all routes will be exported. | No | integer | - -##### Responses - -| Code | Description | Schema | -| ------- |----------------------|-------------------------------------------------------------------------------------------------------| -| 0 | openapi json content | [ [OpenAPI schema](https://github.com/OAI/OpenAPI-Specification/blob/main/schemas/v3.0/schema.json) ] | -| default | unexpected error | [ApiError](#ApiError) | - ### /apisix/admin/ssl #### GET