/*
 * 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
}
