github.com/Tyktechnologies/tyk@v2.9.5+incompatible/gateway/rpc_test.go (about)

     1  // +build !race
     2  
     3  package gateway
     4  
     5  import (
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/gorilla/mux"
    10  
    11  	"github.com/TykTechnologies/tyk/cli"
    12  
    13  	"github.com/TykTechnologies/gorpc"
    14  	"github.com/TykTechnologies/tyk/apidef"
    15  	"github.com/TykTechnologies/tyk/config"
    16  	"github.com/TykTechnologies/tyk/rpc"
    17  	"github.com/TykTechnologies/tyk/test"
    18  )
    19  
    20  func startRPCMock(dispatcher *gorpc.Dispatcher) *gorpc.Server {
    21  
    22  	rpc.GlobalRPCCallTimeout = 100 * time.Millisecond
    23  
    24  	globalConf := config.Global()
    25  	globalConf.SlaveOptions.UseRPC = true
    26  	globalConf.SlaveOptions.RPCKey = "test_org"
    27  	globalConf.SlaveOptions.APIKey = "test"
    28  	globalConf.Policies.PolicySource = "rpc"
    29  	globalConf.SlaveOptions.CallTimeout = 1
    30  	globalConf.SlaveOptions.RPCPoolSize = 2
    31  	globalConf.AuthOverride.ForceAuthProvider = true
    32  	globalConf.AuthOverride.AuthProvider.StorageEngine = "rpc"
    33  
    34  	server := gorpc.NewTCPServer("127.0.0.1:0", dispatcher.NewHandlerFunc())
    35  	list := &customListener{}
    36  	server.Listener = list
    37  	server.LogError = gorpc.NilErrorLogger
    38  
    39  	if err := server.Start(); err != nil {
    40  		panic(err)
    41  	}
    42  	globalConf.SlaveOptions.ConnectionString = list.L.Addr().String()
    43  
    44  	config.SetGlobal(globalConf)
    45  
    46  	return server
    47  }
    48  
    49  func stopRPCMock(server *gorpc.Server) {
    50  	globalConf := config.Global()
    51  	globalConf.SlaveOptions.ConnectionString = ""
    52  	globalConf.SlaveOptions.RPCKey = ""
    53  	globalConf.SlaveOptions.APIKey = ""
    54  	globalConf.SlaveOptions.UseRPC = false
    55  	globalConf.Policies.PolicySource = ""
    56  	globalConf.AuthOverride.ForceAuthProvider = false
    57  	config.SetGlobal(globalConf)
    58  
    59  	if server != nil {
    60  		server.Listener.Close()
    61  		server.Stop()
    62  	}
    63  
    64  	rpc.Reset()
    65  }
    66  
    67  const apiDefListTest = `[{
    68  	"api_id": "1",
    69  	"definition": {
    70  		"location": "header",
    71  		"key": "version"
    72  	},
    73  	"auth": {"auth_header_name": "authorization"},
    74  	"version_data": {
    75  		"versions": {
    76  			"v1": {"name": "v1"}
    77  		}
    78  	},
    79  	"proxy": {
    80  		"listen_path": "/v1",
    81  		"target_url": "` + TestHttpAny + `"
    82  	}
    83  }]`
    84  
    85  const apiDefListTest2 = `[{
    86  	"api_id": "1",
    87  	"definition": {
    88  		"location": "header",
    89  		"key": "version"
    90  	},
    91  	"auth": {"auth_header_name": "authorization"},
    92  	"version_data": {
    93  		"versions": {
    94  			"v1": {"name": "v1"}
    95  		}
    96  	},
    97  	"proxy": {
    98  		"listen_path": "/v1",
    99  		"target_url": "` + TestHttpAny + `"
   100  	}
   101  },
   102  {
   103  	"api_id": "2",
   104  	"definition": {
   105  		"location": "header",
   106  		"key": "version"
   107  	},
   108  	"auth": {"auth_header_name": "authorization"},
   109  	"version_data": {
   110  		"versions": {
   111  			"v2": {"name": "v2"}
   112  		}
   113  	},
   114  	"proxy": {
   115  		"listen_path": "/v2",
   116  		"target_url": "` + TestHttpAny + `"
   117  	}
   118  }]`
   119  
   120  func TestSyncAPISpecsRPCFailure_CheckGlobals(t *testing.T) {
   121  	ts := StartTest()
   122  	defer ts.Close()
   123  	defer ResetTestConfig()
   124  
   125  	// Test RPC
   126  	callCount := 0
   127  	dispatcher := gorpc.NewDispatcher()
   128  	dispatcher.AddFunc("GetApiDefinitions", func(clientAddr string, dr *apidef.DefRequest) (string, error) {
   129  		if callCount == 0 {
   130  			callCount += 1
   131  			return `[]`, nil
   132  		}
   133  
   134  		if callCount == 1 {
   135  			callCount += 1
   136  			return apiDefListTest, nil
   137  		}
   138  
   139  		if callCount == 2 {
   140  			callCount += 1
   141  			return apiDefListTest2, nil
   142  		}
   143  
   144  		if callCount == 3 {
   145  			callCount += 1
   146  			return "malformed json", nil
   147  		}
   148  
   149  		// clean up
   150  		return `[]`, nil
   151  	})
   152  	dispatcher.AddFunc("Login", func(clientAddr, userKey string) bool {
   153  		return true
   154  	})
   155  	dispatcher.AddFunc("GetPolicies", func(orgId string) (string, error) {
   156  		return `[]`, nil
   157  	})
   158  
   159  	rpc := startRPCMock(dispatcher)
   160  	defer stopRPCMock(rpc)
   161  
   162  	// Three cases: 1 API, 2 APIs and Malformed data
   163  	exp := []int{1, 4, 6, 6, 2}
   164  	if *cli.HTTPProfile {
   165  		exp = []int{4, 6, 8, 8, 4}
   166  	}
   167  	for _, e := range exp {
   168  		DoReload()
   169  
   170  		rtCnt := 0
   171  		mainRouter().Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
   172  			rtCnt += 1
   173  			//fmt.Println(route.GetPathTemplate())
   174  			return nil
   175  		})
   176  
   177  		if rtCnt != e {
   178  			t.Errorf("There should be %v routes, got %v", e, rtCnt)
   179  		}
   180  	}
   181  }
   182  
   183  // Our RPC layer too racy, but not harmul, mostly global variables like RPCIsClientConnected
   184  func TestSyncAPISpecsRPCFailure(t *testing.T) {
   185  	// Test RPC
   186  	dispatcher := gorpc.NewDispatcher()
   187  	dispatcher.AddFunc("GetApiDefinitions", func(clientAddr string, dr *apidef.DefRequest) (string, error) {
   188  		return "malformed json", nil
   189  	})
   190  	dispatcher.AddFunc("Login", func(clientAddr, userKey string) bool {
   191  		return true
   192  	})
   193  
   194  	rpc := startRPCMock(dispatcher)
   195  	defer stopRPCMock(rpc)
   196  
   197  	count, _ := syncAPISpecs()
   198  	if count != 0 {
   199  		t.Error("Should return empty value for malformed rpc response", apiSpecs)
   200  	}
   201  }
   202  
   203  func TestSyncAPISpecsRPCSuccess(t *testing.T) {
   204  	// Test RPC
   205  	dispatcher := gorpc.NewDispatcher()
   206  	dispatcher.AddFunc("GetApiDefinitions", func(clientAddr string, dr *apidef.DefRequest) (string, error) {
   207  		return jsonMarshalString(BuildAPI(func(spec *APISpec) {
   208  			spec.UseKeylessAccess = false
   209  		})), nil
   210  	})
   211  	dispatcher.AddFunc("GetPolicies", func(clientAddr string, orgid string) (string, error) {
   212  		return `[{"_id":"507f191e810c19729de860ea", "rate":1, "per":1}]`, nil
   213  	})
   214  	dispatcher.AddFunc("Login", func(clientAddr, userKey string) bool {
   215  		return true
   216  	})
   217  	dispatcher.AddFunc("GetKey", func(clientAddr, key string) (string, error) {
   218  		return jsonMarshalString(CreateStandardSession()), nil
   219  	})
   220  
   221  	t.Run("RPC is live", func(t *testing.T) {
   222  		rpc := startRPCMock(dispatcher)
   223  		defer stopRPCMock(rpc)
   224  		ts := StartTest()
   225  		defer ts.Close()
   226  
   227  		apiBackup, _ := LoadDefinitionsFromRPCBackup()
   228  		if len(apiBackup) != 1 {
   229  			t.Fatal("Should have APIs in backup")
   230  		}
   231  
   232  		policyBackup, _ := LoadPoliciesFromRPCBackup()
   233  		if len(policyBackup) != 1 {
   234  			t.Fatal("Should have Policies in backup")
   235  		}
   236  
   237  		authHeaders := map[string]string{"Authorization": "test"}
   238  		ts.Run(t, []test.TestCase{
   239  			{Path: "/sample", Headers: authHeaders, Code: 200},
   240  		}...)
   241  
   242  		count, _ := syncAPISpecs()
   243  		if count != 1 {
   244  			t.Error("Should return array with one spec", apiSpecs)
   245  		}
   246  	})
   247  
   248  	t.Run("RPC down, cold start, load backup", func(t *testing.T) {
   249  		// Point rpc to non existent address
   250  		globalConf := config.Global()
   251  		globalConf.SlaveOptions.ConnectionString = testHttpFailure
   252  		globalConf.SlaveOptions.UseRPC = true
   253  		globalConf.SlaveOptions.RPCKey = "test_org"
   254  		globalConf.SlaveOptions.APIKey = "test"
   255  		globalConf.Policies.PolicySource = "rpc"
   256  		config.SetGlobal(globalConf)
   257  
   258  		// RPC layer is down
   259  		ts := StartTest()
   260  		defer ts.Close()
   261  
   262  		// Wait for backup to load
   263  		time.Sleep(100 * time.Millisecond)
   264  		ReloadTestCase.Tick()
   265  		time.Sleep(100 * time.Millisecond)
   266  
   267  		cachedAuth := map[string]string{"Authorization": "test"}
   268  		notCachedAuth := map[string]string{"Authorization": "nope1"}
   269  		// Stil works, since it knows about cached key
   270  		ts.Run(t, []test.TestCase{
   271  			{Path: "/sample", Headers: cachedAuth, Code: 200},
   272  			{Path: "/sample", Headers: notCachedAuth, Code: 403},
   273  		}...)
   274  
   275  		stopRPCMock(nil)
   276  	})
   277  
   278  	t.Run("RPC is back, hard reload", func(t *testing.T) {
   279  		rpc.ResetEmergencyMode()
   280  
   281  		dispatcher := gorpc.NewDispatcher()
   282  		dispatcher.AddFunc("GetApiDefinitions", func(clientAddr string, dr *apidef.DefRequest) (string, error) {
   283  			return jsonMarshalString(BuildAPI(
   284  				func(spec *APISpec) { spec.UseKeylessAccess = false },
   285  				func(spec *APISpec) { spec.UseKeylessAccess = false },
   286  			)), nil
   287  		})
   288  		dispatcher.AddFunc("GetPolicies", func(clientAddr string, orgid string) (string, error) {
   289  			return `[{"_id":"507f191e810c19729de860ea", "rate":1, "per":1}, {"_id":"507f191e810c19729de860eb", "rate":1, "per":1}]`, nil
   290  		})
   291  		dispatcher.AddFunc("Login", func(clientAddr, userKey string) bool {
   292  			return true
   293  		})
   294  		dispatcher.AddFunc("GetKey", func(clientAddr, key string) (string, error) {
   295  			return jsonMarshalString(CreateStandardSession()), nil
   296  		})
   297  		// Back to live
   298  		rpc := startRPCMock(dispatcher)
   299  		defer stopRPCMock(rpc)
   300  		ts := StartTest()
   301  		defer ts.Close()
   302  
   303  		time.Sleep(100 * time.Millisecond)
   304  
   305  		cachedAuth := map[string]string{"Authorization": "test"}
   306  		notCachedAuth := map[string]string{"Authorization": "nope2"}
   307  		ts.Run(t, []test.TestCase{
   308  			{Path: "/sample", Headers: cachedAuth, Code: 200},
   309  			{Path: "/sample", Headers: notCachedAuth, Code: 200},
   310  		}...)
   311  
   312  		if count, _ := syncAPISpecs(); count != 2 {
   313  			t.Error("Should fetch latest specs", count)
   314  		}
   315  
   316  		if count, _ := syncPolicies(); count != 2 {
   317  			t.Error("Should fetch latest policies", count)
   318  		}
   319  	})
   320  
   321  	t.Run("RPC is back, live reload", func(t *testing.T) {
   322  		rpc := startRPCMock(dispatcher)
   323  		ts := StartTest()
   324  		defer ts.Close()
   325  
   326  		time.Sleep(100 * time.Millisecond)
   327  
   328  		authHeaders := map[string]string{"Authorization": "test"}
   329  		ts.Run(t, []test.TestCase{
   330  			{Path: "/sample", Headers: authHeaders, Code: 200},
   331  		}...)
   332  
   333  		rpc.Listener.Close()
   334  		rpc.Stop()
   335  
   336  		cached := map[string]string{"Authorization": "test"}
   337  		notCached := map[string]string{"Authorization": "nope3"}
   338  		ts.Run(t, []test.TestCase{
   339  			{Path: "/sample", Headers: cached, Code: 200},
   340  			{Path: "/sample", Headers: notCached, Code: 403},
   341  		}...)
   342  
   343  		// Dynamically restart RPC layer
   344  		rpc = gorpc.NewTCPServer(rpc.Listener.(*customListener).L.Addr().String(), dispatcher.NewHandlerFunc())
   345  		list := &customListener{}
   346  		rpc.Listener = list
   347  		rpc.LogError = gorpc.NilErrorLogger
   348  		if err := rpc.Start(); err != nil {
   349  			panic(err)
   350  		}
   351  		defer stopRPCMock(rpc)
   352  
   353  		// Internal gorpc reconnect timeout is 1 second
   354  		time.Sleep(1000 * time.Millisecond)
   355  
   356  		notCached = map[string]string{"Authorization": "nope4"}
   357  		ts.Run(t, []test.TestCase{
   358  			{Path: "/sample", Headers: notCached, Code: 200},
   359  		}...)
   360  	})
   361  }