github.com/unionj-cloud/go-doudou@v1.3.8-0.20221011095552-0088008e5b31/framework/http/middleware_test.go (about)

     1  package ddhttp_test
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"github.com/apolloconfig/agollo/v4"
     8  	"github.com/apolloconfig/agollo/v4/agcache/memory"
     9  	apolloConfig "github.com/apolloconfig/agollo/v4/env/config"
    10  	"github.com/go-resty/resty/v2"
    11  	"github.com/golang/mock/gomock"
    12  	"github.com/opentracing-contrib/go-stdlib/nethttp"
    13  	"github.com/opentracing/opentracing-go"
    14  	"github.com/pkg/errors"
    15  	"github.com/slok/goresilience"
    16  	. "github.com/smartystreets/goconvey/convey"
    17  	"github.com/unionj-cloud/go-doudou/framework/configmgr"
    18  	"github.com/unionj-cloud/go-doudou/framework/configmgr/mock"
    19  	ddhttp "github.com/unionj-cloud/go-doudou/framework/http"
    20  	httpMock "github.com/unionj-cloud/go-doudou/framework/http/mock"
    21  	ddmodel "github.com/unionj-cloud/go-doudou/framework/http/model"
    22  	"github.com/unionj-cloud/go-doudou/framework/internal/config"
    23  	"github.com/unionj-cloud/go-doudou/framework/registry"
    24  	"github.com/unionj-cloud/go-doudou/toolkit/maputils"
    25  	"github.com/wubin1989/nacos-sdk-go/clients/cache"
    26  	"github.com/wubin1989/nacos-sdk-go/clients/config_client"
    27  	"github.com/wubin1989/nacos-sdk-go/vo"
    28  	"net/http"
    29  	"os"
    30  	"testing"
    31  	"time"
    32  )
    33  
    34  type IMocksvcHandler interface {
    35  	GetUser(w http.ResponseWriter, r *http.Request)
    36  	SaveUser(w http.ResponseWriter, r *http.Request)
    37  	SignUp(w http.ResponseWriter, r *http.Request)
    38  	GetPanic(w http.ResponseWriter, r *http.Request)
    39  }
    40  
    41  type MocksvcHandler struct{}
    42  
    43  func (m *MocksvcHandler) GetUser(w http.ResponseWriter, r *http.Request) {
    44  	w.Header().Set("Content-Type", "text/plain")
    45  	w.Write([]byte("go-doudou"))
    46  }
    47  
    48  func (m *MocksvcHandler) SaveUser(w http.ResponseWriter, r *http.Request) {
    49  	data := struct {
    50  		Data string `json:"data"`
    51  	}{
    52  		Data: "OK",
    53  	}
    54  	resp, _ := json.Marshal(data)
    55  	w.Write(resp)
    56  }
    57  
    58  func (m *MocksvcHandler) SignUp(w http.ResponseWriter, r *http.Request) {
    59  	data := struct {
    60  		Data string `json:"data"`
    61  	}{
    62  		Data: "OK",
    63  	}
    64  	resp, _ := json.Marshal(data)
    65  	w.Write(resp)
    66  }
    67  
    68  func (m *MocksvcHandler) GetPanic(w http.ResponseWriter, r *http.Request) {
    69  	panic(context.Canceled)
    70  }
    71  
    72  func Routes(handler IMocksvcHandler) []ddmodel.Route {
    73  	return []ddmodel.Route{
    74  		{
    75  			Name:        "GetUser",
    76  			Method:      "GET",
    77  			Pattern:     "/user",
    78  			HandlerFunc: handler.GetUser,
    79  		},
    80  		{
    81  			Name:        "SaveUser",
    82  			Method:      "POST",
    83  			Pattern:     "/save/user",
    84  			HandlerFunc: handler.SaveUser,
    85  		},
    86  		{
    87  			Name:        "SignUp",
    88  			Method:      "POST",
    89  			Pattern:     "/sign/up",
    90  			HandlerFunc: handler.SignUp,
    91  		},
    92  		{
    93  			Name:        "GetPanic",
    94  			Method:      "GET",
    95  			Pattern:     "/panic",
    96  			HandlerFunc: handler.GetPanic,
    97  		},
    98  	}
    99  }
   100  
   101  func NewMocksvcHandler() IMocksvcHandler {
   102  	return &MocksvcHandler{}
   103  }
   104  
   105  type UserVo struct {
   106  	Username string
   107  	Password string
   108  }
   109  
   110  type IMockClient interface {
   111  	GetUser(ctx context.Context, _headers map[string]string) (_resp *resty.Response, data string, err error)
   112  	SaveUser(ctx context.Context, _headers map[string]string, payload UserVo) (_resp *resty.Response, data string, err error)
   113  	SignUp(ctx context.Context, _headers map[string]string, username, password string) (_resp *resty.Response, data string, err error)
   114  	GetPanic(ctx context.Context, _headers map[string]string) (_resp *resty.Response, data string, err error)
   115  }
   116  
   117  type MockClient struct {
   118  	provider registry.IServiceProvider
   119  	client   *resty.Client
   120  	rootPath string
   121  }
   122  
   123  func (receiver *MockClient) SetRootPath(rootPath string) {
   124  	receiver.rootPath = rootPath
   125  }
   126  
   127  func (receiver *MockClient) SetProvider(provider registry.IServiceProvider) {
   128  	receiver.provider = provider
   129  }
   130  
   131  func (receiver *MockClient) SetClient(client *resty.Client) {
   132  	receiver.client = client
   133  }
   134  
   135  func (receiver *MockClient) GetUser(ctx context.Context, _headers map[string]string) (_resp *resty.Response, data string, err error) {
   136  	var _err error
   137  	_req := receiver.client.R()
   138  	_req.SetContext(ctx)
   139  	_path := "/user"
   140  	_resp, _err = _req.Get(_path)
   141  	if _err != nil {
   142  		err = errors.Wrap(_err, "error")
   143  		return
   144  	}
   145  	if _resp.IsError() {
   146  		err = errors.New(_resp.String())
   147  		return
   148  	}
   149  	return _resp, string(_resp.Body()), nil
   150  }
   151  
   152  func (receiver *MockClient) GetPanic(ctx context.Context, _headers map[string]string) (_resp *resty.Response, data string, err error) {
   153  	var _err error
   154  	_req := receiver.client.R()
   155  	_req.SetContext(ctx)
   156  	_path := "/panic"
   157  	_resp, _err = _req.Get(_path)
   158  	if _err != nil {
   159  		err = errors.Wrap(_err, "error")
   160  		return
   161  	}
   162  	if _resp.IsError() {
   163  		err = errors.New(_resp.String())
   164  		return
   165  	}
   166  	return _resp, string(_resp.Body()), nil
   167  }
   168  
   169  func (receiver *MockClient) SignUp(ctx context.Context, _headers map[string]string, username, password string) (_resp *resty.Response, data string, err error) {
   170  	var _err error
   171  	_req := receiver.client.R()
   172  	_req.SetContext(ctx)
   173  	formData := make(map[string]string)
   174  	formData["username"] = fmt.Sprintf("%v", username)
   175  	formData["password"] = fmt.Sprintf("%v", password)
   176  	_path := "/sign/up"
   177  	_req.SetMultipartFormData(formData)
   178  	_resp, _err = _req.Post(_path)
   179  	if _err != nil {
   180  		err = errors.Wrap(_err, "error")
   181  		return
   182  	}
   183  	if _resp.IsError() {
   184  		err = errors.New(_resp.String())
   185  		return
   186  	}
   187  	var _result struct {
   188  		Data string `json:"data"`
   189  	}
   190  	if _err = json.Unmarshal(_resp.Body(), &_result); _err != nil {
   191  		err = errors.Wrap(_err, "error")
   192  		return
   193  	}
   194  	return _resp, _result.Data, nil
   195  }
   196  
   197  func (receiver *MockClient) SaveUser(ctx context.Context, _headers map[string]string, payload UserVo) (_resp *resty.Response, data string, err error) {
   198  	var _err error
   199  	_req := receiver.client.R()
   200  	_req.SetContext(ctx)
   201  	_req.SetBody(payload)
   202  	_path := "/save/user"
   203  	_resp, _err = _req.Post(_path)
   204  	if _err != nil {
   205  		err = errors.Wrap(_err, "error")
   206  		return
   207  	}
   208  	if _resp.IsError() {
   209  		err = errors.New(_resp.String())
   210  		return
   211  	}
   212  	var _result struct {
   213  		Data string `json:"data"`
   214  	}
   215  	if _err = json.Unmarshal(_resp.Body(), &_result); _err != nil {
   216  		err = errors.Wrap(_err, "error")
   217  		return
   218  	}
   219  	return _resp, _result.Data, nil
   220  }
   221  
   222  func NewMockClient(opts ...ddhttp.DdClientOption) *MockClient {
   223  	defaultProvider := ddhttp.NewServiceProvider("DDHTTP")
   224  	defaultClient := ddhttp.NewClient()
   225  
   226  	svcClient := &MockClient{
   227  		provider: defaultProvider,
   228  		client:   defaultClient,
   229  	}
   230  
   231  	for _, opt := range opts {
   232  		opt(svcClient)
   233  	}
   234  
   235  	svcClient.client.OnBeforeRequest(func(_ *resty.Client, request *resty.Request) error {
   236  		request.URL = svcClient.provider.SelectServer() + svcClient.rootPath + request.URL
   237  		return nil
   238  	})
   239  
   240  	svcClient.client.SetPreRequestHook(func(_ *resty.Client, request *http.Request) error {
   241  		traceReq, _ := nethttp.TraceRequest(opentracing.GlobalTracer(), request,
   242  			nethttp.OperationName(fmt.Sprintf("HTTP %s: %s", request.Method, request.URL.Path)))
   243  		*request = *traceReq
   244  		return nil
   245  	})
   246  
   247  	svcClient.client.OnAfterResponse(func(_ *resty.Client, response *resty.Response) error {
   248  		nethttp.TracerFromRequest(response.Request.RawRequest).Finish()
   249  		return nil
   250  	})
   251  
   252  	return svcClient
   253  }
   254  
   255  func Test_metrics(t *testing.T) {
   256  	Convey("Should be equal to go-doudou", t, func() {
   257  		go func() {
   258  			srv := ddhttp.NewDefaultHttpSrv()
   259  			srv.AddRoute(Routes(NewMocksvcHandler())...)
   260  			srv.Run()
   261  		}()
   262  		time.Sleep(10 * time.Millisecond)
   263  		os.Setenv("DDHTTP", "http://localhost:8088/v1")
   264  		client := NewMockClient()
   265  		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
   266  		defer cancel()
   267  		_, ret, err := client.GetUser(ctx, nil)
   268  		So(err, ShouldBeNil)
   269  		So(ret, ShouldEqual, "go-doudou")
   270  	})
   271  }
   272  
   273  func Test_NacosConfigType(t *testing.T) {
   274  	Convey("Should be equal to go-doudou with nacos config", t, func() {
   275  		ctrl := gomock.NewController(t)
   276  		defer ctrl.Finish()
   277  		dataId := ".env"
   278  		configClient := mock.NewMockIConfigClient(ctrl)
   279  		configClient.
   280  			EXPECT().
   281  			GetConfig(vo.ConfigParam{
   282  				DataId: dataId,
   283  				Group:  config.DefaultGddNacosConfigGroup,
   284  			}).
   285  			AnyTimes().
   286  			Return("GDD_SERVICE_NAME=configmgr\n\nGDD_READ_TIMEOUT=60s\nGDD_WRITE_TIMEOUT=60s\nGDD_IDLE_TIMEOUT=120s", nil)
   287  
   288  		configClient.
   289  			EXPECT().
   290  			ListenConfig(gomock.Any()).
   291  			AnyTimes().
   292  			Return(nil)
   293  
   294  		configmgr.NewConfigClient = func(param vo.NacosClientParam) (iClient config_client.IConfigClient, err error) {
   295  			return configClient, nil
   296  		}
   297  
   298  		configmgr.NacosClient = configmgr.NewNacosConfigMgr([]string{dataId},
   299  			config.DefaultGddNacosConfigGroup, configmgr.DotenvConfigFormat, config.DefaultGddNacosNamespaceId, configClient, cache.NewConcurrentMap())
   300  
   301  		_ = config.GddConfigRemoteType.Write(config.NacosConfigType)
   302  		config.GddNacosConfigDataid.Write(dataId)
   303  		config.GddPort.Write("6060")
   304  		ddhttp.InitialiseRemoteConfigListener()
   305  		go func() {
   306  			srv := ddhttp.NewDefaultHttpSrv()
   307  			srv.AddRoute(Routes(NewMocksvcHandler())...)
   308  			srv.Run()
   309  		}()
   310  		time.Sleep(10 * time.Millisecond)
   311  		os.Setenv("DDHTTP", "http://localhost:6060/v1")
   312  		client := NewMockClient()
   313  		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
   314  		defer cancel()
   315  		_, ret, err := client.GetUser(ctx, nil)
   316  		So(err, ShouldBeNil)
   317  		So(ret, ShouldEqual, "go-doudou")
   318  	})
   319  }
   320  
   321  func Test_UnknownRemoteConfigType(t *testing.T) {
   322  	Convey("Should be equal to go-doudou with unknown remote config type", t, func() {
   323  		_ = config.GddConfigRemoteType.Write("Unknown")
   324  		config.GddPort.Write("6061")
   325  		ddhttp.InitialiseRemoteConfigListener()
   326  		go func() {
   327  			srv := ddhttp.NewDefaultHttpSrv()
   328  			srv.AddRoute(Routes(NewMocksvcHandler())...)
   329  			srv.Run()
   330  		}()
   331  		time.Sleep(10 * time.Millisecond)
   332  		os.Setenv("DDHTTP", "http://localhost:6061/v1")
   333  		client := NewMockClient()
   334  		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
   335  		defer cancel()
   336  		_, ret, err := client.GetUser(ctx, nil)
   337  		So(err, ShouldBeNil)
   338  		So(ret, ShouldEqual, "go-doudou")
   339  	})
   340  }
   341  
   342  func Test_ApolloConfigType(t *testing.T) {
   343  	Convey("Should be equal to go-doudou with apollo config", t, func() {
   344  		ctrl := gomock.NewController(t)
   345  		defer ctrl.Finish()
   346  		configClient := mock.NewMockClient(ctrl)
   347  		factory := &memory.DefaultCacheFactory{}
   348  		cache := factory.Create()
   349  		cache.Set("gdd.retry.count", "3", 0)
   350  		cache.Set("gdd.weight", "5", 0)
   351  		configClient.
   352  			EXPECT().
   353  			GetConfigCache(config.DefaultGddApolloNamespace).
   354  			AnyTimes().
   355  			Return(cache)
   356  
   357  		configClient.
   358  			EXPECT().
   359  			AddChangeListener(gomock.Any()).
   360  			AnyTimes().
   361  			Return()
   362  
   363  		configmgr.StartWithConfig = func(loadAppConfig func() (*apolloConfig.AppConfig, error)) (agollo.Client, error) {
   364  			_, _ = loadAppConfig()
   365  			return configClient, nil
   366  		}
   367  
   368  		configmgr.ApolloClient = configClient
   369  
   370  		_ = config.GddConfigRemoteType.Write(config.ApolloConfigType)
   371  		config.GddPort.Write("6062")
   372  		ddhttp.InitialiseRemoteConfigListener()
   373  		go func() {
   374  			srv := ddhttp.NewDefaultHttpSrv()
   375  			srv.AddRoute(Routes(NewMocksvcHandler())...)
   376  			srv.Run()
   377  		}()
   378  		time.Sleep(10 * time.Millisecond)
   379  		os.Setenv("DDHTTP", "http://localhost:6062/v1")
   380  		client := NewMockClient()
   381  		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
   382  		defer cancel()
   383  		_, ret, err := client.GetUser(ctx, nil)
   384  		So(err, ShouldBeNil)
   385  		So(ret, ShouldEqual, "go-doudou")
   386  	})
   387  }
   388  
   389  func TestCallbackOnChange(t *testing.T) {
   390  	Convey("Environment variable GDD_MANAGE_USER should be changed", t, func() {
   391  		listener := ddhttp.NewHttpConfigListener()
   392  		ddhttp.CallbackOnChange(listener)(&configmgr.NacosChangeEvent{
   393  			Namespace: "",
   394  			Group:     "",
   395  			DataId:    "",
   396  			Changes: map[string]maputils.Change{
   397  				"gdd.manage.user": {
   398  					OldValue:   "admin",
   399  					NewValue:   "go-doudou",
   400  					ChangeType: maputils.MODIFIED,
   401  				},
   402  			},
   403  		})
   404  		So(config.GddManageUser.Load(), ShouldEqual, "")
   405  		ddhttp.CallbackOnChange(listener)(&configmgr.NacosChangeEvent{
   406  			Namespace: "",
   407  			Group:     "",
   408  			DataId:    "",
   409  			Changes: map[string]maputils.Change{
   410  				"gdd.manage.user": {
   411  					OldValue:   "admin",
   412  					NewValue:   "go-doudou",
   413  					ChangeType: maputils.MODIFIED,
   414  				},
   415  			},
   416  		})
   417  		So(config.GddManageUser.Load(), ShouldEqual, "go-doudou")
   418  	})
   419  }
   420  
   421  func Test_log_get_text(t *testing.T) {
   422  	Convey("Should be equal to go-doudou", t, func() {
   423  		config.GddLogReqEnable.Write("true")
   424  		config.GddPort.Write("6063")
   425  		go func() {
   426  			srv := ddhttp.NewDefaultHttpSrv()
   427  			srv.AddRoute(Routes(NewMocksvcHandler())...)
   428  			srv.Run()
   429  		}()
   430  		time.Sleep(10 * time.Millisecond)
   431  		os.Setenv("DDHTTP", "http://localhost:6063/v1")
   432  		client := NewMockClient()
   433  		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
   434  		defer cancel()
   435  		_, ret, err := client.GetUser(ctx, nil)
   436  		So(err, ShouldBeNil)
   437  		So(ret, ShouldEqual, "go-doudou")
   438  	})
   439  }
   440  
   441  func Test_log_post_json(t *testing.T) {
   442  	Convey("Should be equal to OK", t, func() {
   443  		config.GddLogReqEnable.Write("true")
   444  		config.GddPort.Write("6064")
   445  		go func() {
   446  			srv := ddhttp.NewDefaultHttpSrv()
   447  			srv.AddRoute(Routes(NewMocksvcHandler())...)
   448  			srv.Run()
   449  		}()
   450  		time.Sleep(10 * time.Millisecond)
   451  		os.Setenv("DDHTTP", "http://localhost:6064/v1")
   452  		client := NewMockClient()
   453  		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
   454  		defer cancel()
   455  		_, ret, err := client.SaveUser(ctx, nil, UserVo{
   456  			Username: "go-doudou",
   457  			Password: "go-doudou",
   458  		})
   459  		So(err, ShouldBeNil)
   460  		So(ret, ShouldEqual, "OK")
   461  	})
   462  }
   463  
   464  func Test_log_post_formdata(t *testing.T) {
   465  	Convey("Should be equal to OK", t, func() {
   466  		config.GddLogReqEnable.Write("true")
   467  		config.GddPort.Write("6065")
   468  		go func() {
   469  			srv := ddhttp.NewDefaultHttpSrv()
   470  			srv.AddRoute(Routes(NewMocksvcHandler())...)
   471  			srv.Run()
   472  		}()
   473  		time.Sleep(10 * time.Millisecond)
   474  		os.Setenv("DDHTTP", "http://localhost:6065/v1")
   475  		client := NewMockClient()
   476  		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
   477  		defer cancel()
   478  		_, ret, err := client.SignUp(ctx, nil, "go-doudou", "go-doudou")
   479  		So(err, ShouldBeNil)
   480  		So(ret, ShouldEqual, "OK")
   481  	})
   482  }
   483  
   484  func Test_basicauth_401(t *testing.T) {
   485  	Convey("Should return 401", t, func() {
   486  		config.GddPort.Write("6066")
   487  		config.GddManagePass.Write("admin")
   488  		go func() {
   489  			srv := ddhttp.NewDefaultHttpSrv()
   490  			srv.AddRoute(Routes(NewMocksvcHandler())...)
   491  			srv.Run()
   492  		}()
   493  		time.Sleep(10 * time.Millisecond)
   494  		resp, err := http.Get("http://localhost:6066/go-doudou/config")
   495  		So(err, ShouldBeNil)
   496  		So(resp.StatusCode, ShouldEqual, 401)
   497  	})
   498  }
   499  
   500  func Test_basicauth_200(t *testing.T) {
   501  	Convey("Should return 200", t, func() {
   502  		config.GddPort.Write("6066")
   503  		config.GddManageUser.Write("admin")
   504  		config.GddManagePass.Write("admin")
   505  		go func() {
   506  			srv := ddhttp.NewDefaultHttpSrv()
   507  			srv.AddRoute(Routes(NewMocksvcHandler())...)
   508  			srv.Run()
   509  		}()
   510  		time.Sleep(10 * time.Millisecond)
   511  		resp, err := http.Get("http://admin:admin@localhost:6066/go-doudou/config")
   512  		So(err, ShouldBeNil)
   513  		So(resp.StatusCode, ShouldEqual, 200)
   514  	})
   515  }
   516  
   517  func Test_recovery(t *testing.T) {
   518  	Convey("Should recovery from panic", t, func() {
   519  		config.GddPort.Write("6067")
   520  		go func() {
   521  			srv := ddhttp.NewDefaultHttpSrv()
   522  			srv.AddRoute(Routes(NewMocksvcHandler())...)
   523  			srv.Run()
   524  		}()
   525  		time.Sleep(10 * time.Millisecond)
   526  		os.Setenv("DDHTTP", "http://localhost:6067/v1")
   527  		client := NewMockClient()
   528  		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
   529  		defer cancel()
   530  		_, _, err := client.GetPanic(ctx, nil)
   531  		So(err, ShouldNotBeNil)
   532  	})
   533  }
   534  
   535  func Test_bulkhead(t *testing.T) {
   536  	Convey("Should work with bulkhead", t, func() {
   537  		config.GddPort.Write("6068")
   538  		go func() {
   539  			srv := ddhttp.NewDefaultHttpSrv()
   540  			srv.AddRoute(Routes(NewMocksvcHandler())...)
   541  			srv.AddMiddleware(ddhttp.BulkHead(4, 500*time.Millisecond))
   542  			srv.Run()
   543  		}()
   544  		time.Sleep(10 * time.Millisecond)
   545  		os.Setenv("DDHTTP", "http://localhost:6068/v1")
   546  		client := NewMockClient()
   547  		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
   548  		defer cancel()
   549  		_, ret, err := client.SignUp(ctx, nil, "go-doudou", "go-doudou")
   550  		So(err, ShouldBeNil)
   551  		So(ret, ShouldEqual, "OK")
   552  	})
   553  }
   554  
   555  func Test_bulkhead_fail(t *testing.T) {
   556  	Convey("Should fail with bulkhead", t, func() {
   557  		ctrl := gomock.NewController(t)
   558  		defer ctrl.Finish()
   559  		runner := httpMock.NewMockRunner(ctrl)
   560  		runner.
   561  			EXPECT().
   562  			Run(gomock.Any(), gomock.Any()).
   563  			AnyTimes().
   564  			Return(errors.New("mock runner test error"))
   565  
   566  		ddhttp.RunnerChain = func(middlewares ...goresilience.Middleware) goresilience.Runner {
   567  			return runner
   568  		}
   569  		config.GddPort.Write("6069")
   570  		go func() {
   571  			srv := ddhttp.NewDefaultHttpSrv()
   572  			srv.AddRoute(Routes(NewMocksvcHandler())...)
   573  			srv.AddMiddleware(ddhttp.BulkHead(4, 500*time.Millisecond))
   574  			srv.Run()
   575  		}()
   576  		time.Sleep(10 * time.Millisecond)
   577  		os.Setenv("DDHTTP", "http://localhost:6069/v1")
   578  		client := NewMockClient()
   579  		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
   580  		defer cancel()
   581  		_, _, err := client.SignUp(ctx, nil, "go-doudou", "go-doudou")
   582  		So(err.Error(), ShouldEqual, "too many requests")
   583  	})
   584  }