You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by ch...@apache.org on 2020/10/02 03:16:38 UTC

[apisix-dashboard] branch refactor updated: fix: add test cases for refactored apis and fix bugs (#528)

This is an automated email from the ASF dual-hosted git repository.

chenjunxu pushed a commit to branch refactor
in repository https://gitbox.apache.org/repos/asf/apisix-dashboard.git


The following commit(s) were added to refs/heads/refactor by this push:
     new 9b5c198  fix: add test cases for refactored apis and fix bugs (#528)
9b5c198 is described below

commit 9b5c19854e3765b7bb5acd34bdd3f6f2f97f301c
Author: nic-chen <33...@users.noreply.github.com>
AuthorDate: Fri Oct 2 11:16:29 2020 +0800

    fix: add test cases for refactored apis and fix bugs (#528)
    
    * test: delete mysql version test cases.
    
    * fix: add ssl test cases and bug fix
    
    * fix: list api should return an empty array not a null for client
    
    * test: consumer test cases
    
    * fix: code style
    
    * test: init etcd in github action
    
    * fix: skip checking generated file's license
    
    * feat: add store hub and flake id (#534)
    
    * feat: add store hub and flake id
    
    * feat: add store interface to easy est
    
    * fix CI failed
    
    Co-authored-by: Vinci Xu <27...@qq.com>
---
 .actions/ASF-Release.cfg                  |   5 +
 .github/workflows/api_ci.yml              |  32 +--
 api/internal/core/entity/entity.go        |  20 +-
 api/internal/core/store/store.go          |   5 +
 api/internal/core/store/store_test.go     |  13 +-
 api/internal/core/store/storehub.go       |  16 ++
 api/internal/handler/consumer/consumer.go |  18 +-
 api/internal/handler/service/service.go   |   6 +-
 api/internal/handler/ssl/ssl.go           |  77 ++++---
 api/internal/handler/upstream/upstream.go |   6 +-
 api/internal/utils/utils.go               |  16 ++
 api/internal/utils/utils_test.go          |  16 ++
 api/route/authentication_test.go          |   4 +-
 api/route/base.go                         |   4 +-
 api/route/base_test.go                    |  92 +++++++-
 api/route/consumer_test.go                |  46 ++--
 api/route/route_group_test.go             | 131 -----------
 api/route/route_test.go                   | 200 -----------------
 api/route/ssl_test.go                     |  36 +--
 api/route/zclear_test.go                  |  37 ----
 api/service/base_test.go                  |  25 ---
 api/service/consumer_test.go              | 133 -----------
 api/service/route_group_test.go           | 120 ----------
 api/service/route_test.go                 | 329 ----------------------------
 api/service/ssl_test.go                   | 352 ------------------------------
 api/service/upstream_test.go              | 108 ---------
 26 files changed, 275 insertions(+), 1572 deletions(-)

diff --git a/.actions/ASF-Release.cfg b/.actions/ASF-Release.cfg
index 6b4cd0b..7c31253 100644
--- a/.actions/ASF-Release.cfg
+++ b/.actions/ASF-Release.cfg
@@ -87,6 +87,11 @@ DISCLAIMER.txt
 LICENSE*.txt
 NOTICE.txt
 
+# Skip generated file
+api/internal/core/store/validate_mock.go
+api/internal/core/storage/storage_mock.go
+
+
 conf
 .actions/openwhisk-utilities
 
diff --git a/.github/workflows/api_ci.yml b/.github/workflows/api_ci.yml
index 0cec7ee..32206f7 100644
--- a/.github/workflows/api_ci.yml
+++ b/.github/workflows/api_ci.yml
@@ -4,9 +4,11 @@ on:
   push:
     branches:
       - master
+      - refactor
   pull_request:
     branches:
       - master
+      - refactor
 
 jobs:
 
@@ -16,44 +18,17 @@ jobs:
 
     services:
       etcd:
-        image: bitnami/etcd:3.3.13-r80
+        image: bitnami/etcd:3.4.13
         ports:
           - 2379:2379
           - 2380:2380
         env:
           ALLOW_NONE_AUTHENTICATION: yes
 
-      mysql:
-        image: mysql:8.0
-        env:
-          MYSQL_ROOT_PASSWORD: 123456
-        ports:
-            - '3306:3306'
-        options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
-
-
     steps:
 
     - uses: actions/checkout@v2
 
-    - name: run apisix
-      run: |
-        network=$(docker network ls | grep github_network | awk '{print $2}')
-        docker run --name apisix  -d -p 9080:9080 \
-        -v ${{ github.workspace }}/.github/apisix-config.yaml:/usr/local/apisix/conf/config.yaml \
-        --network "$network" --network-alias apisix \
-        apache/apisix:dev
-        sleep 5
-        docker logs apisix
-
-    - name: setting up database
-      run: |
-        mysql -h 127.0.0.1 --port 3306 -u root -p123456  < ./api/script/db/schema.sql
-
-    - name: ping apisix
-      run: |
-        curl 127.0.0.1:9080
-
     - name: run Makefile
       run: |
         make license-check
@@ -77,4 +52,5 @@ jobs:
     - name: run test
       working-directory: ./api
       run: |
+        export APIX_ETCD_ENDPOINTS=127.0.0.1:2379
         go test ./...
diff --git a/api/internal/core/entity/entity.go b/api/internal/core/entity/entity.go
index 5dca9c8..0a38c82 100644
--- a/api/internal/core/entity/entity.go
+++ b/api/internal/core/entity/entity.go
@@ -140,15 +140,17 @@ type Consumer struct {
 }
 
 type SSL struct {
-	ID      string   `json:"id"`
-	Cert    string   `json:"cert"`
-	Key     string   `json:"key"`
-	Sni     string   `json:"sni"`
-	Snis    []string `json:"snis"`
-	Certs   []string `json:"certs"`
-	Keys    []string `json:"keys"`
-	ExpTime int      `json:"exptime"`
-	Status  int      `json:"status"`
+	ID            string   `json:"id"`
+	Cert          string   `json:"cert"`
+	Key           string   `json:"key"`
+	Sni           string   `json:"sni"`
+	Snis          []string `json:"snis"`
+	Certs         []string `json:"certs"`
+	Keys          []string `json:"keys"`
+	ExpTime       int64    `json:"exptime"`
+	Status        int      `json:"status"`
+	ValidityStart int64    `json:"validity_start"`
+	ValidityEnd   int64    `json:"validity_end"`
 }
 
 type Service struct {
diff --git a/api/internal/core/store/store.go b/api/internal/core/store/store.go
index 3d2d4b9..75c74a0 100644
--- a/api/internal/core/store/store.go
+++ b/api/internal/core/store/store.go
@@ -151,6 +151,11 @@ func (s *GenericStore) List(input ListInput) (*ListOutput, error) {
 		ret = append(ret, s.cache[k])
 	}
 
+	//should return an empty array not a null for client
+	if ret == nil {
+		ret = []interface{}{}
+	}
+
 	output := &ListOutput{
 		Rows:      ret,
 		TotalSize: len(ret),
diff --git a/api/internal/core/store/store_test.go b/api/internal/core/store/store_test.go
index 38ab343..4f29abc 100644
--- a/api/internal/core/store/store_test.go
+++ b/api/internal/core/store/store_test.go
@@ -20,14 +20,17 @@ import (
 	"context"
 	"encoding/json"
 	"fmt"
-	"github.com/apisix/manager-api/internal/core/entity"
-	"github.com/apisix/manager-api/internal/core/storage"
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/mock"
 	"reflect"
 	"strings"
 	"testing"
 	"time"
+
+	"github.com/shiningrush/droplet/data"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
+
+	"github.com/apisix/manager-api/internal/core/entity"
+	"github.com/apisix/manager-api/internal/core/storage"
 )
 
 func TestNewGenericStore(t *testing.T) {
@@ -259,7 +262,7 @@ func TestGenericStore_Get(t *testing.T) {
 					},
 				},
 			},
-			wantErr: fmt.Errorf("id:not not found"),
+			wantErr: data.ErrNotFound,
 		},
 	}
 
diff --git a/api/internal/core/store/storehub.go b/api/internal/core/store/storehub.go
index 5b26bd3..203c5bc 100644
--- a/api/internal/core/store/storehub.go
+++ b/api/internal/core/store/storehub.go
@@ -1,3 +1,19 @@
+/*
+ * 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 store
 
 import (
diff --git a/api/internal/handler/consumer/consumer.go b/api/internal/handler/consumer/consumer.go
index ed55d39..71d4b03 100644
--- a/api/internal/handler/consumer/consumer.go
+++ b/api/internal/handler/consumer/consumer.go
@@ -42,26 +42,26 @@ func NewHandler() (handler.RouteRegister, error) {
 }
 
 func (h *Handler) ApplyRoute(r *gin.Engine) {
-	r.GET("/apisix/admin/consumers/:id", wgin.Wraps(h.Get,
+	r.GET("/apisix/admin/consumers/:username", wgin.Wraps(h.Get,
 		wrapper.InputType(reflect.TypeOf(GetInput{}))))
 	r.GET("/apisix/admin/consumers", wgin.Wraps(h.List,
 		wrapper.InputType(reflect.TypeOf(ListInput{}))))
 	r.POST("/apisix/admin/consumers", wgin.Wraps(h.Create,
 		wrapper.InputType(reflect.TypeOf(entity.Consumer{}))))
-	r.PUT("/apisix/admin/consumers/:id", wgin.Wraps(h.Update,
+	r.PUT("/apisix/admin/consumers/:username", wgin.Wraps(h.Update,
 		wrapper.InputType(reflect.TypeOf(UpdateInput{}))))
-	r.DELETE("/apisix/admin/consumers", wgin.Wraps(h.BatchDelete,
+	r.DELETE("/apisix/admin/consumers/:usernames", wgin.Wraps(h.BatchDelete,
 		wrapper.InputType(reflect.TypeOf(BatchDelete{}))))
 }
 
 type GetInput struct {
-	ID string `auto_read:"id,path" validate:"required"`
+	Username string `auto_read:"username,path" validate:"required"`
 }
 
 func (h *Handler) Get(c droplet.Context) (interface{}, error) {
 	input := c.Input().(*GetInput)
 
-	r, err := h.consumerStore.Get(input.ID)
+	r, err := h.consumerStore.Get(input.Username)
 	if err != nil {
 		return nil, err
 	}
@@ -96,6 +96,7 @@ func (h *Handler) List(c droplet.Context) (interface{}, error) {
 func (h *Handler) Create(c droplet.Context) (interface{}, error) {
 	input := c.Input().(*entity.Consumer)
 
+	//TODO: check duplicate username
 	if err := h.consumerStore.Create(c.Context(), input); err != nil {
 		return nil, err
 	}
@@ -104,14 +105,15 @@ func (h *Handler) Create(c droplet.Context) (interface{}, error) {
 }
 
 type UpdateInput struct {
-	ID string `auto_read:"id,path"`
+	Username string `auto_read:"username,path"`
 	entity.Consumer
 }
 
 func (h *Handler) Update(c droplet.Context) (interface{}, error) {
 	input := c.Input().(*UpdateInput)
-	input.Consumer.ID = input.ID
+	input.Consumer.Username = input.Username
 
+	//TODO: if not exists, create
 	if err := h.consumerStore.Update(c.Context(), &input.Consumer); err != nil {
 		return nil, err
 	}
@@ -120,7 +122,7 @@ func (h *Handler) Update(c droplet.Context) (interface{}, error) {
 }
 
 type BatchDelete struct {
-	UserNames string `auto_read:"usernames,query"`
+	UserNames string `auto_read:"usernames,path"`
 }
 
 func (h *Handler) BatchDelete(c droplet.Context) (interface{}, error) {
diff --git a/api/internal/handler/service/service.go b/api/internal/handler/service/service.go
index ee8b5c5..ac4619a 100644
--- a/api/internal/handler/service/service.go
+++ b/api/internal/handler/service/service.go
@@ -51,6 +51,8 @@ func (h *Handler) ApplyRoute(r *gin.Engine) {
 		wrapper.InputType(reflect.TypeOf(entity.Service{}))))
 	r.PUT("/apisix/admin/services/:id", wgin.Wraps(h.Update,
 		wrapper.InputType(reflect.TypeOf(UpdateInput{}))))
+	r.PATCH("/apisix/admin/services/:id", wgin.Wraps(h.Patch,
+		wrapper.InputType(reflect.TypeOf(UpdateInput{}))))
 	r.DELETE("/apisix/admin/services", wgin.Wraps(h.BatchDelete,
 		wrapper.InputType(reflect.TypeOf(BatchDelete{}))))
 }
@@ -155,13 +157,13 @@ func (h *Handler) Patch(c droplet.Context) (interface{}, error) {
 	} else {
 		patch, err = jsonpatch.MakePatch(stored, input.Service)
 		if err != nil {
-			panic(err)
+			return nil, err
 		}
 	}
 
 	err = patch.Apply(&stored)
 	if err != nil {
-		panic(err)
+		return nil, err
 	}
 
 	if err := h.serviceStore.Update(c.Context(), &stored); err != nil {
diff --git a/api/internal/handler/ssl/ssl.go b/api/internal/handler/ssl/ssl.go
index 52162fb..b7bd4bb 100644
--- a/api/internal/handler/ssl/ssl.go
+++ b/api/internal/handler/ssl/ssl.go
@@ -54,7 +54,7 @@ func (h *Handler) ApplyRoute(r *gin.Engine) {
 		wrapper.InputType(reflect.TypeOf(ListInput{}))))
 	r.POST("/apisix/admin/ssl", wgin.Wraps(h.Create,
 		wrapper.InputType(reflect.TypeOf(entity.SSL{}))))
-	r.POST("/apisix/admin/ssl/validate", wgin.Wraps(h.Validate,
+	r.POST("/apisix/admin/check_ssl_cert", wgin.Wraps(h.Validate,
 		wrapper.InputType(reflect.TypeOf(entity.SSL{}))))
 	r.PUT("/apisix/admin/ssl/:id", wgin.Wraps(h.Update,
 		wrapper.InputType(reflect.TypeOf(UpdateInput{}))))
@@ -106,7 +106,14 @@ func (h *Handler) List(c droplet.Context) (interface{}, error) {
 func (h *Handler) Create(c droplet.Context) (interface{}, error) {
 	input := c.Input().(*entity.SSL)
 
-	if err := h.sslStore.Create(c.Context(), input); err != nil {
+	ssl, err := ParseCert(input.Cert, input.Key)
+	if err != nil {
+		return nil, err
+	}
+
+	ssl.ID = input.ID
+
+	if err := h.sslStore.Create(c.Context(), ssl); err != nil {
 		return nil, err
 	}
 
@@ -202,42 +209,48 @@ func ParseCert(crt, key string) (*entity.SSL, error) {
 
 	if err != nil {
 		return nil, errors.New("Certificate resolution failed")
+	}
+
+	ssl := entity.SSL{}
+	//domain
+	snis := []string{}
+	if x509Cert.DNSNames != nil && len(x509Cert.DNSNames) > 0 {
+		snis = x509Cert.DNSNames
+	} else if x509Cert.IPAddresses != nil && len(x509Cert.IPAddresses) > 0 {
+		for _, ip := range x509Cert.IPAddresses {
+			snis = append(snis, ip.String())
+		}
 	} else {
-		ssl := entity.SSL{}
-		//domain
-		snis := []string{}
-		if x509Cert.DNSNames != nil && len(x509Cert.DNSNames) > 0 {
-			snis = x509Cert.DNSNames
-		} else if x509Cert.IPAddresses != nil && len(x509Cert.IPAddresses) > 0 {
-			for _, ip := range x509Cert.IPAddresses {
-				snis = append(snis, ip.String())
+		if x509Cert.Subject.Names != nil && len(x509Cert.Subject.Names) > 1 {
+			var attributeTypeNames = map[string]string{
+				"2.5.4.6":  "C",
+				"2.5.4.10": "O",
+				"2.5.4.11": "OU",
+				"2.5.4.3":  "CN",
+				"2.5.4.5":  "SERIALNUMBER",
+				"2.5.4.7":  "L",
+				"2.5.4.8":  "ST",
+				"2.5.4.9":  "STREET",
+				"2.5.4.17": "POSTALCODE",
 			}
-		} else {
-			if x509Cert.Subject.Names != nil && len(x509Cert.Subject.Names) > 1 {
-				var attributeTypeNames = map[string]string{
-					"2.5.4.6":  "C",
-					"2.5.4.10": "O",
-					"2.5.4.11": "OU",
-					"2.5.4.3":  "CN",
-					"2.5.4.5":  "SERIALNUMBER",
-					"2.5.4.7":  "L",
-					"2.5.4.8":  "ST",
-					"2.5.4.9":  "STREET",
-					"2.5.4.17": "POSTALCODE",
-				}
-				for _, tv := range x509Cert.Subject.Names {
-					oidString := tv.Type.String()
-					typeName, ok := attributeTypeNames[oidString]
-					if ok && typeName == "CN" {
-						valueString := fmt.Sprint(tv.Value)
-						snis = append(snis, valueString)
-					}
+			for _, tv := range x509Cert.Subject.Names {
+				oidString := tv.Type.String()
+				typeName, ok := attributeTypeNames[oidString]
+				if ok && typeName == "CN" {
+					valueString := fmt.Sprint(tv.Value)
+					snis = append(snis, valueString)
 				}
 			}
 		}
-
-		return &ssl, nil
 	}
+
+	ssl.Snis = snis
+	ssl.Key = key
+	ssl.ValidityStart = x509Cert.NotBefore.Unix()
+	ssl.ValidityEnd = x509Cert.NotAfter.Unix()
+	ssl.Cert = crt
+
+	return &ssl, nil
 }
 
 func (h *Handler) Validate(c droplet.Context) (interface{}, error) {
diff --git a/api/internal/handler/upstream/upstream.go b/api/internal/handler/upstream/upstream.go
index 87a8dd0..9efb944 100644
--- a/api/internal/handler/upstream/upstream.go
+++ b/api/internal/handler/upstream/upstream.go
@@ -51,6 +51,8 @@ func (h *Handler) ApplyRoute(r *gin.Engine) {
 		wrapper.InputType(reflect.TypeOf(entity.Upstream{}))))
 	r.PUT("/apisix/admin/upstreams/:id", wgin.Wraps(h.Update,
 		wrapper.InputType(reflect.TypeOf(UpdateInput{}))))
+	r.PATCH("/apisix/admin/upstreams/:id", wgin.Wraps(h.Patch,
+		wrapper.InputType(reflect.TypeOf(UpdateInput{}))))
 	r.DELETE("/apisix/admin/upstreams", wgin.Wraps(h.BatchDelete,
 		wrapper.InputType(reflect.TypeOf(BatchDelete{}))))
 }
@@ -158,13 +160,13 @@ func (h *Handler) Patch(c droplet.Context) (interface{}, error) {
 	} else {
 		patch, err = jsonpatch.MakePatch(stored, input.Upstream)
 		if err != nil {
-			panic(err)
+			return nil, err
 		}
 	}
 
 	err = patch.Apply(&stored)
 	if err != nil {
-		panic(err)
+		return nil, err
 	}
 
 	if err := h.upstreamStore.Update(c.Context(), &stored); err != nil {
diff --git a/api/internal/utils/utils.go b/api/internal/utils/utils.go
index f28c1bf..a314df7 100644
--- a/api/internal/utils/utils.go
+++ b/api/internal/utils/utils.go
@@ -1,3 +1,19 @@
+/*
+ * 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 utils
 
 import (
diff --git a/api/internal/utils/utils_test.go b/api/internal/utils/utils_test.go
index f88a6e4..7856c9c 100644
--- a/api/internal/utils/utils_test.go
+++ b/api/internal/utils/utils_test.go
@@ -1,3 +1,19 @@
+/*
+ * 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 utils
 
 import (
diff --git a/api/route/authentication_test.go b/api/route/authentication_test.go
index c778048..952a689 100644
--- a/api/route/authentication_test.go
+++ b/api/route/authentication_test.go
@@ -27,7 +27,7 @@ var token string
 
 func TestUserLogin(t *testing.T) {
 	// password error
-	handler.
+	testHandler.
 		Post("/apisix/admin/user/login").
 		Header("Content-Type", "application/x-www-form-urlencoded").
 		Body("username=admin&password=admin1").
@@ -36,7 +36,7 @@ func TestUserLogin(t *testing.T) {
 		End()
 
 	// login success
-	sessionResponse := handler.
+	sessionResponse := testHandler.
 		Post("/apisix/admin/user/login").
 		Header("Content-Type", "application/x-www-form-urlencoded").
 		Body("username=admin&password=admin").
diff --git a/api/route/base.go b/api/route/base.go
index e40bcc6..979e750 100644
--- a/api/route/base.go
+++ b/api/route/base.go
@@ -17,8 +17,6 @@
 package route
 
 import (
-	"github.com/apisix/manager-api/internal/handler/service"
-	"github.com/apisix/manager-api/internal/handler/upstream"
 	"github.com/gin-contrib/pprof"
 	"github.com/gin-contrib/sessions"
 	"github.com/gin-contrib/sessions/cookie"
@@ -29,7 +27,9 @@ import (
 	"github.com/apisix/manager-api/internal/handler"
 	"github.com/apisix/manager-api/internal/handler/consumer"
 	"github.com/apisix/manager-api/internal/handler/route"
+	"github.com/apisix/manager-api/internal/handler/service"
 	"github.com/apisix/manager-api/internal/handler/ssl"
+	"github.com/apisix/manager-api/internal/handler/upstream"
 )
 
 func SetUpRouter() *gin.Engine {
diff --git a/api/route/base_test.go b/api/route/base_test.go
index fb9f27d..fdfd6f9 100644
--- a/api/route/base_test.go
+++ b/api/route/base_test.go
@@ -17,23 +17,105 @@
 package route
 
 import (
+	"reflect"
+	"strings"
+
 	"github.com/api7/apitest"
-	"github.com/apisix/manager-api/conf"
+	dlog "github.com/shiningrush/droplet/log"
+	"github.com/spf13/viper"
+
+	"github.com/apisix/manager-api/internal/core/entity"
+	"github.com/apisix/manager-api/internal/core/storage"
+	"github.com/apisix/manager-api/internal/core/store"
+	"github.com/apisix/manager-api/log"
 )
 
-var handler *apitest.APITest
+var testHandler *apitest.APITest
 
 var (
 	uriPrefix = "/apisix/admin"
 )
 
 func init() {
-	//init mysql connect
-	conf.InitializeMysql()
+	//init etcd
+	viper.SetEnvPrefix("APIX")
+	viper.AutomaticEnv()
+	dlog.DefLogger = log.DefLogger{}
+
+	if err := storage.InitETCDClient(strings.Split(viper.GetString("etcd_endpoints"), ",")); err != nil {
+		panic(err)
+	}
+
+	if err := initStores(); err != nil {
+		panic(err)
+	}
 
 	r := SetUpRouter()
 
-	handler = apitest.
+	testHandler = apitest.
 		New().
 		Handler(r)
 }
+
+func initStores() error {
+	err := store.InitStore(store.HubKeyConsumer, store.GenericStoreOption{
+		BasePath: "/apisix/consumers",
+		ObjType:  reflect.TypeOf(entity.Consumer{}),
+		KeyFunc: func(obj interface{}) string {
+			r := obj.(*entity.Consumer)
+			return r.Username
+		},
+	})
+	if err != nil {
+		return err
+	}
+
+	err = store.InitStore(store.HubKeyRoute, store.GenericStoreOption{
+		BasePath: "/apisix/routes",
+		ObjType:  reflect.TypeOf(entity.Route{}),
+		KeyFunc: func(obj interface{}) string {
+			r := obj.(*entity.Route)
+			return r.ID
+		},
+	})
+	if err != nil {
+		return err
+	}
+
+	err = store.InitStore(store.HubKeyService, store.GenericStoreOption{
+		BasePath: "/apisix/services",
+		ObjType:  reflect.TypeOf(entity.Service{}),
+		KeyFunc: func(obj interface{}) string {
+			r := obj.(*entity.Service)
+			return r.ID
+		},
+	})
+	if err != nil {
+		return err
+	}
+
+	err = store.InitStore(store.HubKeySsl, store.GenericStoreOption{
+		BasePath: "/apisix/ssl",
+		ObjType:  reflect.TypeOf(entity.SSL{}),
+		KeyFunc: func(obj interface{}) string {
+			r := obj.(*entity.SSL)
+			return r.ID
+		},
+	})
+	if err != nil {
+		return err
+	}
+
+	err = store.InitStore(store.HubKeyUpstream, store.GenericStoreOption{
+		BasePath: "/apisix/upstreams",
+		ObjType:  reflect.TypeOf(entity.Upstream{}),
+		KeyFunc: func(obj interface{}) string {
+			r := obj.(*entity.Upstream)
+			return r.ID
+		},
+	})
+	if err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/api/route/consumer_test.go b/api/route/consumer_test.go
index 9228ece..3793804 100644
--- a/api/route/consumer_test.go
+++ b/api/route/consumer_test.go
@@ -19,17 +19,16 @@ package route
 import (
 	"net/http"
 	"testing"
-
-	"github.com/apisix/manager-api/service"
 )
 
 func TestConsumer(t *testing.T) {
 	// create ok
-	handler.
+	username1 := "e2e_test_consumer1"
+	testHandler.
 		Post(uriPrefix+"/consumers").
 		Header("Authorization", token).
 		JSON(`{
-			"username": "e2e_test_consumer1",
+			"username": "` + username1 + `",
 			"plugins": {
 				"limit-count": {
 					"count": 2,
@@ -48,11 +47,9 @@ func TestConsumer(t *testing.T) {
 		Status(http.StatusOK).
 		End()
 
-	c1, _ := service.GetConsumerByUserName("e2e_test_consumer1")
-
 	//update ok
-	handler.
-		Put(uriPrefix + "/consumers/" + c1.ID.String()).
+	testHandler.
+		Put(uriPrefix + "/consumers/" + username1).
 		JSON(`{
 			"username": "e2e_test_consumer1",
 			"plugins": {
@@ -73,26 +70,19 @@ func TestConsumer(t *testing.T) {
 		Status(http.StatusOK).
 		End()
 
-	// duplicate username
-	handler.
-		Post(uriPrefix + "/consumers").
-		JSON(`{
-			"username": "e2e_test_consumer1",
-			"plugins": {
-				"limit-count": {
-					"count": 2,
-					"time_window": 60,
-					"rejected_code": 503,
-					"key": "remote_addr"
-				},
-				"basic-auth": {
-					"username": "foo",
-					"password": "bar"
-				}
-			},
-			"desc": "test description"
-		}`).
+	//list
+	testHandler.
+		Get(uriPrefix + "/consumers").
+		Headers(map[string]string{"Authorization": token}).
 		Expect(t).
-		Status(http.StatusBadRequest).
+		Status(http.StatusOK).
+		End()
+
+	//delete
+	testHandler.
+		Delete(uriPrefix + "/consumers/" + username1).
+		Expect(t).
+		Status(http.StatusOK).
 		End()
+
 }
diff --git a/api/route/route_group_test.go b/api/route/route_group_test.go
deleted file mode 100644
index 702ea79..0000000
--- a/api/route/route_group_test.go
+++ /dev/null
@@ -1,131 +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
-
-import (
-	"github.com/apisix/manager-api/conf"
-	"github.com/apisix/manager-api/service"
-	"net/http"
-	"testing"
-)
-
-func TestCreateRouteGroup(t *testing.T) {
-	// create ok
-	handler.
-		Post(uriPrefix+"/routegroups").
-		Header("Authorization", token).
-		JSON(`{
-			"name": "create_route_group_test",
-			"description": "test description"
-		}`).
-		Expect(t).
-		Status(http.StatusOK).
-		End()
-}
-
-func TestDuplicateGroupName(t *testing.T) {
-	// duplicate name
-	handler.
-		Post(uriPrefix+"/routegroups").
-		Header("Authorization", token).
-		JSON(`{
-			"name": "create_route_group_test",
-			"description": "test description"
-		}`).
-		Expect(t).
-		Status(http.StatusInternalServerError).
-		End()
-}
-
-func TestUpdateRouteGroup(t *testing.T) {
-	routeGroup, _ := getRouteGroupByName("create_route_group_test")
-	//update ok
-	handler.
-		Put(uriPrefix+"/routegroups/"+routeGroup.ID.String()).
-		Header("Authorization", token).
-		JSON(`{
-			"name": "update_route_group_test",
-			"description": "test description"
-		}`).
-		Expect(t).
-		Status(http.StatusOK).
-		End()
-}
-
-func TestDeleteRouteGroupHasRoutes(t *testing.T) {
-	routeGroup, _ := getRouteGroupByName("update_route_group_test")
-	// create route
-	handler.Post(uriPrefix+"/routes").
-		Header("Authorization", token).
-		JSON(`{
-			"name":"api-test-for-delete-group",
-			"desc":"api-test",
-			"priority":0,
-			"protocols":["http"],
-			"hosts":["test.com"],
-			"paths":["/*"],
-			"methods":["GET","HEAD","POST","PUT","DELETE","OPTIONS","PATCH"],
-			"status":false,
-			"upstream_protocol":"keep",
-			"plugins":{},
-			"uris":["/*"],
-			"vars":[],
-			"upstream":{"type":"roundrobin","nodes":{"127.0.0.1:443":1},
-			"timeout":{"connect":6000,"send":6000,"read":6000}},
-			"upstream_header":{},
-			"route_group_id":"` + routeGroup.ID.String() + `",
-			"route_group_name":"` + routeGroup.Name + `"
-}`).Expect(t).
-		Status(http.StatusOK).
-		End()
-	// delete fail
-	handler.
-		Delete(uriPrefix+"/routegroups/"+routeGroup.ID.String()).
-		Header("Authorization", token).
-		Expect(t).
-		Status(http.StatusInternalServerError).
-		End()
-	// get api-test-for-group
-	route, _ := getRouteByName("api-test-for-delete-group")
-	// delete route
-	handler.
-		Delete(uriPrefix+"/routes/"+route.ID.String()).
-		Header("Authorization", token).
-		Expect(t).
-		Status(http.StatusOK).
-		End()
-}
-
-func TestDeleteRouteGroup(t *testing.T) {
-	routeGroup, _ := getRouteGroupByName("update_route_group_test")
-	// delete ok
-	handler.
-		Delete(uriPrefix+"/routegroups/"+routeGroup.ID.String()).
-		Header("Authorization", token).
-		Expect(t).
-		Status(http.StatusOK).
-		End()
-}
-
-func getRouteGroupByName(name string) (*service.RouteGroupDao, error) {
-	db := conf.DB()
-	routeGroup := &service.RouteGroupDao{}
-	if err := db.Table("route_group").Where("name = ?", name).First(&routeGroup).Error; err != nil {
-		return nil, err
-	}
-	return routeGroup, nil
-}
diff --git a/api/route/route_test.go b/api/route/route_test.go
deleted file mode 100644
index dff3627..0000000
--- a/api/route/route_test.go
+++ /dev/null
@@ -1,200 +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
-
-import (
-	"net/http"
-	"testing"
-
-	"github.com/apisix/manager-api/conf"
-	"github.com/apisix/manager-api/service"
-)
-
-func TestCreateRouteForUngroup(t *testing.T) {
-	// create route with no route group -- test ungroup
-	handler.Post(uriPrefix+"/routes").
-		Header("Authorization", token).
-		JSON(`{
-			"name":"api-test-no-group",
-			"desc":"api-test-no-group",
-			"priority":0,
-			"protocols":["http"],
-			"hosts":["test.com"],
-			"paths":["/*"],
-			"methods":["GET","HEAD","POST","PUT","DELETE","OPTIONS","PATCH"],
-			"status":false,
-			"upstream_protocol":"keep",
-			"plugins":{},
-			"uris":["/*"],
-			"vars":[],
-			"upstream":{"type":"roundrobin","nodes":{"127.0.0.1:443":1},
-			"timeout":{"connect":6000,"send":6000,"read":6000}},
-			"upstream_header":{},
-			"route_group_id":"",
-			"route_group_name":""
-}`).Expect(t).
-		Status(http.StatusOK).
-		End()
-}
-
-func TestUpdateRouteWithCreateRouteGroup(t *testing.T) {
-	route, _ := getRouteByName("api-test-no-group")
-
-	// update route for create route group
-	handler.Put(uriPrefix+"/routes/"+route.ID.String()).
-		Header("Authorization", token).
-		JSON(`{
-			"name":"api-test-no-group",
-			"desc":"api-test-no-group",
-			"priority":0,
-			"protocols":["http"],
-			"hosts":["test.com"],
-			"paths":["/*"],
-			"methods":["GET","HEAD","POST","PUT","DELETE","OPTIONS","PATCH"],
-			"status":false,
-			"upstream_protocol":"keep",
-			"plugins":{},
-			"uris":["/*"],
-			"vars":[],
-			"upstream":{"type":"roundrobin","nodes":{"127.0.0.1:443":1},
-			"timeout":{"connect":6000,"send":6000,"read":6000}},
-			"upstream_header":{},
-			"route_group_id":"",
-			"route_group_name":"route-update-test-create-group"
-}`).Expect(t).
-		Status(http.StatusOK).
-		End()
-}
-
-func TestCreateRouteWithCreateNewGroup(t *testing.T) {
-	// create route with new route group
-	handler.Post(uriPrefix+"/routes").
-		Header("Authorization", token).
-		JSON(`{
-			"name":"api-test-new-group",
-			"desc":"api-test-new-group",
-			"priority":0,
-			"protocols":["http"],
-			"hosts":["test.com"],
-			"paths":["/*"],
-			"methods":["GET","HEAD","POST","PUT","DELETE","OPTIONS","PATCH"],
-			"status":false,
-			"upstream_protocol":"keep",
-			"plugins":{},
-			"uris":["/*"],
-			"vars":[],
-			"upstream":{"type":"roundrobin","nodes":{"127.0.0.1:443":1},
-			"timeout":{"connect":6000,"send":6000,"read":6000}},
-			"upstream_header":{},
-			"route_group_id":"",
-			"route_group_name":"route-create-test-create-group"
-}`).Expect(t).
-		Status(http.StatusOK).
-		End()
-}
-
-func TestCreateRouteWithDuplicateGroupName(t *testing.T) {
-	// create route with duplicate route group name
-	handler.Post(uriPrefix+"/routes").
-		Header("Authorization", token).
-		JSON(`{
-			"name":"api-test",
-			"desc":"api-test",
-			"priority":0,
-			"protocols":["http"],
-			"hosts":["test.com"],
-			"paths":["/*"],
-			"methods":["GET","HEAD","POST","PUT","DELETE","OPTIONS","PATCH"],
-			"status":false,
-			"upstream_protocol":"keep",
-			"plugins":{},
-			"uris":["/*"],
-			"vars":[],
-			"upstream":{"type":"roundrobin","nodes":{"127.0.0.1:443":1},
-			"timeout":{"connect":6000,"send":6000,"read":6000}},
-			"upstream_header":{},
-			"route_group_id":"",
-			"route_group_name":"route-create-test-create-group"
-}`).Expect(t).
-		Status(http.StatusInternalServerError).
-		End()
-}
-
-func TestPublishRoute(t *testing.T) {
-	// create route
-	handler.Post(uriPrefix+"/routes").
-		Header("Authorization", token).
-		JSON(`{
-      "name":"api-test",
-      "desc":"",
-      "priority":0,
-      "protocols":["http"],
-      "hosts":["test1.com"],
-      "paths":["/*"],
-      "methods":["GET","HEAD","POST","PUT","DELETE","OPTIONS","PATCH"],
-      "status":false,
-      "upstream_protocol":"keep",
-      "plugins":{},
-      "uris":["/*"],
-      "vars":[],
-      "upstream":{"type":"roundrobin","nodes":{"127.0.0.1:443":1},
-      "timeout":{"connect":6000,"send":6000,"read":6000}},
-      "upstream_header":{}
-}`).Expect(t).
-		Status(http.StatusOK).
-		End()
-	route, _ := getRouteByName("api-test")
-	// publish route
-	handler.Put(uriPrefix + "/routes/" + route.ID.String() + "/publish").Expect(t).Status(http.StatusOK).End()
-}
-
-func TestOfflineRoute(t *testing.T) {
-	// create route
-	handler.Post(uriPrefix+"/routes").
-		Header("Authorization", token).
-		JSON(`{
-      "name":"api-test-published",
-      "desc":"",
-      "priority":0,
-      "protocols":["http"],
-      "hosts":["test1.com"],
-      "paths":["/*"],
-      "methods":["GET","HEAD","POST","PUT","DELETE","OPTIONS","PATCH"],
-      "status":true,
-      "upstream_protocol":"keep",
-      "plugins":{},
-      "uris":["/*"],
-      "vars":[],
-      "upstream":{"type":"roundrobin","nodes":{"127.0.0.1:443":1},
-      "timeout":{"connect":6000,"send":6000,"read":6000}},
-      "upstream_header":{}
-}`).Expect(t).
-		Status(http.StatusOK).
-		End()
-	routePublished, _ := getRouteByName("api-test-published")
-	// offline route
-	handler.Put(uriPrefix + "/routes/" + routePublished.ID.String() + "/offline").Expect(t).Status(http.StatusOK).End()
-}
-
-func getRouteByName(name string) (*service.Route, error) {
-	db := conf.DB()
-	route := &service.Route{}
-	if err := db.Table("routes").Where("name = ?", name).First(&route).Error; err != nil {
-		return nil, err
-	}
-	return route, nil
-}
diff --git a/api/route/ssl_test.go b/api/route/ssl_test.go
index 3952b6b..8c85ff3 100644
--- a/api/route/ssl_test.go
+++ b/api/route/ssl_test.go
@@ -22,10 +22,12 @@ import (
 )
 
 func TestSslCreate(t *testing.T) {
+	sslId := "ssl_id"
 	// ok
-	handler.
-		Post(uriPrefix + "/ssls").
+	testHandler.
+		Post(uriPrefix + "/ssl").
 		JSON(`{
+      "id": "` + sslId + `"
 			"key": "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDGO0J9xrOcmvgh\npkqHIYHCw35FTfIT5uXOSzdF49M2ZAKBQwFG0ovYT8bc0glNLB+hpDhJPL531qSP\nl1ZOe0W1ofP1u0T5Zzc9Rub/kn7RMPq0BsSC6J3rF+rQEwh1PM8qUuD8DxZ7jaOL\niMNL6SyuZIPsS1kPPBtsioukdo666tbjNMixhQbI9Wpg55abdXRFh3i7Zu/9siF1\njCGcsskjOaUOY4sYQ3i5WU/HIIRhA82XuIL+Sxd32P8bKi2UT1sqFXRjAVR7KRWo\nIVvkmSLoZb9ucV6MsccDrRYBf6rLbI1tFj9l2rY6GTFlT+6z7K/ZI60DGi/hsBfl\nDeEQ5WuxAgMBAAECggEAVHQQyucpxHGdfzCKlfGnh+Oj20Du/p2jkHUp [...]
 			"cert": "-----BEGIN CERTIFICATE-----\nMIIEVzCCAr+gAwIBAgIQITiNM7xmudhg3pK85KDwLDANBgkqhkiG9w0BAQsFADB/\nMR4wHAYDVQQKExVta2NlcnQgZGV2ZWxvcG1lbnQgQ0ExKjAoBgNVBAsMIWp1bnh1\nY2hlbkBqdW54dWRlQWlyIChqdW54dSBjaGVuKTExMC8GA1UEAwwobWtjZXJ0IGp1\nbnh1Y2hlbkBqdW54dWRlQWlyIChqdW54dSBjaGVuKTAeFw0xOTA2MDEwMDAwMDBa\nFw0zMDA3MDgwNzQ4MDJaMFUxJzAlBgNVBAoTHm1rY2VydCBkZXZlbG9wbWVudCBj\nZXJ0aWZpY2F0ZTEqMCgGA1UECwwhanVueHVjaGVuQGp1bnh1ZGVBaXIgKGp1bnh1\nIGNoZW4pMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxjt [...]
 		}`).
@@ -33,25 +35,31 @@ func TestSslCreate(t *testing.T) {
 		Status(http.StatusOK).
 		End()
 
-	// schema fail
-	handler.
-		Post(uriPrefix + "/ssls").
+	//update ok
+	testHandler.
+		Put(uriPrefix + "/consumers/" + sslId).
 		JSON(`{
+      "id": "` + sslId + `"
+			"key": "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDGO0J9xrOcmvgh\npkqHIYHCw35FTfIT5uXOSzdF49M2ZAKBQwFG0ovYT8bc0glNLB+hpDhJPL531qSP\nl1ZOe0W1ofP1u0T5Zzc9Rub/kn7RMPq0BsSC6J3rF+rQEwh1PM8qUuD8DxZ7jaOL\niMNL6SyuZIPsS1kPPBtsioukdo666tbjNMixhQbI9Wpg55abdXRFh3i7Zu/9siF1\njCGcsskjOaUOY4sYQ3i5WU/HIIRhA82XuIL+Sxd32P8bKi2UT1sqFXRjAVR7KRWo\nIVvkmSLoZb9ucV6MsccDrRYBf6rLbI1tFj9l2rY6GTFlT+6z7K/ZI60DGi/hsBfl\nDeEQ5WuxAgMBAAECggEAVHQQyucpxHGdfzCKlfGnh+Oj20Du/p2jkHUp [...]
 			"cert": "-----BEGIN CERTIFICATE-----\nMIIEVzCCAr+gAwIBAgIQITiNM7xmudhg3pK85KDwLDANBgkqhkiG9w0BAQsFADB/\nMR4wHAYDVQQKExVta2NlcnQgZGV2ZWxvcG1lbnQgQ0ExKjAoBgNVBAsMIWp1bnh1\nY2hlbkBqdW54dWRlQWlyIChqdW54dSBjaGVuKTExMC8GA1UEAwwobWtjZXJ0IGp1\nbnh1Y2hlbkBqdW54dWRlQWlyIChqdW54dSBjaGVuKTAeFw0xOTA2MDEwMDAwMDBa\nFw0zMDA3MDgwNzQ4MDJaMFUxJzAlBgNVBAoTHm1rY2VydCBkZXZlbG9wbWVudCBj\nZXJ0aWZpY2F0ZTEqMCgGA1UECwwhanVueHVjaGVuQGp1bnh1ZGVBaXIgKGp1bnh1\nIGNoZW4pMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxjt [...]
 		}`).
 		Expect(t).
-		Status(http.StatusBadRequest).
+		Status(http.StatusOK).
 		End()
 
-	//schema fail 2
-	handler.
-		Post(uriPrefix + "/ssls").
-		JSON(`{
-			"key": "",
-			"cert": "-----BEGIN CERTIFICATE-----\nMIIEVzCCAr+gAwIBAgIQITiNM7xmudhg3pK85KDwLDANBgkqhkiG9w0BAQsFADB/\nMR4wHAYDVQQKExVta2NlcnQgZGV2ZWxvcG1lbnQgQ0ExKjAoBgNVBAsMIWp1bnh1\nY2hlbkBqdW54dWRlQWlyIChqdW54dSBjaGVuKTExMC8GA1UEAwwobWtjZXJ0IGp1\nbnh1Y2hlbkBqdW54dWRlQWlyIChqdW54dSBjaGVuKTAeFw0xOTA2MDEwMDAwMDBa\nFw0zMDA3MDgwNzQ4MDJaMFUxJzAlBgNVBAoTHm1rY2VydCBkZXZlbG9wbWVudCBj\nZXJ0aWZpY2F0ZTEqMCgGA1UECwwhanVueHVjaGVuQGp1bnh1ZGVBaXIgKGp1bnh1\nIGNoZW4pMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxjt [...]
-		}`).
+	//list
+	testHandler.
+		Get(uriPrefix + "/ssl").
+		Headers(map[string]string{"Authorization": token}).
 		Expect(t).
-		Status(http.StatusBadRequest).
+		Status(http.StatusOK).
+		End()
+
+	//delete
+	testHandler.
+		Delete(uriPrefix + "/consumers/" + sslId).
+		Expect(t).
+		Status(http.StatusOK).
 		End()
 
 }
diff --git a/api/route/zclear_test.go b/api/route/zclear_test.go
deleted file mode 100644
index e44101b..0000000
--- a/api/route/zclear_test.go
+++ /dev/null
@@ -1,37 +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
-
-import (
-	"net/http"
-	"testing"
-
-	"github.com/apisix/manager-api/service"
-)
-
-func TestClearTestData(t *testing.T) {
-	// delete consumers
-	c1, _ := service.GetConsumerByUserName("e2e_test_consumer1")
-	handler.
-		Delete(uriPrefix + "/consumers/" + c1.ID.String()).
-		Expect(t).
-		Status(http.StatusOK).
-		End()
-
-	//delete test ssl
-	service.DeleteTestSslData()
-}
diff --git a/api/service/base_test.go b/api/service/base_test.go
deleted file mode 100644
index dc665a9..0000000
--- a/api/service/base_test.go
+++ /dev/null
@@ -1,25 +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 service
-
-import (
-	"github.com/apisix/manager-api/conf"
-)
-
-func init() {
-	conf.InitializeMysql()
-}
diff --git a/api/service/consumer_test.go b/api/service/consumer_test.go
deleted file mode 100644
index cd0e3d9..0000000
--- a/api/service/consumer_test.go
+++ /dev/null
@@ -1,133 +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 service
-
-import (
-	"testing"
-
-	"github.com/apisix/manager-api/errno"
-	uuid "github.com/satori/go.uuid"
-	"github.com/stretchr/testify/assert"
-)
-
-var (
-	c1 = uuid.NewV4()
-	c2 = uuid.NewV4()
-)
-
-func TestConsumerCurd(t *testing.T) {
-	//test3.com
-	param := []byte(`{
-	"username": "test_consumer",
-    "plugins": {
-        "key-auth": {
-            "key": "auth-one"
-        },
-        "limit-count": {
-            "count": 2,
-            "time_window": 60,
-            "rejected_code": 503,
-            "key": "remote_addr"
-        }
-    },
-	"desc": "test description"
-}`)
-
-	err := ConsumerCreate(param, c1.String())
-
-	assert := assert.New(t)
-	assert.Nil(err)
-
-	//get item
-	consumer, err := ConsumerItem(c1.String())
-	assert.Nil(err)
-	assert.Equal("test_consumer", consumer.Username)
-	assert.Equal(2, len(consumer.Plugins))
-
-	//duplicate username fail
-	param = []byte(`{
-	"username": "test_consumer",
-    "plugins": {
-        "key-auth": {
-            "key": "auth-one"
-        },
-        "limit-count": {
-            "count": 2,
-            "time_window": 60,
-            "rejected_code": 503,
-            "key": "remote_addr"
-        }
-    },
-	"desc": "test description"
-}`)
-
-	err = ConsumerCreate(param, c2.String())
-	assert.NotNil(err)
-	assert.Equal(errno.DuplicateUserName.Code, err.(*errno.ManagerError).Code)
-
-	// ok
-	param = []byte(`{
-	"username": "test_consumer2",
-    "plugins": {
-        "key-auth": {
-            "key": "auth-one"
-        }
-    },
-	"desc": "test description2"
-}`)
-
-	err = ConsumerCreate(param, c2.String())
-	assert.Nil(err)
-
-	//list
-	count, list, err := ConsumerList(2, 1, "")
-	assert.Equal(true, count >= 2)
-	assert.Equal(1, len(list))
-
-	//update
-	param = []byte(`{
-	"username": "test_consumer1",
-    "plugins": {
-        "key-auth": {
-            "key": "auth-one"
-        },
-        "limit-count": {
-            "count": 2,
-            "time_window": 60,
-            "rejected_code": 503,
-            "key": "remote_addr"
-        }
-    },
-	"desc": "test description"
-}`)
-
-	err = ConsumerUpdate(param, c1.String())
-	assert.Nil(err)
-
-	consumer, _ = ConsumerItem(c1.String())
-	assert.Equal("test_consumer1", consumer.Username)
-
-	//delete
-	err = ConsumerDelete(c1.String())
-	assert.Nil(err)
-
-	_, err = ConsumerItem(c1.String())
-	assert.Equal(errno.DBReadError.Code, err.(*errno.ManagerError).Code)
-
-	err = ConsumerDelete(c2.String())
-	assert.Nil(err)
-}
diff --git a/api/service/route_group_test.go b/api/service/route_group_test.go
deleted file mode 100644
index cb656b3..0000000
--- a/api/service/route_group_test.go
+++ /dev/null
@@ -1,120 +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 service
-
-import (
-	"testing"
-
-	uuid "github.com/satori/go.uuid"
-	"github.com/stretchr/testify/assert"
-)
-
-var gid = uuid.NewV4()
-var gid2 = uuid.NewV4()
-
-func TestCreateRouteGroup(t *testing.T) {
-	routeGroup := &RouteGroupDao{
-		Base:        Base{},
-		Name:        "route_group_test",
-		Description: "route_group_test",
-	}
-	routeGroup.ID = gid
-	// create ok
-	err := routeGroup.CreateRouteGroup()
-	as := assert.New(t)
-	as.Nil(err)
-}
-
-func TestGetRouteGroup(t *testing.T) {
-	// get group ok
-	as := assert.New(t)
-	getGroup := &RouteGroupDao{}
-	err, i := getGroup.FindRouteGroup(gid.String())
-	as.Nil(err)
-	as.Equal("route_group_test", getGroup.Name)
-	as.Equal(1, i)
-}
-
-func TestRouteGroupNameDuplicate(t *testing.T) {
-	// name duplicate
-	as := assert.New(t)
-	routeGroup2 := &RouteGroupDao{
-		Base:        Base{},
-		Name:        "route_group_test",
-		Description: "route_group_test",
-	}
-	routeGroup2.ID = gid2
-	err := routeGroup2.CreateRouteGroup()
-	as.NotNil(err)
-	// ok
-	routeGroup2.Name = "route_group_test2"
-	err = routeGroup2.CreateRouteGroup()
-	as.Nil(err)
-}
-
-func TestGetRouteGupList(t *testing.T) {
-	as := assert.New(t)
-	// list ok
-	routeGroups := []RouteGroupDao{}
-	routeGroup := &RouteGroupDao{}
-	err, i3 := routeGroup.GetRouteGroupList(&routeGroups, "", 1, 2)
-	as.Nil(err)
-	as.Equal(true, i3 >= 2)
-	as.Equal(2, len(routeGroups))
-}
-
-func TestUpdateRouteGroup(t *testing.T) {
-	as := assert.New(t)
-	// update ok
-	routeGroup := &RouteGroupDao{
-		Base:        Base{},
-		Name:        "route_group_test_update",
-		Description: "route_group_test_update",
-	}
-	routeGroup.ID = gid
-	err := routeGroup.UpdateRouteGroup()
-	as.Nil(err)
-}
-
-func TestDeleteRouteGroup(t *testing.T) {
-	as := assert.New(t)
-	routeGroup := &RouteGroupDao{
-		Base:        Base{},
-		Name:        "route_group_test_update",
-		Description: "route_group_test_update",
-	}
-	routeGroup.ID = gid
-	// delete ok
-	err := routeGroup.DeleteRouteGroup()
-	as.Nil(err)
-
-	deleteGroup := &RouteGroupDao{}
-	err, i2 := deleteGroup.FindRouteGroup(gid.String())
-	as.Nil(err)
-	as.Equal("", deleteGroup.Name)
-	as.Equal(0, i2)
-
-	routeGroup2 := &RouteGroupDao{
-		Base:        Base{},
-		Name:        "route_group_test",
-		Description: "route_group_test",
-	}
-	routeGroup2.ID = gid2
-	err = routeGroup2.DeleteRouteGroup()
-	as.Nil(err)
-}
diff --git a/api/service/route_test.go b/api/service/route_test.go
deleted file mode 100644
index 98bf3e0..0000000
--- a/api/service/route_test.go
+++ /dev/null
@@ -1,329 +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 service
-
-import (
-	"encoding/json"
-	"testing"
-
-	uuid "github.com/satori/go.uuid"
-	"github.com/stretchr/testify/assert"
-)
-
-func TestRedirectMarshal(t *testing.T) {
-	a := assert.New(t)
-	r := &Redirect{
-		HttpToHttps: true,
-		Code:        302,
-		Uri:         "/hello",
-	}
-	if result, err := json.Marshal(r); err != nil {
-		t.Error(err.Error())
-	} else {
-		h := make(map[string]interface{})
-		json.Unmarshal(result, &h)
-		a.Equal(1, len(h))
-		a.Equal(nil, h["code"])
-		a.Equal(true, h["http_to_https"])
-	}
-}
-
-func TestToApisixRequest_RediretPlugins(t *testing.T) {
-	rr := &RouteRequest{
-		ID:        "u guess a uuid",
-		Name:      "a special name",
-		Desc:      "any description",
-		Priority:  0,
-		Methods:   []string{"GET"},
-		Uris:      []string{},
-		Hosts:     []string{"www.baidu.com"},
-		Protocols: []string{"http", "https", "websocket"},
-		Redirect:  &Redirect{HttpToHttps: true, Code: 200, Uri: "/hello"},
-		Vars:      [][]string{},
-	}
-	ar := ToApisixRequest(rr)
-	a := assert.New(t)
-	a.Equal(1, len(ar.Plugins))
-	a.NotEqual(nil, ar.Plugins["redirect"])
-}
-
-func TestToApisixRequest_proxyRewrite(t *testing.T) {
-	nodes := make(map[string]int64)
-	nodes["127.0.0.1:8080"] = 100
-	upstream := &Upstream{
-		UType:   "roundrobin",
-		Nodes:   nodes,
-		Timeout: UpstreamTimeout{15, 15, 15},
-	}
-	to := "/hello"
-	upstreamPath := &UpstreamPath{To: to}
-	rr := &RouteRequest{
-		ID:           "u guess a uuid",
-		Name:         "a special name",
-		Desc:         "any description",
-		Priority:     0,
-		Methods:      []string{"GET"},
-		Uris:         []string{},
-		Hosts:        []string{"www.baidu.com"},
-		Protocols:    []string{"http", "https", "websocket"},
-		Redirect:     &Redirect{HttpToHttps: true, Code: 200, Uri: "/hello"},
-		Vars:         [][]string{},
-		Upstream:     upstream,
-		UpstreamPath: upstreamPath,
-	}
-	ar := ToApisixRequest(rr)
-	a := assert.New(t)
-	var pr ProxyRewrite
-	bytes, _ := json.Marshal(ar.Plugins["proxy-rewrite"])
-	json.Unmarshal(bytes, &pr)
-
-	a.Equal(2, len(ar.Plugins))
-	a.NotEqual(nil, ar.Plugins["redirect"])
-	a.Equal(to, pr.Uri)
-}
-
-func TestToApisixRequest_Vars(t *testing.T) {
-	rr := &RouteRequest{
-		ID:        "u guess a uuid",
-		Name:      "a special name",
-		Desc:      "any description",
-		Priority:  0,
-		Methods:   []string{"GET"},
-		Uris:      []string{},
-		Hosts:     []string{"www.baidu.com"},
-		Protocols: []string{"http", "https", "websocket"},
-		Redirect:  &Redirect{HttpToHttps: true, Code: 200, Uri: "/hello"},
-		Vars:      [][]string{},
-	}
-	ar := ToApisixRequest(rr)
-	a := assert.New(t)
-	b, err := json.Marshal(ar)
-	a.Equal(nil, err)
-
-	m := make(map[string]interface{})
-	err = json.Unmarshal(b, &m)
-	a.Equal(nil, err)
-	t.Log(m["vars"])
-	a.Equal(nil, m["vars"])
-}
-
-func TestToApisixRequest_Upstream(t *testing.T) {
-	nodes := make(map[string]int64)
-	nodes["127.0.0.1:8080"] = 100
-	upstream := &Upstream{
-		UType:   "roundrobin",
-		Nodes:   nodes,
-		Timeout: UpstreamTimeout{15, 15, 15},
-	}
-	rr := &RouteRequest{
-		ID:        "u guess a uuid",
-		Name:      "a special name",
-		Desc:      "any description",
-		Priority:  0,
-		Methods:   []string{"GET"},
-		Uris:      []string{},
-		Hosts:     []string{"www.baidu.com"},
-		Protocols: []string{"http", "https", "websocket"},
-		Redirect:  &Redirect{HttpToHttps: true, Code: 200, Uri: "/hello"},
-		Vars:      [][]string{},
-		Upstream:  upstream,
-	}
-	ar := ToApisixRequest(rr)
-	a := assert.New(t)
-	a.Equal("roundrobin", ar.Upstream.UType)
-	a.Equal(true, ar.Upstream.EnableWebsocket)
-}
-
-func TestToApisixRequest_UpstreamUnable(t *testing.T) {
-	nodes := make(map[string]int64)
-	nodes["127.0.0.1:8080"] = 100
-	upstream := &Upstream{
-		UType:   "roundrobin",
-		Nodes:   nodes,
-		Timeout: UpstreamTimeout{15, 15, 15},
-	}
-	rr := &RouteRequest{
-		ID:        "u guess a uuid",
-		Name:      "a special name",
-		Desc:      "any description",
-		Priority:  0,
-		Methods:   []string{"GET"},
-		Uris:      []string{},
-		Hosts:     []string{"www.baidu.com"},
-		Protocols: []string{"http", "https"},
-		Redirect:  &Redirect{HttpToHttps: true, Code: 200, Uri: "/hello"},
-		Vars:      [][]string{},
-		Upstream:  upstream,
-	}
-	ar := ToApisixRequest(rr)
-	a := assert.New(t)
-	a.Equal("roundrobin", ar.Upstream.UType)
-	a.Equal(false, ar.Upstream.EnableWebsocket)
-}
-
-// no upstream
-func TestApisixRouteResponse_Parse(t *testing.T) {
-	a := assert.New(t)
-	plugins := make(map[string]interface{})
-	redirect := &Redirect{
-		Code: 302,
-		Uri:  "/foo",
-	}
-	plugins["redirect"] = redirect
-	arr := &ApisixRouteResponse{
-		Action: "get",
-		Node: &Node{
-			Value: Value{
-				Id:       "",
-				Name:     "",
-				Desc:     "",
-				Priority: 0,
-				Methods:  []string{"GET"},
-				Uris:     []string{"/*"},
-				Hosts:    []string{"www.baidu.com"},
-				Vars:     [][]string{},
-				Upstream: nil,
-				Plugins:  plugins,
-			},
-		},
-	}
-	_, err := arr.Parse()
-	a.Equal(nil, err)
-}
-
-// parse from params to RouteRequest
-func TestRouteRequest_Parse(t *testing.T) {
-	a := assert.New(t)
-	param := []byte(`{
-		 "name": "API 名称",
-		 "protocols": [
-			 "http",
-			 "https"
-		 ],
-		 "hosts": [
-			 "www.baidu.com"
-		 ],
-		 "methods": [
-			 "GET",
-			 "HEAD",
-			 "POST",
-			 "PUT",
-			 "DELETE",
-			 "OPTIONS",
-			 "PATCH"
-		 ],
-		 "redirect": {
-			 "code": 302,
-			 "uri": "11111"
-		 },
-		 "vars": [],
-		 "script": {
-			 "rule": {},
-			 "conf": {}
-		 }
-	 }`)
-	routeRequest := &RouteRequest{}
-	err := routeRequest.Parse(param)
-	a.Nil(err)
-	a.Equal("API 名称", routeRequest.Name)
-	a.Equal(int64(0), routeRequest.Priority)
-	a.Equal(2, len(routeRequest.Script))
-	a.Equal("/*", routeRequest.Uris[0])
-}
-
-// parse from RouteRequest and ApisixRouteRequest to Route
-func TestRoute_Parse(t *testing.T) {
-	a := assert.New(t)
-	rrb := []byte(`{"name":"API 名称2","methods":["GET","HEAD","POST","PUT","DELETE","OPTIONS","PATCH"],"uris":["/*"],"hosts":["www.baidu.com"],"protocols":["http","https"],"redirect":{"code":302,"uri":"11111"},"plugins":null}`)
-	routeRequest := &RouteRequest{}
-	json.Unmarshal(rrb, routeRequest)
-	arrb := []byte(`{"priority":0,"methods":["GET","HEAD","POST","PUT","DELETE","OPTIONS","PATCH"],"uris":["/*"],"hosts":["www.baidu.com"],"plugins":{"redirect":{"code":302,"uri":"11111"}}, "script":{
-    "rule":{
-        "root": "11-22-33-44",
-        "11-22-33-44":[
-            [
-                "code == 503",
-                "yy-uu-ii-oo"
-            ],
-            [
-                "",
-                "vv-cc-xx-zz"
-            ]
-        ]
-    },
-    "conf":{
-        "11-22-33-44":{
-            "name": "limit-count",
-            "conf": {
-                "count":2,
-                "time_window":60,
-                "rejected_code":503,
-                "key":"remote_addr"
-            }
-        },
-        "yy-uu-ii-oo":{
-            "name": "response-rewrite",
-            "conf": {
-                "body":{"code":"ok","message":"request has been limited."},
-                "headers":{
-                    "X-limit-status": "limited"
-                }
-            }
-        },
-        "vv-cc-xx-zz":{
-            "name": "response-rewrite",
-            "conf": {
-                "body":{"code":"ok","message":"normal request"},
-                "headers":{
-                    "X-limit-status": "normal"
-                }
-            }
-        }
-    }
-} }`)
-	arr := &ApisixRouteRequest{}
-	json.Unmarshal(arrb, arr)
-
-	rd := &Route{}
-	err := rd.Parse(routeRequest, arr)
-	a.Nil(err)
-}
-
-// parse Route
-func TestToRoute(t *testing.T) {
-	a := assert.New(t)
-	b1 := []byte(`{"name":"API 名称2","methods":["GET","HEAD","POST","PUT","DELETE","OPTIONS","PATCH"],"uris":["/*"],"hosts":["www.baidu.com"],"protocols":["http","https"],"redirect":{"code":302,"uri":"11111"},"plugins":null}`)
-	rr := &RouteRequest{}
-	err := json.Unmarshal(b1, &rr)
-	a.Nil(err)
-
-	b2 := []byte(`{"priority":0,"methods":["GET","HEAD","POST","PUT","DELETE","OPTIONS","PATCH"],"uris":["/*"],"hosts":["www.baidu.com"],"plugins":{"redirect":{"code":302,"uri":"11111"}},"script":"function(vars, opts) return vars[\"arg_key\"] == \"a\" or vars[\"arg_key\"] == \"b\" end"}`)
-	arr := &ApisixRouteRequest{}
-	err = json.Unmarshal(b2, &arr)
-	a.Nil(err)
-
-	b3 := []byte(`{"action":"set","node":{"value":{"id":"","name":"","priority":0,"methods":["GET","HEAD","POST","PUT","DELETE","OPTIONS","PATCH"],"uris":["/*"],"hosts":["www.baidu.com"],"vars":null,"plugins":{"redirect":{"code":302,"ret_code":302,"uri":"11111"}}},"modifiedIndex":75}}`)
-	arp := &ApisixRouteResponse{}
-	err = json.Unmarshal(b3, &arp)
-	a.Nil(err)
-
-	u4 := uuid.NewV4()
-	route, err := ToRoute(rr, arr, u4, arp)
-	a.Nil(err)
-	t.Log(route.Uris)
-	a.Equal("[\"/*\"]", route.Uris)
-}
diff --git a/api/service/ssl_test.go b/api/service/ssl_test.go
deleted file mode 100644
index 2134bb1..0000000
--- a/api/service/ssl_test.go
+++ /dev/null
@@ -1,352 +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 service
-
-import (
-	"strings"
-	"testing"
-
-	"github.com/apisix/manager-api/errno"
-	uuid "github.com/satori/go.uuid"
-	"github.com/stretchr/testify/assert"
-)
-
-var (
-	u1 = uuid.NewV4()
-	u2 = uuid.NewV4()
-)
-
-func TestSslParseCert(t *testing.T) {
-	ssl, err := ParseCert("", "")
-
-	assert := assert.New(t)
-	assert.Nil(ssl)
-	assert.Equal("invalid certificate", err.Error())
-
-	//KeyPair fail
-
-	cert := `-----BEGIN CERTIFICATE-----
-MIIEWjCCAsKgAwIBAgIRAMLLNCKEvgEQL22Hpox6E1kwDQYJKoZIhvcNAQELBQAw
-fzEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMSowKAYDVQQLDCFqdW54
-dWNoZW5AanVueHVkZUFpciAoanVueHUgY2hlbikxMTAvBgNVBAMMKG1rY2VydCBq
-dW54dWNoZW5AanVueHVkZUFpciAoanVueHUgY2hlbikwHhcNMTkwNjAxMDAwMDAw
-WhcNMzAwNjA5MTA0MjA1WjBVMScwJQYDVQQKEx5ta2NlcnQgZGV2ZWxvcG1lbnQg
-Y2VydGlmaWNhdGUxKjAoBgNVBAsMIWp1bnh1Y2hlbkBqdW54dWRlQWlyIChqdW54
-dSBjaGVuKTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL2lg+vzHkRI
-Cs8PHv6UVxXFbrL6wlsdurOICkW5daKUJyzUZQZl11CK9SWOk8vAc7j3pQ7Mz15r
-hfQB558WHzI/XXbZ1NrZrTpLaL0fWW5n4hIE8EbYf3Hy/xM8gRUXsWMEexq2WC/R
-PfTCQIZ85vUSANS72E5rHdba3Y5IMr8bn/NUg1sm2LxZQmZV6tBOpYnibyj7bXxw
-8kxr4w+B/5jDBPmwL59bdoatEs1FjdHzz+fbW1K4NdHZZEotYqkQhCS09JnwGswd
-Ariy+Is44kt/gtw7nVWmuV/eQaxPEHVE4Bwvdmv11IsPsj6hif23gXjXLIHx66CY
-/S4I/P0allkCAwEAAaN7MHkwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsG
-AQUFBwMBMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUVPhGyY/h6etoAqzb298k
-JGJzx1wwIwYDVR0RBBwwGoIJdGVzdDMuY29tgg13d3cudGVzdDMuY29tMA0GCSqG
-SIb3DQEBCwUAA4IBgQCgb5wOMzkD1/tgrjwE7Cj1NvX7/p/JIQVVtvtnnypyXGNn
-VL+q4oB9WzvOvMcTCiKKHqg9jCiu/KFFHy7nRzj7KPhU/o9M7qLNwLJjfUOtPYUm
-rS62kEXlj5L5+UJjiGABGfLllxMwwTkAFbdSUSB1awzoafPn5+g+qABXgkF/EN2I
-+IJcJCqg3IO30n4MMhqNx3IbqIohD3p5GzjQqnuQSrC/HJEsUuIlMCHPJ1GVbbrd
-RnSySMcbv2jThP53JVIe+0HHvcujb2pDQ4RcCSaN3OXaZDYVqoSR04+amotGwiWO
-DY/4LTWFJkfoWnv1kg2/AllMpsXB+1u+O+x6qWzBw2hXP5AM+8KIoJ2/Mb13TsN9
-qhrGep+SfhjARH068ZjaS2zQC2Uvc+SrEGXfITPIkstRELxIV9Lmjl9lwpAOJrte
-4TDjYhBS20j6mt3dUyEBnPfkpcOeLYZNS1sK66MRfzJ9MowdTcWyvMzFHjSjfWPY
-+4scQdmkFkCulnzylak=
------END CERTIFICATE-----`
-	key := `-----BEGIN PRIVATE KEY-----
-MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC25tQs8GRxdWUR
-c4kjhmJmrxQgCcoN4VTHyBbdbnZFPgxCULAr/2e54ooatMWh9DEdrgpi3EfQXqDV
-okzKrSfJVZqmS1qOcgaSkgz5/puKcF31bXUgSVw1qGEjXbpQcyzZp95pPaErXCq3
-7bKST5d0TO8asNebON+jZZkpa5NA+qFOOWdx0Y6UWG0G/RzhYyRRU9B6+SBwOLa8
-c9+07vxjjAOXfr5Terp0lS9xNOVcjnHA48XPq2y8cJstbVjQI8Ls1HlzJoeJz+lt
-FFxd8nMQ30NoJYoVXewUEjuTibQdEpUY8m5zuNqYKOax4McpoTouKl2BWIuWr10Y
-Wrtw9XWlAgMBAAECggEAdoDsbAl9Kr3jNAFlk2zYiKtbIL72+TNL2P1dQy701jwz
-eSwKWRdsP1X2IQOLITm0MQS4mgEbTnhhQMmdc5vpMVuTjbc4/x4GACU83yUF5haT
-6hZ3Uun1IpbsCRwLQWC+aG+JfSp/KDbZPr51erKy8JmAOgzmRR3+WEHVkK6wg+JF
-qDha7Gnq2xgzmutGLBUb9BFgL7bbNyf3V4d+HbgYPjQossfpLnTIrsmKce36r5U8
-pF6Uf69EUs34N9w98E6mEGY12nY4jOKZMeRPR1FIGGK7Y3+7fkd2+pYF00s7uSUq
-/j8DdxxykqvZkE1lBZJBwxk9Ty4PBq2lNKdq6pXtAQKBgQDu12vVuenRCJEsK2FY
-puYlfoDiQpIYzK9Bme+eDsPcVyOQ9q+Tf4QASZN81InQsanQ2ovcbmSpB52/ZvjU
-rVX7RnIEcZ6jB1VUcCU/QOEg0kqTkCo3SfyeawF8iPyuLSbb5ZBufFMq6nOyOWco
-hg4EqQIg3rcKw3lW8NT6DqqRxQKBgQDECpuhfEMYUslfDlSbS8V/vSXjD2xzRFt3
-SL87xQXwZOLRPYiLdRGb/WP2L/PGE8K1XUMz/geeFeAdrzRxJ1JtCn/K0UyMxSnw
-TJEm6CFfsOJXOq4yC5gosNYw3xBc9NKtsGLrAlWOBLPdeO1wdrM6BYfs6AP3X49r
-67Y7AujyYQKBgQCMSV//c2nQ6/VJOlm9VprL3xgYzf0+L8uo/p/t+MI2Q8CSPzM1
-sap4+L52jeg8+n3CPPv1h6n8Vorjh7oUQZPFOcVyssH5BC+snwphstwJCTvgnMcP
-HpgQ/M0sttGkBMVUV+yT2NaI2JkIUAs1lDfbqOGlKOvemJ5G4MJX9hFd+QKBgQDC
-oe2F1EMg4QCAWU/yprW8buQwnF2FyzYsJZOHGcMdumveZYMtQdtrzZTzFQSngXLs
-cV2JPwn9D6bkkdA1D18sVyItEMM5d359zubFg+2ufYUaKW5MzWoR7A+bkbtDLuYD
-/30V6clbKJwSpD7IS3EBiAA9WtSlQsC32tuflvIDwQKBgAqJAqrempkVGA2rvTX5
-7uWCAiqUKX859kmIuQV9RTQ7qfQRWhckuAjeTdTq6tWKFkzaVaRCXb+tRi7eqVsz
-R/us0LXwHez2LacSVudO7g/LMY3yDxVL2iFLVA/x1FBqjAgjWAEfnc7PmZSK2B3g
-fpf+iWh15t6I4nuyEmMFmtVr
------END PRIVATE KEY-----`
-	ssl1, err := ParseCert(cert, key)
-
-	assert.Nil(ssl1)
-	assert.Equal("key and cert don't match", err.Error())
-
-	// ip
-
-	cert = `-----BEGIN CERTIFICATE-----
-MIIERjCCAq6gAwIBAgIRALI5vYiIHdtNd4ocLsZ9i/IwDQYJKoZIhvcNAQELBQAw
-fzEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMSowKAYDVQQLDCFqdW54
-dWNoZW5AanVueHVkZUFpciAoanVueHUgY2hlbikxMTAvBgNVBAMMKG1rY2VydCBq
-dW54dWNoZW5AanVueHVkZUFpciAoanVueHUgY2hlbikwHhcNMTkwNjAxMDAwMDAw
-WhcNMzAwNjAzMDEyODQ5WjBVMScwJQYDVQQKEx5ta2NlcnQgZGV2ZWxvcG1lbnQg
-Y2VydGlmaWNhdGUxKjAoBgNVBAsMIWp1bnh1Y2hlbkBqdW54dWRlQWlyIChqdW54
-dSBjaGVuKTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALbm1CzwZHF1
-ZRFziSOGYmavFCAJyg3hVMfIFt1udkU+DEJQsCv/Z7niihq0xaH0MR2uCmLcR9Be
-oNWiTMqtJ8lVmqZLWo5yBpKSDPn+m4pwXfVtdSBJXDWoYSNdulBzLNmn3mk9oStc
-KrftspJPl3RM7xqw15s436NlmSlrk0D6oU45Z3HRjpRYbQb9HOFjJFFT0Hr5IHA4
-trxz37Tu/GOMA5d+vlN6unSVL3E05VyOccDjxc+rbLxwmy1tWNAjwuzUeXMmh4nP
-6W0UXF3ycxDfQ2glihVd7BQSO5OJtB0SlRjybnO42pgo5rHgxymhOi4qXYFYi5av
-XRhau3D1daUCAwEAAaNnMGUwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsG
-AQUFBwMBMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUVPhGyY/h6etoAqzb298k
-JGJzx1wwDwYDVR0RBAgwBocEfwAAATANBgkqhkiG9w0BAQsFAAOCAYEAowBgpVs+
-pZ4PeT2mVx79thwh02AzinmNbMQMboHK9RaRSZHxLHiVjY7LR1qn5zjLcUcZHel7
-96bka6vlufYzWHSjtKwAchDVVPVK6tzpfHnpLzNLShx0LjIl0EvjrHv5mHIx8R1T
-WKQGxwdTzIxGMgrziuTNc1LvS+yoJElWe07PeRSdSPKUNKQQWqaukzqw3JZaLQkm
-8MaqrzQwNEsCbeojz/ME3e+SzpSsqXgW0x5Og4TyEnIen/q7OzmRzrkHR40Hu+j4
-aW287l3ywIU0pGl/sY2bmyOYCgpZ5w2utfdd7167Doy4vHFKJD3GuN3i+W1f7PyF
-gdUFUQTr6HO4sfQXeZoitzl2Dvr360sb9BBDLAoFiV6J5bAV4algVz45kSpJ7VIm
-pfS8+BUcZHWbn35M9mx2dyoNvIajcET545D60wcttqw4TRh4ljsE69GCU1swiwxH
-hXSkf958injuwYuxv0b1k9qGm6znJc+tRcn35H6x0ff/HwuBIj3TsEXo
------END CERTIFICATE-----`
-	key = `-----BEGIN PRIVATE KEY-----
-MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC25tQs8GRxdWUR
-c4kjhmJmrxQgCcoN4VTHyBbdbnZFPgxCULAr/2e54ooatMWh9DEdrgpi3EfQXqDV
-okzKrSfJVZqmS1qOcgaSkgz5/puKcF31bXUgSVw1qGEjXbpQcyzZp95pPaErXCq3
-7bKST5d0TO8asNebON+jZZkpa5NA+qFOOWdx0Y6UWG0G/RzhYyRRU9B6+SBwOLa8
-c9+07vxjjAOXfr5Terp0lS9xNOVcjnHA48XPq2y8cJstbVjQI8Ls1HlzJoeJz+lt
-FFxd8nMQ30NoJYoVXewUEjuTibQdEpUY8m5zuNqYKOax4McpoTouKl2BWIuWr10Y
-Wrtw9XWlAgMBAAECggEAdoDsbAl9Kr3jNAFlk2zYiKtbIL72+TNL2P1dQy701jwz
-eSwKWRdsP1X2IQOLITm0MQS4mgEbTnhhQMmdc5vpMVuTjbc4/x4GACU83yUF5haT
-6hZ3Uun1IpbsCRwLQWC+aG+JfSp/KDbZPr51erKy8JmAOgzmRR3+WEHVkK6wg+JF
-qDha7Gnq2xgzmutGLBUb9BFgL7bbNyf3V4d+HbgYPjQossfpLnTIrsmKce36r5U8
-pF6Uf69EUs34N9w98E6mEGY12nY4jOKZMeRPR1FIGGK7Y3+7fkd2+pYF00s7uSUq
-/j8DdxxykqvZkE1lBZJBwxk9Ty4PBq2lNKdq6pXtAQKBgQDu12vVuenRCJEsK2FY
-puYlfoDiQpIYzK9Bme+eDsPcVyOQ9q+Tf4QASZN81InQsanQ2ovcbmSpB52/ZvjU
-rVX7RnIEcZ6jB1VUcCU/QOEg0kqTkCo3SfyeawF8iPyuLSbb5ZBufFMq6nOyOWco
-hg4EqQIg3rcKw3lW8NT6DqqRxQKBgQDECpuhfEMYUslfDlSbS8V/vSXjD2xzRFt3
-SL87xQXwZOLRPYiLdRGb/WP2L/PGE8K1XUMz/geeFeAdrzRxJ1JtCn/K0UyMxSnw
-TJEm6CFfsOJXOq4yC5gosNYw3xBc9NKtsGLrAlWOBLPdeO1wdrM6BYfs6AP3X49r
-67Y7AujyYQKBgQCMSV//c2nQ6/VJOlm9VprL3xgYzf0+L8uo/p/t+MI2Q8CSPzM1
-sap4+L52jeg8+n3CPPv1h6n8Vorjh7oUQZPFOcVyssH5BC+snwphstwJCTvgnMcP
-HpgQ/M0sttGkBMVUV+yT2NaI2JkIUAs1lDfbqOGlKOvemJ5G4MJX9hFd+QKBgQDC
-oe2F1EMg4QCAWU/yprW8buQwnF2FyzYsJZOHGcMdumveZYMtQdtrzZTzFQSngXLs
-cV2JPwn9D6bkkdA1D18sVyItEMM5d359zubFg+2ufYUaKW5MzWoR7A+bkbtDLuYD
-/30V6clbKJwSpD7IS3EBiAA9WtSlQsC32tuflvIDwQKBgAqJAqrempkVGA2rvTX5
-7uWCAiqUKX859kmIuQV9RTQ7qfQRWhckuAjeTdTq6tWKFkzaVaRCXb+tRi7eqVsz
-R/us0LXwHez2LacSVudO7g/LMY3yDxVL2iFLVA/x1FBqjAgjWAEfnc7PmZSK2B3g
-fpf+iWh15t6I4nuyEmMFmtVr
------END PRIVATE KEY-----`
-	ssl2, err := ParseCert(cert, key)
-
-	assert.Nil(err)
-	assert.Equal("[\"127.0.0.1\"]", ssl2.Snis)
-
-	// v1 multi domain
-	cert = `-----BEGIN CERTIFICATE-----
-MIICcTCCAdoCCQDQoPEll/bQizANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJD
-TjEOMAwGA1UECAwFbXlrZXkxDjAMBgNVBAcMBW15a2V5MQ4wDAYDVQQKDAVteWtl
-eTEOMAwGA1UECwwFbXlrZXkxDjAMBgNVBAMMBWEuY29tMQ4wDAYDVQQDDAViLmNv
-bTEOMAwGA1UEAwwFYy5jb20wHhcNMjAwNjE3MDk1MDA0WhcNMzAwNjE1MDk1MDA0
-WjB9MQswCQYDVQQGEwJDTjEOMAwGA1UECAwFbXlrZXkxDjAMBgNVBAcMBW15a2V5
-MQ4wDAYDVQQKDAVteWtleTEOMAwGA1UECwwFbXlrZXkxDjAMBgNVBAMMBWEuY29t
-MQ4wDAYDVQQDDAViLmNvbTEOMAwGA1UEAwwFYy5jb20wgZ8wDQYJKoZIhvcNAQEB
-BQADgY0AMIGJAoGBANHMrKlfFzJbyYuD0YveK2mOOXR9zXi+vC5lW6RaoyKjx5AL
-yIXQWXURGVnxw1+xbmxWN1MXZyAP7eJYFPa0PIJvW0kbyHkJt/TrCyBLVOqpTqvE
-kDAIde9Fx83556sXD43Oq93lyBraXmR+fXuoLxJQQLhALW1tOg1X3VrxKYXNAgMB
-AAEwDQYJKoZIhvcNAQELBQADgYEAwJ7qV0Tj6JXR035ySVSBG1KBF19DVmMYRKdO
-SAU1j437q+ktTcEWSA0CkH6rg53tP4V1h0tzdhCxisivYynngjtEcZfsrwdIrsSg
-cmOBZ+KTRyZ2fLgH4F8Naz5hBrwmR8ZIG46feVOV/swJzz4BNaXGj1oATWkLMA3c
-Sf0G+aI=
------END CERTIFICATE-----`
-	key = `-----BEGIN RSA PRIVATE KEY-----
-MIICXAIBAAKBgQDRzKypXxcyW8mLg9GL3itpjjl0fc14vrwuZVukWqMio8eQC8iF
-0Fl1ERlZ8cNfsW5sVjdTF2cgD+3iWBT2tDyCb1tJG8h5Cbf06wsgS1TqqU6rxJAw
-CHXvRcfN+eerFw+Nzqvd5cga2l5kfn17qC8SUEC4QC1tbToNV91a8SmFzQIDAQAB
-AoGBAJIL/y4wqf8+ckES1G6fjG0AuvJjGQQzEuDhYjg5eFMG3EdkTIUKkxuxeYpp
-iG43H/1+zyiipAFn1Vu5oW5T7cJEgC1YA39dERT605S5BrNWWHoZsgH+qmLoq7X+
-jXMlmCagwlgwhUWMU2M1/LUbAl42384dK9u3EwcCgS//sFuBAkEA6mK52/Z03PB3
-0sS14eN7xFl96yc/NcneJ7Vy5APT0KGLo0j2S8gpOVW9EYrrzDzWgQ8FLIeed2Zw
-Z4ATksgRXQJBAOUlh5VJkyMdMiDEeJgK9QKtJkuiLZFAzZiWAUqjvSG2j8tWX/iN
-veI1sXCPyQSKoWPN74+23KWL+nW+mUzkzzECQFf+UIB/+keoD5QVPaNcX+7LGjba
-OSTccIa/3C42MaM1wtK+ZZj1wGRCCAU5/mRiwrUZCnw5PgjdcH2q265TZhECQASY
-JgnGOd8AXNrvVYOm5JazJgtqKwO4iua+SzRV6Bre8C8hgjcXkHESpoYdO+iNZwL7
-RAxbnDzte44UzjoOdGECQGtkrBffiyMaQv6LM/6Fa5TXHb1kPtLGIjFSygR3eTYI
-gHG78R5ac0dzhbyKaOo6cbj7CJVkbBh4BNW94tBZE/I=
------END RSA PRIVATE KEY-----`
-
-	ssl3, err := ParseCert(cert, key)
-
-	assert.Nil(err)
-	assert.Equal("[\"a.com\",\"b.com\",\"c.com\"]", ssl3.Snis)
-}
-
-func TestSslCurd(t *testing.T) {
-	//test3.com
-	param := []byte(`{
-		"cert": "-----BEGIN CERTIFICATE-----\nMIIEWjCCAsKgAwIBAgIRAMLLNCKEvgEQL22Hpox6E1kwDQYJKoZIhvcNAQELBQAw\nfzEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMSowKAYDVQQLDCFqdW54\ndWNoZW5AanVueHVkZUFpciAoanVueHUgY2hlbikxMTAvBgNVBAMMKG1rY2VydCBq\ndW54dWNoZW5AanVueHVkZUFpciAoanVueHUgY2hlbikwHhcNMTkwNjAxMDAwMDAw\nWhcNMzAwNjA5MTA0MjA1WjBVMScwJQYDVQQKEx5ta2NlcnQgZGV2ZWxvcG1lbnQg\nY2VydGlmaWNhdGUxKjAoBgNVBAsMIWp1bnh1Y2hlbkBqdW54dWRlQWlyIChqdW54\ndSBjaGVuKTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL2l [...]
-		"key": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC9pYPr8x5ESArP\nDx7+lFcVxW6y+sJbHbqziApFuXWilCcs1GUGZddQivUljpPLwHO496UOzM9ea4X0\nAeefFh8yP1122dTa2a06S2i9H1luZ+ISBPBG2H9x8v8TPIEVF7FjBHsatlgv0T30\nwkCGfOb1EgDUu9hOax3W2t2OSDK/G5/zVINbJti8WUJmVerQTqWJ4m8o+218cPJM\na+MPgf+YwwT5sC+fW3aGrRLNRY3R88/n21tSuDXR2WRKLWKpEIQktPSZ8BrMHQK4\nsviLOOJLf4LcO51Vprlf3kGsTxB1ROAcL3Zr9dSLD7I+oYn9t4F41yyB8eugmP0u\nCPz9GpZZAgMBAAECggEAZ2+8SVgb/QASLSdBL3d3HB/IJgSRNyM67qrXd [...]
-	}`)
-
-	err := SslCreate(param, u1.String())
-
-	assert := assert.New(t)
-	assert.Nil(err)
-
-	//get item
-	ssl, err := SslItem(u1.String())
-	assert.Nil(err)
-	assert.Equal(uint64(1), ssl.Status)
-	assert.Equal(2, len(ssl.Snis))
-	for _, dm := range ssl.Snis {
-		assert.Equal(true, strings.Contains(dm, "test3.com"))
-	}
-
-	//test3.com duplicate
-	param = []byte(`{
-		"cert": "-----BEGIN CERTIFICATE-----\nMIIEWjCCAsKgAwIBAgIRAMLLNCKEvgEQL22Hpox6E1kwDQYJKoZIhvcNAQELBQAw\nfzEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMSowKAYDVQQLDCFqdW54\ndWNoZW5AanVueHVkZUFpciAoanVueHUgY2hlbikxMTAvBgNVBAMMKG1rY2VydCBq\ndW54dWNoZW5AanVueHVkZUFpciAoanVueHUgY2hlbikwHhcNMTkwNjAxMDAwMDAw\nWhcNMzAwNjA5MTA0MjA1WjBVMScwJQYDVQQKEx5ta2NlcnQgZGV2ZWxvcG1lbnQg\nY2VydGlmaWNhdGUxKjAoBgNVBAsMIWp1bnh1Y2hlbkBqdW54dWRlQWlyIChqdW54\ndSBjaGVuKTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL2l [...]
-		"key": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC9pYPr8x5ESArP\nDx7+lFcVxW6y+sJbHbqziApFuXWilCcs1GUGZddQivUljpPLwHO496UOzM9ea4X0\nAeefFh8yP1122dTa2a06S2i9H1luZ+ISBPBG2H9x8v8TPIEVF7FjBHsatlgv0T30\nwkCGfOb1EgDUu9hOax3W2t2OSDK/G5/zVINbJti8WUJmVerQTqWJ4m8o+218cPJM\na+MPgf+YwwT5sC+fW3aGrRLNRY3R88/n21tSuDXR2WRKLWKpEIQktPSZ8BrMHQK4\nsviLOOJLf4LcO51Vprlf3kGsTxB1ROAcL3Zr9dSLD7I+oYn9t4F41yyB8eugmP0u\nCPz9GpZZAgMBAAECggEAZ2+8SVgb/QASLSdBL3d3HB/IJgSRNyM67qrXd [...]
-	}`)
-
-	err = SslCreate(param, u2.String())
-	assert.NotNil(err)
-	assert.Equal(errno.DuplicateSslCert.Code, err.(*errno.ManagerError).Code)
-
-	//a.com b.com fail
-	param = []byte(`{
-		"cert": "-----BEGIN CERTIFICATE-----\nMIICcTCCAdoCCQDQoPEll/bQizANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJD\nTjEOMAwGA1UECAwFbXlrZXkxDjAMBgNVBAcMBW15a2V5MQ4wDAYDVQQKDAVteWtl\neTEOMAwGA1UECwwFbXlrZXkxDjAMBgNVBAMMBWEuY29tMQ4wDAYDVQQDDAViLmNv\nbTEOMAwGA1UEAwwFYy5jb20wHhcNMjAwNjE3MDk1MDA0WhcNMzAwNjE1MDk1MDA0\nWjB9MQswCQYDVQQGEwJDTjEOMAwGA1UECAwFbXlrZXkxDjAMBgNVBAcMBW15a2V5\nMQ4wDAYDVQQKDAVteWtleTEOMAwGA1UECwwFbXlrZXkxDjAMBgNVBAMMBWEuY29t\nMQ4wDAYDVQQDDAViLmNvbTEOMAwGA1UEAwwFYy5jb20wgZ8wDQYJKoZI [...]
-		"key": "-----BEGIN RSA PRIVATE KEY-----\nMIICXAIBAAKBgQDRzKypXxcyW8mLg9GL3itpjjl0fc14vrwuZVukWqMio8eQC8iF\n0Fl1ERlZ8cNfsW5sVjdTF2cgD+3iWBT2tDyCb1tJG8h5Cbf06wsgS1TqqU6rxJAw\nCHXvRcfN+eerFw+Nzqvd5cga2l5kfn17qC8SUEC4QC1tbToNV91a8SmFzQIDAQAB\nAoGBAJIL/y4wqf8+ckES1G6fjG0AuvJjGQQzEuDhYjg5eFMG3EdkTIUKkxuxeYpp\niG43H/1+zyiipAFn1Vu5oW5T7cJEgC1YA39dERT605S5BrNWWHoZsgH+qmLoq7X+\njXMlmCagwlgwhUWMU2M1/LUbAl42384dK9u3EwcCgS//sFuBAkEA6mK52/Z03PB3\n0sS14eN7xFl96yc/NcneJ7Vy5APT0KGLo0j2S8gpOVW9EYrrzDzWg [...]
-	}`)
-
-	err = SslCreate(param, u1.String())
-	assert.NotNil(err)
-	assert.Equal(errno.DBWriteError.Code, err.(*errno.ManagerError).Code)
-
-	//a.com b.com  ok
-	param = []byte(`{
-		"cert": "-----BEGIN CERTIFICATE-----\nMIICcTCCAdoCCQDQoPEll/bQizANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJD\nTjEOMAwGA1UECAwFbXlrZXkxDjAMBgNVBAcMBW15a2V5MQ4wDAYDVQQKDAVteWtl\neTEOMAwGA1UECwwFbXlrZXkxDjAMBgNVBAMMBWEuY29tMQ4wDAYDVQQDDAViLmNv\nbTEOMAwGA1UEAwwFYy5jb20wHhcNMjAwNjE3MDk1MDA0WhcNMzAwNjE1MDk1MDA0\nWjB9MQswCQYDVQQGEwJDTjEOMAwGA1UECAwFbXlrZXkxDjAMBgNVBAcMBW15a2V5\nMQ4wDAYDVQQKDAVteWtleTEOMAwGA1UECwwFbXlrZXkxDjAMBgNVBAMMBWEuY29t\nMQ4wDAYDVQQDDAViLmNvbTEOMAwGA1UEAwwFYy5jb20wgZ8wDQYJKoZI [...]
-		"key": "-----BEGIN RSA PRIVATE KEY-----\nMIICXAIBAAKBgQDRzKypXxcyW8mLg9GL3itpjjl0fc14vrwuZVukWqMio8eQC8iF\n0Fl1ERlZ8cNfsW5sVjdTF2cgD+3iWBT2tDyCb1tJG8h5Cbf06wsgS1TqqU6rxJAw\nCHXvRcfN+eerFw+Nzqvd5cga2l5kfn17qC8SUEC4QC1tbToNV91a8SmFzQIDAQAB\nAoGBAJIL/y4wqf8+ckES1G6fjG0AuvJjGQQzEuDhYjg5eFMG3EdkTIUKkxuxeYpp\niG43H/1+zyiipAFn1Vu5oW5T7cJEgC1YA39dERT605S5BrNWWHoZsgH+qmLoq7X+\njXMlmCagwlgwhUWMU2M1/LUbAl42384dK9u3EwcCgS//sFuBAkEA6mK52/Z03PB3\n0sS14eN7xFl96yc/NcneJ7Vy5APT0KGLo0j2S8gpOVW9EYrrzDzWg [...]
-	}`)
-
-	err = SslCreate(param, u2.String())
-	assert.Nil(err)
-
-	//list
-	count, list, err := SslList(2, 1, -1, 0, 0, "", "asc")
-	assert.Equal(true, count >= 2)
-	assert.Equal(1, len(list))
-
-	// check sni ssl exist
-	param = []byte(`[
-		"test3.com",
-		"www.test3.com",
-		"a.com"
-	]`)
-
-	err = CheckSniExists(param)
-	assert.Nil(err)
-
-	// check sni ssl exist
-	param = []byte(`[
-		"test3.com",
-		"a.test3.com",
-		"b.com"
-	]`)
-	err = CheckSniExists(param)
-	assert.NotNil(err)
-
-	// patch
-	param = []byte(`{
-		"status": 0
-	}`)
-	err = SslPatch(param, u1.String())
-	assert.Nil(err)
-
-	ssl, err = SslItem(u1.String())
-	assert.Equal(uint64(0), ssl.Status)
-
-	// check sni ssl exist  --- disable test3
-	param = []byte(`[
-		"test3.com",
-		"www.test3.com",
-		"a.com"
-	]`)
-
-	err = CheckSniExists(param)
-	assert.NotNil(err)
-
-	param = []byte(`[
-		"a.com"
-	]`)
-	err = CheckSniExists(param)
-	assert.Nil(err)
-
-	//update
-	param = []byte(`{
-		"cert": "-----BEGIN CERTIFICATE-----\nMIIEWzCCAsOgAwIBAgIQDYoN+el2w074sSGlyKVZFTANBgkqhkiG9w0BAQsFADB/\nMR4wHAYDVQQKExVta2NlcnQgZGV2ZWxvcG1lbnQgQ0ExKjAoBgNVBAsMIWp1bnh1\nY2hlbkBqdW54dWRlQWlyIChqdW54dSBjaGVuKTExMC8GA1UEAwwobWtjZXJ0IGp1\nbnh1Y2hlbkBqdW54dWRlQWlyIChqdW54dSBjaGVuKTAeFw0xOTA2MDEwMDAwMDBa\nFw0zMDA3MDQwNjA0MzNaMFUxJzAlBgNVBAoTHm1rY2VydCBkZXZlbG9wbWVudCBj\nZXJ0aWZpY2F0ZTEqMCgGA1UECwwhanVueHVjaGVuQGp1bnh1ZGVBaXIgKGp1bnh1\nIGNoZW4pMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy21L [...]
-		"key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDLbUtgWZBileYy\nVSPJvBsnffybAqbFj7BMQksGHDu0Fxq71oWOPI7hpGmHiul0xCAKfiXBMwTaVsV1\nGEfNTn5LL0mwjWT738nyxlJpMiP2lo5fY9icQ6gWMjH3CklGl4s0GPLcgJLccLhL\nNNsNUCT0tkgsu//zW+3UqlDUeg+kT45nXBf4IvT/pGc2Z1qqCua20+/Sy6X3Ih4r\nPX0evbqnHuDpSegrSjytLAKpWaOhVMn55jbOabNKGoU9MsWC81mYx4vd0+aDqcZ2\nOOxuRdLnS2HJMNv+H5gi8Sxl+sNWBtXaDo/8qLJ8oLJ68xDF3Unn9QjgeW0jcxeC\numhqIOJXAgMBAAECggEARdPea9RSm4SY3+4ZusW3DHdSnmLqnCYWfhbDa [...]
-	}`)
-
-	err = SslUpdate(param, u1.String())
-	assert.Nil(err)
-
-	ssl, _ = SslItem(u1.String())
-	assert.Equal(2, len(ssl.Snis))
-
-	// check sni ssl exist
-	param = []byte(`[
-		"example.com",
-		"www.example.com",
-		"a.example.com",
-		"a.com",
-		"b.com"
-	]`)
-
-	err = CheckSniExists(param)
-	assert.NotNil(err)
-	assert.Equal(errno.SslForSniNotExists.Code, err.(*errno.ManagerError).Code)
-
-	param = []byte(`{
-		"status": 1
-	}`)
-	err = SslPatch(param, u1.String())
-	assert.Nil(err)
-
-	// check sni ssl exist
-	param = []byte(`[
-		"example.com",
-		"www.example.com",
-		"a.example.com",
-		"a.com",
-		"b.com"
-	]`)
-
-	err = CheckSniExists(param)
-	assert.Nil(err)
-
-	//delete
-	err = SslDelete(u1.String())
-	assert.Nil(err)
-
-	_, err = SslItem(u1.String())
-	assert.Equal(errno.DBReadError.Code, err.(*errno.ManagerError).Code)
-
-	err = SslDelete(u2.String())
-	assert.Nil(err)
-}
diff --git a/api/service/upstream_test.go b/api/service/upstream_test.go
deleted file mode 100644
index a4d671b..0000000
--- a/api/service/upstream_test.go
+++ /dev/null
@@ -1,108 +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 service
-
-import (
-	"testing"
-
-	uuid "github.com/satori/go.uuid"
-	"github.com/stretchr/testify/assert"
-)
-
-// parse from params to RouteRequest must be error
-func TestUpstreamRequest_Parse(t *testing.T) {
-	a := assert.New(t)
-	param := []byte(`{
-		"name": "upstream-test",
-		"description": "test upstream",
-		"type": "roundrobin",
-		"nodes": {
-			"127.0.0.1:8080":100,
-			"127.0.0.1:8081":200
-		},
-		"timeout":{
-			"connect":15,
-			"send":15,
-			"read":15
-		},
-		"enable_websocket": true,
-		"hash_on": "header",
-		"key": "server_addr",
-		"checks": {
-			"active": {
-				"timeout": 5,
-				"http_path": "/status",
-				"host": "foo.com",
-				"healthy": {
-					"interval": 2,
-					"successes": 1
-				},
-				"unhealthy": {
-					"interval": 1,
-					"http_failures": 2
-				},
-				"req_headers": ["User-Agent: curl/7.29.0"]
-			},
-			"passive": {
-				"healthy": {
-					"http_statuses": [200, 201],
-					"successes": 3
-				},
-				"unhealthy": {
-					"http_statuses": [500],
-					"http_failures": 3,
-					"tcp_failures": 3
-				}
-			}
-		}	
-	}`)
-
-	ur := &UpstreamRequest{}
-	err := ur.Parse(param)
-	a.Nil(err)
-	a.Equal("header", ur.HashOn)
-	a.Equal("server_addr", ur.Key)
-
-	u4 := uuid.NewV4()
-	uuid := u4.String()
-	ur.Id = uuid
-
-	aur, err := ur.Parse2Apisix()
-	a.Nil(err)
-
-	res := aur.toJson()
-	a.NotNil(res)
-
-	//create a upstream
-	apisixResp, err := aur.Create()
-	a.Nil(err)
-	rur, err := apisixResp.Parse2Request()
-	a.Nil(err)
-	a.Equal(ur.Key, rur.Key)
-
-	aur.Id = rur.Id
-	//get the upstream just created
-	created, err := aur.FindById()
-	a.Nil(err)
-	createdFormat, err := created.Parse2Request()
-	a.Nil(err)
-	a.Equal(createdFormat.HashOn, rur.HashOn)
-
-	//delete test data
-	_, err = aur.Delete()
-	a.Nil(err)
-}