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

     1  package gateway
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"net/http"
     7  	"net/http/httptest"
     8  	"reflect"
     9  	"sort"
    10  	"strconv"
    11  	"sync"
    12  	"testing"
    13  
    14  	"github.com/go-redis/redis"
    15  	uuid "github.com/satori/go.uuid"
    16  
    17  	"fmt"
    18  
    19  	"github.com/TykTechnologies/tyk/config"
    20  	"github.com/TykTechnologies/tyk/storage"
    21  	"github.com/TykTechnologies/tyk/test"
    22  	"github.com/TykTechnologies/tyk/user"
    23  )
    24  
    25  const apiTestDef = `{
    26  	"api_id": "1",
    27  	"definition": {
    28  		"location": "header",
    29  		"key": "version"
    30  	},
    31  	"auth": {"auth_header_name": "authorization"},
    32  	"version_data": {
    33  		"versions": {
    34  			"v1": {"name": "v1"}
    35  		}
    36  	},
    37  	"proxy": {
    38  		"listen_path": "/v1",
    39  		"target_url": "` + TestHttpAny + `"
    40  	}
    41  }`
    42  
    43  func TestHealthCheckEndpoint(t *testing.T) {
    44  	globalConf := config.Global()
    45  	globalConf.HealthCheck.EnableHealthChecks = true
    46  	config.SetGlobal(globalConf)
    47  	defer ResetTestConfig()
    48  
    49  	ts := StartTest()
    50  	defer ts.Close()
    51  
    52  	BuildAndLoadAPI()
    53  
    54  	ts.Run(t, []test.TestCase{
    55  		{Path: "/tyk/health/?api_id=test", AdminAuth: true, Code: 200},
    56  		{Path: "/tyk/health/?api_id=unknown", AdminAuth: true, Code: 404, BodyMatch: `"message":"API ID not found"`},
    57  	}...)
    58  }
    59  
    60  func TestApiHandlerPostDupPath(t *testing.T) {
    61  	type testCase struct {
    62  		APIID, ListenPath string
    63  	}
    64  
    65  	assertListenPaths := func(tests []testCase) {
    66  		for _, tc := range tests {
    67  			s := getApiSpec(tc.APIID)
    68  			if want, got := tc.ListenPath, s.Proxy.ListenPath; want != got {
    69  				t.Errorf("API spec %s want path %s, got %s", "2", want, got)
    70  			}
    71  		}
    72  	}
    73  
    74  	t.Run("Sequentieal order", func(t *testing.T) {
    75  		// Load initial API
    76  		BuildAndLoadAPI(
    77  			func(spec *APISpec) { spec.APIID = "1" },
    78  		)
    79  
    80  		BuildAndLoadAPI(
    81  			func(spec *APISpec) { spec.APIID = "1" },
    82  			func(spec *APISpec) { spec.APIID = "2" },
    83  			func(spec *APISpec) { spec.APIID = "3" },
    84  		)
    85  
    86  		assertListenPaths([]testCase{
    87  			// Should retain original API
    88  			{"1", "/sample"},
    89  			{"2", "/sample-2"},
    90  			{"3", "/sample-3"},
    91  		})
    92  	})
    93  
    94  	t.Run("Should re-order", func(t *testing.T) {
    95  		BuildAndLoadAPI(
    96  			func(spec *APISpec) { spec.APIID = "2" },
    97  			func(spec *APISpec) { spec.APIID = "3" },
    98  		)
    99  
   100  		assertListenPaths([]testCase{
   101  			{"2", "/sample-2"},
   102  			{"3", "/sample-3"},
   103  		})
   104  	})
   105  
   106  	t.Run("Restore original order", func(t *testing.T) {
   107  		BuildAndLoadAPI(
   108  			func(spec *APISpec) { spec.APIID = "1" },
   109  			func(spec *APISpec) { spec.APIID = "2" },
   110  			func(spec *APISpec) { spec.APIID = "3" },
   111  		)
   112  
   113  		assertListenPaths([]testCase{
   114  			// Since API was not loaded previously first it has prefixed id
   115  			{"1", "/sample-1"},
   116  			{"2", "/sample-2"},
   117  			{"3", "/sample-3"},
   118  		})
   119  	})
   120  }
   121  
   122  func TestKeyHandler(t *testing.T) {
   123  	ts := StartTest()
   124  	defer ts.Close()
   125  
   126  	defer ResetTestConfig()
   127  
   128  	BuildAndLoadAPI(func(spec *APISpec) {
   129  		spec.UseKeylessAccess = false
   130  		spec.Auth.UseParam = true
   131  	})
   132  
   133  	// Access right not specified
   134  	masterKey := CreateStandardSession()
   135  	masterKeyJSON, _ := json.Marshal(masterKey)
   136  
   137  	// with access
   138  	withAccess := CreateStandardSession()
   139  	withAccess.AccessRights = map[string]user.AccessDefinition{"test": {
   140  		APIID: "test", Versions: []string{"v1"},
   141  	}}
   142  	withAccessJSON, _ := json.Marshal(withAccess)
   143  
   144  	// with policy
   145  	policiesMu.Lock()
   146  	policiesByID["abc_policy"] = user.Policy{
   147  		Active:           true,
   148  		QuotaMax:         5,
   149  		QuotaRenewalRate: 300,
   150  		AccessRights: map[string]user.AccessDefinition{"test": {
   151  			APIID: "test", Versions: []string{"v1"},
   152  		}},
   153  		OrgID: "default",
   154  	}
   155  	policiesMu.Unlock()
   156  	withPolicy := CreateStandardSession()
   157  	withoutPolicyJSON, _ := json.Marshal(withPolicy)
   158  
   159  	withPolicy.ApplyPolicies = []string{
   160  		"abc_policy",
   161  	}
   162  	withPolicyJSON, _ := json.Marshal(withPolicy)
   163  
   164  	// with invalid policy
   165  	withBadPolicy := CreateStandardSession()
   166  	withBadPolicy.AccessRights = map[string]user.AccessDefinition{"test": {
   167  		APIID: "test", Versions: []string{"v1"},
   168  	}}
   169  	withBadPolicy.ApplyPolicies = []string{
   170  		"xyz_policy",
   171  	}
   172  	withBadPolicyJSON, _ := json.Marshal(withBadPolicy)
   173  
   174  	t.Run("Create key", func(t *testing.T) {
   175  		ts.Run(t, []test.TestCase{
   176  			// Master keys should be disabled by default
   177  			{Method: "POST", Path: "/tyk/keys/create", Data: string(masterKeyJSON), AdminAuth: true, Code: 400, BodyMatch: "Failed to create key, keys must have at least one Access Rights record set."},
   178  			{Method: "POST", Path: "/tyk/keys/create", Data: string(withAccessJSON), AdminAuth: true, Code: 200},
   179  		}...)
   180  	})
   181  
   182  	t.Run("Create key with policy", func(t *testing.T) {
   183  		ts.Run(t, []test.TestCase{
   184  			{
   185  				Method:    "POST",
   186  				Path:      "/tyk/keys/create",
   187  				Data:      string(withoutPolicyJSON),
   188  				AdminAuth: true,
   189  				Code:      400,
   190  			},
   191  			{
   192  				Method:    "POST",
   193  				Path:      "/tyk/keys/create",
   194  				Data:      string(withPolicyJSON),
   195  				AdminAuth: true,
   196  				Code:      200,
   197  			},
   198  			{
   199  				Method:    "POST",
   200  				Path:      "/tyk/keys/create",
   201  				Data:      string(withBadPolicyJSON),
   202  				AdminAuth: true,
   203  				Code:      500,
   204  			},
   205  			{
   206  				Method:    "POST",
   207  				Path:      "/tyk/keys/my_key_id",
   208  				Data:      string(withPolicyJSON),
   209  				AdminAuth: true,
   210  				Code:      200,
   211  			},
   212  			{
   213  				Method: "GET",
   214  				Path:   "/sample/?authorization=wrong_key_id",
   215  				Code:   403,
   216  			},
   217  			{
   218  				Method: "GET",
   219  				Path:   "/sample/?authorization=my_key_id",
   220  				Code:   200,
   221  			},
   222  			{
   223  				Method:    "GET",
   224  				Path:      "/tyk/keys/my_key_id" + "?api_id=test",
   225  				AdminAuth: true,
   226  				Code:      200,
   227  				BodyMatch: `"quota_max":5`,
   228  			},
   229  			{
   230  				Method:    "GET",
   231  				Path:      "/tyk/keys/my_key_id" + "?api_id=test",
   232  				AdminAuth: true,
   233  				Code:      200,
   234  				BodyMatch: `"quota_remaining":4`,
   235  			},
   236  		}...)
   237  
   238  		FallbackKeySesionManager.Store().DeleteAllKeys()
   239  	})
   240  
   241  	_, knownKey := ts.CreateSession(func(s *user.SessionState) {
   242  		s.AccessRights = map[string]user.AccessDefinition{"test": {
   243  			APIID: "test", Versions: []string{"v1"},
   244  		}}
   245  		s.Mutex = &sync.RWMutex{}
   246  	})
   247  
   248  	_, unknownOrgKey := ts.CreateSession(func(s *user.SessionState) {
   249  		s.OrgID = "dummy"
   250  		s.AccessRights = map[string]user.AccessDefinition{"test": {
   251  			APIID: "test", Versions: []string{"v1"},
   252  		}}
   253  		s.Mutex = &sync.RWMutex{}
   254  	})
   255  
   256  	t.Run("Get key", func(t *testing.T) {
   257  		ts.Run(t, []test.TestCase{
   258  			{Method: "GET", Path: "/tyk/keys/unknown", AdminAuth: true, Code: 404},
   259  			{Method: "GET", Path: "/tyk/keys/" + knownKey, AdminAuth: true, Code: 200},
   260  			{Method: "GET", Path: "/tyk/keys/" + knownKey + "?api_id=test", AdminAuth: true, Code: 200},
   261  			{Method: "GET", Path: "/tyk/keys/" + knownKey + "?api_id=unknown", AdminAuth: true, Code: 200},
   262  		}...)
   263  	})
   264  
   265  	t.Run("List keys", func(t *testing.T) {
   266  		ts.Run(t, []test.TestCase{
   267  			{Method: "GET", Path: "/tyk/keys/", AdminAuth: true, Code: 200, BodyMatch: knownKey},
   268  			{Method: "GET", Path: "/tyk/keys/?api_id=test", AdminAuth: true, Code: 200, BodyMatch: knownKey},
   269  			{Method: "GET", Path: "/tyk/keys/?api_id=unknown", AdminAuth: true, Code: 200, BodyMatch: knownKey},
   270  		}...)
   271  
   272  		globalConf := config.Global()
   273  		globalConf.HashKeyFunction = ""
   274  		config.SetGlobal(globalConf)
   275  		_, keyWithoutHash := ts.CreateSession(func(s *user.SessionState) {
   276  			s.AccessRights = map[string]user.AccessDefinition{"test": {
   277  				APIID: "test", Versions: []string{"v1"},
   278  			}}
   279  			s.Mutex = &sync.RWMutex{}
   280  		})
   281  
   282  		assert := func(response *http.Response, expected []string) {
   283  			var keys apiAllKeys
   284  			_ = json.NewDecoder(response.Body).Decode(&keys)
   285  			actual := keys.APIKeys
   286  
   287  			sort.Strings(expected)
   288  			sort.Strings(actual)
   289  
   290  			if !reflect.DeepEqual(expected, actual) {
   291  				t.Errorf("Expected %v, actual %v", expected, actual)
   292  			}
   293  		}
   294  
   295  		t.Run(`filter=""`, func(t *testing.T) {
   296  			resp, _ := ts.Run(t, test.TestCase{Method: "GET", Path: "/tyk/keys/", AdminAuth: true, Code: 200, BodyMatch: knownKey})
   297  			expected := []string{knownKey, unknownOrgKey, keyWithoutHash}
   298  			assert(resp, expected)
   299  		})
   300  
   301  		t.Run(`filter=orgID`, func(t *testing.T) {
   302  			resp, _ := ts.Run(t, test.TestCase{Method: "GET", Path: "/tyk/keys/?filter=" + "default", AdminAuth: true, Code: 200, BodyMatch: knownKey})
   303  			expected := []string{knownKey, keyWithoutHash}
   304  			assert(resp, expected)
   305  		})
   306  	})
   307  
   308  	t.Run("Update key", func(t *testing.T) {
   309  		ts.Run(t, []test.TestCase{
   310  			// Without data
   311  			{Method: "PUT", Path: "/tyk/keys/" + knownKey, AdminAuth: true, Code: 400},
   312  			{Method: "PUT", Path: "/tyk/keys/" + knownKey, Data: string(withAccessJSON), AdminAuth: true, Code: 200},
   313  			{Method: "PUT", Path: "/tyk/keys/" + knownKey + "?api_id=test", Data: string(withAccessJSON), AdminAuth: true, Code: 200},
   314  			{Method: "PUT", Path: "/tyk/keys/" + knownKey + "?api_id=none", Data: string(withAccessJSON), AdminAuth: true, Code: 200},
   315  		}...)
   316  	})
   317  
   318  	t.Run("Delete key", func(t *testing.T) {
   319  		ts.Run(t, []test.TestCase{
   320  			{Method: "DELETE", Path: "/tyk/keys/" + knownKey, AdminAuth: true, Code: 200, BodyMatch: `"action":"deleted"`},
   321  			{Method: "GET", Path: "/tyk/keys/" + knownKey, AdminAuth: true, Code: 404},
   322  		}...)
   323  	})
   324  }
   325  
   326  func TestKeyHandler_UpdateKey(t *testing.T) {
   327  	const testAPIID = "testAPIID"
   328  
   329  	ts := StartTest()
   330  	defer ts.Close()
   331  
   332  	BuildAndLoadAPI(func(spec *APISpec) {
   333  		spec.APIID = testAPIID
   334  		spec.UseKeylessAccess = false
   335  		spec.Auth.UseParam = true
   336  		spec.OrgID = "default"
   337  	})
   338  
   339  	pID := CreatePolicy(func(p *user.Policy) {
   340  		p.Partitions.RateLimit = true
   341  		p.Tags = []string{"p1-tag"}
   342  		p.MetaData = map[string]interface{}{
   343  			"p1-meta": "p1-value",
   344  		}
   345  	})
   346  
   347  	pID2 := CreatePolicy(func(p *user.Policy) {
   348  		p.Partitions.Quota = true
   349  		p.Tags = []string{"p2-tag"}
   350  		p.MetaData = map[string]interface{}{
   351  			"p2-meta": "p2-value",
   352  		}
   353  	})
   354  
   355  	session, key := ts.CreateSession(func(s *user.SessionState) {
   356  		s.ApplyPolicies = []string{pID}
   357  		s.Tags = []string{"key-tag1", "key-tag2"}
   358  		s.MetaData = map[string]interface{}{
   359  			"key-meta1": "key-value1",
   360  			"key-meta2": "key-value2",
   361  		}
   362  		s.AccessRights = map[string]user.AccessDefinition{testAPIID: {
   363  			APIID: testAPIID, Versions: []string{"v1"},
   364  		}}
   365  		s.Mutex = &sync.RWMutex{}
   366  	})
   367  
   368  	t.Run("Add policy not enforcing acl", func(t *testing.T) {
   369  		session.ApplyPolicies = append(session.ApplyPolicies, pID2)
   370  		sessionData, _ := json.Marshal(session)
   371  		path := fmt.Sprintf("/tyk/keys/%s", key)
   372  
   373  		_, _ = ts.Run(t, []test.TestCase{
   374  			{Method: http.MethodPut, Path: path, Data: sessionData, AdminAuth: true, Code: 200},
   375  		}...)
   376  
   377  		sessionState, found := FallbackKeySesionManager.SessionDetail(key, false)
   378  		accessRight, _ := sessionState.GetAccessRightByAPIID(testAPIID)
   379  		if !found || accessRight.APIID != testAPIID || len(sessionState.ApplyPolicies) != 2 {
   380  			t.Fatal("Adding policy to the list failed")
   381  		}
   382  	})
   383  
   384  	t.Run("Remove policy not enforcing acl", func(t *testing.T) {
   385  		session.ApplyPolicies = []string{}
   386  		sessionData, _ := json.Marshal(session)
   387  		path := fmt.Sprintf("/tyk/keys/%s", key)
   388  
   389  		_, _ = ts.Run(t, []test.TestCase{
   390  			{Method: http.MethodPut, Path: path, Data: sessionData, AdminAuth: true, Code: 200},
   391  		}...)
   392  
   393  		sessionState, found := FallbackKeySesionManager.SessionDetail(key, false)
   394  		accessRight, _ := sessionState.GetAccessRightByAPIID(testAPIID)
   395  		if !found || accessRight.APIID != testAPIID || len(sessionState.ApplyPolicies) != 0 {
   396  			t.Fatal("Removing policy from the list failed")
   397  		}
   398  	})
   399  
   400  	t.Run("Tags on key level", func(t *testing.T) {
   401  		assertTags := func(session *user.SessionState, expected []string) {
   402  			sessionData, _ := json.Marshal(session)
   403  			path := fmt.Sprintf("/tyk/keys/%s", key)
   404  
   405  			_, _ = ts.Run(t, []test.TestCase{
   406  				{Method: http.MethodPut, Path: path, Data: sessionData, AdminAuth: true, Code: 200},
   407  			}...)
   408  
   409  			sessionState, found := FallbackKeySesionManager.SessionDetail(key, false)
   410  
   411  			sort.Strings(sessionState.Tags)
   412  			sort.Strings(expected)
   413  
   414  			if !found || !reflect.DeepEqual(expected, sessionState.Tags) {
   415  				t.Fatalf("Expected %v, returned %v", expected, sessionState.Tags)
   416  			}
   417  		}
   418  
   419  		t.Run("Add", func(t *testing.T) {
   420  			expected := []string{"p1-tag", "p2-tag", "key-tag1", "key-tag2"}
   421  			session.ApplyPolicies = []string{pID, pID2}
   422  			assertTags(session, expected)
   423  		})
   424  
   425  		t.Run("Make unique", func(t *testing.T) {
   426  			expected := []string{"p1-tag", "p2-tag", "key-tag1", "key-tag2"}
   427  			session.ApplyPolicies = []string{pID, pID2}
   428  			session.Tags = append(session.Tags, "p1-tag", "key-tag1")
   429  			assertTags(session, expected)
   430  		})
   431  
   432  		t.Run("Remove", func(t *testing.T) {
   433  			expected := []string{"p1-tag", "p2-tag", "key-tag2"}
   434  			session.ApplyPolicies = []string{pID, pID2}
   435  			session.Tags = []string{"key-tag2"}
   436  			assertTags(session, expected)
   437  		})
   438  
   439  	})
   440  
   441  	t.Run("MetaData on key level", func(t *testing.T) {
   442  		assertMetaData := func(session *user.SessionState, expected map[string]interface{}) {
   443  			sessionData, _ := json.Marshal(session)
   444  			path := fmt.Sprintf("/tyk/keys/%s", key)
   445  
   446  			_, _ = ts.Run(t, []test.TestCase{
   447  				{Method: http.MethodPut, Path: path, Data: sessionData, AdminAuth: true, Code: 200},
   448  			}...)
   449  
   450  			sessionState, found := FallbackKeySesionManager.SessionDetail(key, false)
   451  
   452  			if !found || !reflect.DeepEqual(expected, sessionState.GetMetaData()) {
   453  				t.Fatalf("Expected %v, returned %v", expected, sessionState.GetMetaData())
   454  			}
   455  		}
   456  
   457  		t.Run("Add", func(t *testing.T) {
   458  			expected := map[string]interface{}{
   459  				"p1-meta":   "p1-value",
   460  				"p2-meta":   "p2-value",
   461  				"key-meta1": "key-value1",
   462  				"key-meta2": "key-value2",
   463  			}
   464  			session.ApplyPolicies = []string{pID, pID2}
   465  			assertMetaData(session, expected)
   466  		})
   467  
   468  		t.Run("Make unique", func(t *testing.T) {
   469  			expected := map[string]interface{}{
   470  				"p1-meta":   "p1-value",
   471  				"p2-meta":   "p2-value",
   472  				"key-meta1": "key-value1",
   473  				"key-meta2": "key-value2",
   474  			}
   475  			session.ApplyPolicies = []string{pID, pID2}
   476  			assertMetaData(session, expected)
   477  		})
   478  
   479  		t.Run("Remove", func(t *testing.T) {
   480  			expected := map[string]interface{}{
   481  				"p1-meta":   "p1-value",
   482  				"p2-meta":   "p2-value",
   483  				"key-meta2": "key-value2",
   484  			}
   485  			session.ApplyPolicies = []string{pID, pID2}
   486  			session.SetMetaData(map[string]interface{}{
   487  				"key-meta2": "key-value2",
   488  			})
   489  			assertMetaData(session, expected)
   490  		})
   491  	})
   492  }
   493  
   494  func TestKeyHandler_CheckKeysNotDuplicateOnUpdate(t *testing.T) {
   495  	ts := StartTest()
   496  	defer ts.Close()
   497  
   498  	BuildAndLoadAPI(func(spec *APISpec) {
   499  		spec.UseKeylessAccess = false
   500  		spec.Auth.UseParam = true
   501  	})
   502  
   503  	cases := []struct {
   504  		Name        string
   505  		IsCustomKey bool
   506  		KeyName     string
   507  	}{
   508  		{
   509  			Name:        "duplicity on update custom key",
   510  			IsCustomKey: true,
   511  			KeyName:     "my_custom_key",
   512  		},
   513  		{
   514  			Name:        "duplicity on update regular key",
   515  			IsCustomKey: false,
   516  		},
   517  	}
   518  
   519  	for _, tc := range cases {
   520  		t.Run(tc.Name, func(t *testing.T) {
   521  			FallbackKeySesionManager.Store().DeleteAllKeys()
   522  			session := CreateStandardSession()
   523  			session.AccessRights = map[string]user.AccessDefinition{"test": {
   524  				APIID: "test", Versions: []string{"v1"},
   525  			}}
   526  
   527  			keyName := tc.KeyName
   528  			if !tc.IsCustomKey {
   529  				keyName = generateToken(session.OrgID, "")
   530  			}
   531  
   532  			if err := doAddOrUpdate(keyName, session, false, true); err != nil {
   533  				t.Error("Failed to create key, ensure security settings are correct:" + err.Error())
   534  			}
   535  
   536  			requestByte, _ := json.Marshal(session)
   537  			r := httptest.NewRequest(http.MethodPut, "/tyk/keys/"+keyName, bytes.NewReader(requestByte))
   538  			handleAddOrUpdate(keyName, r, true)
   539  
   540  			sessions := FallbackKeySesionManager.Sessions("")
   541  			if len(sessions) != 1 {
   542  				t.Errorf("Sessions stored in global manager should be 1. But got: %v", len(sessions))
   543  			}
   544  
   545  		})
   546  	}
   547  }
   548  
   549  func TestHashKeyHandler(t *testing.T) {
   550  	globalConf := config.Global()
   551  	// make it to use hashes for Redis keys
   552  	globalConf.HashKeys = true
   553  	// enable hashed keys listing
   554  	globalConf.EnableHashedKeysListing = true
   555  	config.SetGlobal(globalConf)
   556  	defer ResetTestConfig()
   557  
   558  	hashTests := []struct {
   559  		hashFunction     string
   560  		expectedHashSize int
   561  		desc             string
   562  	}{
   563  		{"", 8, " Legacy tokens, fallback to murmur32"},
   564  		{storage.HashMurmur32, 8, ""},
   565  		{storage.HashMurmur64, 16, ""},
   566  		{storage.HashMurmur128, 32, ""},
   567  		{storage.HashSha256, 64, ""},
   568  		{"wrong", 16, " Should fallback to murmur64 if wrong alg"},
   569  	}
   570  
   571  	for _, tc := range hashTests {
   572  		globalConf.HashKeyFunction = tc.hashFunction
   573  		config.SetGlobal(globalConf)
   574  
   575  		t.Run(fmt.Sprintf("%sHash fn: %s", tc.desc, tc.hashFunction), func(t *testing.T) {
   576  			testHashKeyHandlerHelper(t, tc.expectedHashSize)
   577  		})
   578  		t.Run(fmt.Sprintf("%sHash fn: %s and Basic Auth", tc.desc, tc.hashFunction), func(t *testing.T) {
   579  			testHashFuncAndBAHelper(t)
   580  		})
   581  	}
   582  }
   583  
   584  func TestHashKeyHandlerLegacyWithHashFunc(t *testing.T) {
   585  	globalConf := config.Global()
   586  
   587  	globalConf.HashKeys = true
   588  	globalConf.EnableHashedKeysListing = true
   589  	// settings to create BA session with legacy key format
   590  	globalConf.HashKeyFunction = ""
   591  	config.SetGlobal(globalConf)
   592  	defer ResetTestConfig()
   593  
   594  	ts := StartTest()
   595  	defer ts.Close()
   596  
   597  	// create session with legacy key format
   598  	session := testPrepareBasicAuth(false)
   599  
   600  	ts.Run(t, []test.TestCase{
   601  		{
   602  			Method:    "POST",
   603  			Path:      "/tyk/keys/defaultuser",
   604  			Data:      session,
   605  			AdminAuth: true,
   606  			Code:      200,
   607  		},
   608  		{
   609  			Method:    "GET",
   610  			Path:      "/tyk/keys/defaultuser?username=true&org_id=default",
   611  			AdminAuth: true,
   612  			Code:      200,
   613  		},
   614  	}...)
   615  
   616  	// set custom hashing function and check if we still can get BA session with legacy key format
   617  	globalConf.HashKeyFunction = storage.HashMurmur64
   618  	config.SetGlobal(globalConf)
   619  
   620  	ts.Run(t, []test.TestCase{
   621  		{
   622  			Method:    "GET",
   623  			Path:      "/tyk/keys/defaultuser?username=true&org_id=default",
   624  			AdminAuth: true,
   625  			Code:      200,
   626  		},
   627  		{
   628  			Method:    "DELETE",
   629  			Path:      "/tyk/keys/defaultuser?username=true&org_id=default",
   630  			AdminAuth: true,
   631  			Code:      200,
   632  			BodyMatch: `"action":"deleted"`,
   633  		},
   634  	}...)
   635  }
   636  
   637  func testHashKeyHandlerHelper(t *testing.T, expectedHashSize int) {
   638  	ts := StartTest()
   639  	defer ts.Close()
   640  
   641  	BuildAndLoadAPI()
   642  
   643  	withAccess := CreateStandardSession()
   644  	withAccess.AccessRights = map[string]user.AccessDefinition{"test": {
   645  		APIID: "test", Versions: []string{"v1"},
   646  	}}
   647  	withAccessJSON, _ := json.Marshal(withAccess)
   648  
   649  	myKey := "my_key_id"
   650  	myKeyHash := storage.HashKey(generateToken("default", myKey))
   651  
   652  	if len(myKeyHash) != expectedHashSize {
   653  		t.Errorf("Expected hash size: %d, got %d. Hash: %s. Key: %s", expectedHashSize, len(myKeyHash), myKeyHash, myKey)
   654  	}
   655  
   656  	t.Run("Create, get and delete key with key hashing", func(t *testing.T) {
   657  		ts.Run(t, []test.TestCase{
   658  			// create key
   659  			{
   660  				Method:    "POST",
   661  				Path:      "/tyk/keys/create",
   662  				Data:      string(withAccessJSON),
   663  				AdminAuth: true,
   664  				Code:      200,
   665  				BodyMatch: `"key_hash"`,
   666  			},
   667  			{
   668  				Method:    "POST",
   669  				Path:      "/tyk/keys",
   670  				Data:      string(withAccessJSON),
   671  				AdminAuth: true,
   672  				Code:      200,
   673  				BodyMatch: `"key_hash"`,
   674  			},
   675  			// create key with custom value
   676  			{
   677  				Method:    "POST",
   678  				Path:      "/tyk/keys/" + myKey,
   679  				Data:      string(withAccessJSON),
   680  				AdminAuth: true,
   681  				Code:      200,
   682  				BodyMatch: fmt.Sprintf(`"key_hash":"%s"`, myKeyHash),
   683  			},
   684  			// Update key by hash value with specifying hashed=true
   685  			{
   686  				Method:    "PUT",
   687  				Path:      "/tyk/keys/" + myKeyHash + "?hashed=true",
   688  				Data:      string(withAccessJSON),
   689  				AdminAuth: true,
   690  				Code:      200,
   691  				BodyMatch: fmt.Sprintf(`"key":"%s"`, myKeyHash),
   692  			},
   693  			// get one key by key name (API specified)
   694  			{
   695  				Method:    "GET",
   696  				Path:      "/tyk/keys/" + myKey + "?api_id=test",
   697  				Data:      string(withAccessJSON),
   698  				AdminAuth: true,
   699  				Code:      200,
   700  			},
   701  			// get one key by hash value with specifying hashed=true (no API specified)
   702  			{
   703  				Method:    "GET",
   704  				Path:      "/tyk/keys/" + myKeyHash + "?hashed=true",
   705  				Data:      string(withAccessJSON),
   706  				AdminAuth: true,
   707  				Code:      200,
   708  			},
   709  			// get one key by hash value with specifying hashed=true (API specified)
   710  			{
   711  				Method:    "GET",
   712  				Path:      "/tyk/keys/" + myKeyHash + "?hashed=true&api_id=test",
   713  				Data:      string(withAccessJSON),
   714  				AdminAuth: true,
   715  				Code:      200,
   716  			},
   717  			// get one key by hash value without specifying hashed=true
   718  			{
   719  				Method:    "GET",
   720  				Path:      "/tyk/keys/" + myKeyHash,
   721  				Data:      string(withAccessJSON),
   722  				AdminAuth: true,
   723  				Code:      404,
   724  			},
   725  			// get list of keys' hashes, no API specified
   726  			{
   727  				Method:    "GET",
   728  				Path:      "/tyk/keys",
   729  				Data:      string(withAccessJSON),
   730  				AdminAuth: true,
   731  				Code:      200,
   732  				BodyMatch: myKeyHash,
   733  			},
   734  			// get list of keys' hashes, API specified
   735  			{
   736  				Method:    "GET",
   737  				Path:      "/tyk/keys?api_id=test",
   738  				Data:      string(withAccessJSON),
   739  				AdminAuth: true,
   740  				Code:      200,
   741  				BodyMatch: myKeyHash,
   742  			},
   743  			// delete one key by hash value with specifying hashed=true
   744  			{
   745  				Method:    "DELETE",
   746  				Path:      "/tyk/keys/" + myKeyHash + "?hashed=true&api_id=test",
   747  				Data:      string(withAccessJSON),
   748  				AdminAuth: true,
   749  				Code:      200,
   750  			},
   751  			// check that key is not present any more
   752  			{
   753  				Method:    "GET",
   754  				Path:      "/tyk/keys/" + myKeyHash + "?hashed=true&api_id=test",
   755  				Data:      string(withAccessJSON),
   756  				AdminAuth: true,
   757  				Code:      404,
   758  			},
   759  		}...)
   760  	})
   761  }
   762  
   763  func testHashFuncAndBAHelper(t *testing.T) {
   764  	ts := StartTest()
   765  	defer ts.Close()
   766  
   767  	session := testPrepareBasicAuth(false)
   768  
   769  	ts.Run(t, []test.TestCase{
   770  		{
   771  			Method:    "POST",
   772  			Path:      "/tyk/keys/defaultuser",
   773  			Data:      session,
   774  			AdminAuth: true,
   775  			Code:      200,
   776  		},
   777  		{
   778  			Method:    "GET",
   779  			Path:      "/tyk/keys/defaultuser?username=true&org_id=default",
   780  			AdminAuth: true,
   781  			Code:      200,
   782  		},
   783  		{
   784  			Method:    "DELETE",
   785  			Path:      "/tyk/keys/defaultuser?username=true&org_id=default",
   786  			AdminAuth: true,
   787  			Code:      200,
   788  			BodyMatch: `"action":"deleted"`,
   789  		},
   790  	}...)
   791  }
   792  
   793  func TestHashKeyListingDisabled(t *testing.T) {
   794  	globalConf := config.Global()
   795  	// make it to use hashes for Redis keys
   796  	globalConf.HashKeys = true
   797  	// disable hashed keys listing
   798  	globalConf.EnableHashedKeysListing = false
   799  	config.SetGlobal(globalConf)
   800  
   801  	defer ResetTestConfig()
   802  
   803  	ts := StartTest()
   804  	defer ts.Close()
   805  
   806  	BuildAndLoadAPI()
   807  
   808  	withAccess := CreateStandardSession()
   809  	withAccess.AccessRights = map[string]user.AccessDefinition{"test": {
   810  		APIID: "test", Versions: []string{"v1"},
   811  	}}
   812  	withAccessJSON, _ := json.Marshal(withAccess)
   813  
   814  	myKey := "my_key_id"
   815  	myKeyHash := storage.HashKey(generateToken("default", myKey))
   816  
   817  	t.Run("Create, get and delete key with key hashing", func(t *testing.T) {
   818  		ts.Run(t, []test.TestCase{
   819  			// create key
   820  			{
   821  				Method:    "POST",
   822  				Path:      "/tyk/keys/create",
   823  				Data:      string(withAccessJSON),
   824  				AdminAuth: true,
   825  				Code:      200,
   826  				BodyMatch: `"key_hash"`,
   827  			},
   828  			{
   829  				Method:    "POST",
   830  				Path:      "/tyk/keys",
   831  				Data:      string(withAccessJSON),
   832  				AdminAuth: true,
   833  				Code:      200,
   834  				BodyMatch: `"key_hash"`,
   835  			},
   836  			// create key with custom value
   837  			{
   838  				Method:    "POST",
   839  				Path:      "/tyk/keys/" + myKey,
   840  				Data:      string(withAccessJSON),
   841  				AdminAuth: true,
   842  				Code:      200,
   843  				BodyMatch: fmt.Sprintf(`"key_hash":"%s"`, myKeyHash),
   844  			},
   845  			// get one key by key name (API specified)
   846  			{
   847  				Method:    "GET",
   848  				Path:      "/tyk/keys/" + myKey + "?api_id=test",
   849  				Data:      string(withAccessJSON),
   850  				AdminAuth: true,
   851  				Code:      200,
   852  			},
   853  			// get one key by hash value with specifying hashed=true (no API specified)
   854  			{
   855  				Method:    "GET",
   856  				Path:      "/tyk/keys/" + myKeyHash + "?hashed=true",
   857  				Data:      string(withAccessJSON),
   858  				AdminAuth: true,
   859  				Code:      200,
   860  			},
   861  			// get one key by hash value with specifying hashed=true (API specified)
   862  			{
   863  				Method:    "GET",
   864  				Path:      "/tyk/keys/" + myKeyHash + "?hashed=true&api_id=test",
   865  				Data:      string(withAccessJSON),
   866  				AdminAuth: true,
   867  				Code:      200,
   868  			},
   869  			// get one key by hash value without specifying hashed=true
   870  			{
   871  				Method:    "GET",
   872  				Path:      "/tyk/keys/" + myKeyHash,
   873  				Data:      string(withAccessJSON),
   874  				AdminAuth: true,
   875  				Code:      404,
   876  			},
   877  			// get list of keys' hashes, no API specified
   878  			{
   879  				Method:    "GET",
   880  				Path:      "/tyk/keys",
   881  				Data:      string(withAccessJSON),
   882  				AdminAuth: true,
   883  				Code:      404,
   884  			},
   885  			// get list of keys' hashes, API specified
   886  			{
   887  				Method:    "GET",
   888  				Path:      "/tyk/keys?api_id=test",
   889  				Data:      string(withAccessJSON),
   890  				AdminAuth: true,
   891  				Code:      404,
   892  			},
   893  			// delete one key by hash value with specifying hashed=true
   894  			{
   895  				Method:    "DELETE",
   896  				Path:      "/tyk/keys/" + myKeyHash + "?hashed=true&api_id=test",
   897  				Data:      string(withAccessJSON),
   898  				AdminAuth: true,
   899  				Code:      200,
   900  			},
   901  			// check that key is not present any more
   902  			{
   903  				Method:    "GET",
   904  				Path:      "/tyk/keys/" + myKeyHash + "?hashed=true&api_id=test",
   905  				Data:      string(withAccessJSON),
   906  				AdminAuth: true,
   907  				Code:      404,
   908  			},
   909  		}...)
   910  	})
   911  }
   912  
   913  func TestKeyHandler_HashingDisabled(t *testing.T) {
   914  	globalConf := config.Global()
   915  	// make it to NOT use hashes for Redis keys
   916  	globalConf.HashKeys = false
   917  	config.SetGlobal(globalConf)
   918  
   919  	defer ResetTestConfig()
   920  
   921  	ts := StartTest()
   922  	defer ts.Close()
   923  
   924  	BuildAndLoadAPI()
   925  
   926  	withAccess := CreateStandardSession()
   927  	withAccess.AccessRights = map[string]user.AccessDefinition{"test": {
   928  		APIID: "test", Versions: []string{"v1"},
   929  	}}
   930  	withAccessJSON, _ := json.Marshal(withAccess)
   931  
   932  	myKeyID := "my_key_id"
   933  	token := generateToken("default", myKeyID)
   934  	myKeyHash := storage.HashKey(token)
   935  
   936  	t.Run("Create, get and delete key with key hashing", func(t *testing.T) {
   937  		_, _ = ts.Run(t, []test.TestCase{
   938  			// create key
   939  			{
   940  				Method:       "POST",
   941  				Path:         "/tyk/keys/create",
   942  				Data:         string(withAccessJSON),
   943  				AdminAuth:    true,
   944  				Code:         200,
   945  				BodyNotMatch: `"key_hash"`,
   946  			},
   947  			{
   948  				Method:       "POST",
   949  				Path:         "/tyk/keys",
   950  				Data:         string(withAccessJSON),
   951  				AdminAuth:    true,
   952  				Code:         200,
   953  				BodyNotMatch: `"key_hash"`,
   954  			},
   955  			// create key with custom key ID
   956  			{
   957  				Method:       "POST",
   958  				Path:         "/tyk/keys/" + myKeyID,
   959  				Data:         string(withAccessJSON),
   960  				AdminAuth:    true,
   961  				Code:         200,
   962  				BodyMatch:    fmt.Sprintf(`"key":"%s"`, token),
   963  				BodyNotMatch: fmt.Sprintf(`"key_hash":"%s"`, myKeyHash),
   964  			},
   965  			// get one key by generated token
   966  			{
   967  				Method:    "GET",
   968  				Path:      "/tyk/keys/" + token,
   969  				AdminAuth: true,
   970  				Code:      200,
   971  			},
   972  			// get one key by hash value with specifying hashed=true (no API specified)
   973  			{
   974  				Method:    "GET",
   975  				Path:      "/tyk/keys/" + myKeyHash + "?hashed=true",
   976  				AdminAuth: true,
   977  				Code:      400,
   978  			},
   979  			// get one key by hash value with specifying hashed=true (API specified)
   980  			{
   981  				Method:    "GET",
   982  				Path:      "/tyk/keys/" + myKeyHash + "?hashed=true&api_id=test",
   983  				AdminAuth: true,
   984  				Code:      400,
   985  			},
   986  			// delete one key by hash value with specifying hashed=true
   987  			{
   988  				Method:    "DELETE",
   989  				Path:      "/tyk/keys/" + myKeyHash + "?hashed=true&api_id=test",
   990  				AdminAuth: true,
   991  				Code:      200,
   992  			},
   993  		}...)
   994  	})
   995  }
   996  
   997  func TestInvalidateCache(t *testing.T) {
   998  	ts := StartTest()
   999  	defer ts.Close()
  1000  
  1001  	BuildAndLoadAPI()
  1002  
  1003  	ts.Run(t, []test.TestCase{
  1004  		{Method: "DELETE", Path: "/tyk/cache/test", AdminAuth: true, Code: 200},
  1005  		{Method: "DELETE", Path: "/tyk/cache/test/", AdminAuth: true, Code: 200},
  1006  	}...)
  1007  }
  1008  
  1009  func TestGetOAuthClients(t *testing.T) {
  1010  	ts := StartTest()
  1011  	defer ts.Close()
  1012  
  1013  	BuildAndLoadAPI(func(spec *APISpec) {
  1014  		spec.UseOauth2 = true
  1015  	})
  1016  
  1017  	oauthRequest := NewClientRequest{
  1018  		ClientID:          "test",
  1019  		ClientRedirectURI: "http://localhost",
  1020  		APIID:             "test",
  1021  		ClientSecret:      "secret",
  1022  	}
  1023  	validOauthRequest, _ := json.Marshal(oauthRequest)
  1024  
  1025  	ts.Run(t, []test.TestCase{
  1026  		{Path: "/tyk/oauth/clients/unknown", AdminAuth: true, Code: 404},
  1027  		{Path: "/tyk/oauth/clients/test", AdminAuth: true, Code: 200, BodyMatch: `\[\]`},
  1028  		{Method: "POST", Path: "/tyk/oauth/clients/create", AdminAuth: true, Data: string(validOauthRequest), Code: 200},
  1029  		{Path: "/tyk/oauth/clients/test", AdminAuth: true, Code: 200, BodyMatch: `\[{"client_id":"test"`},
  1030  	}...)
  1031  }
  1032  
  1033  func TestCreateOAuthClient(t *testing.T) {
  1034  	ts := StartTest()
  1035  	defer ts.Close()
  1036  
  1037  	BuildAndLoadAPI(
  1038  		func(spec *APISpec) {
  1039  			spec.UseOauth2 = true
  1040  		},
  1041  		func(spec *APISpec) {
  1042  			spec.APIID = "non_oauth_api"
  1043  			spec.UseOauth2 = false
  1044  		},
  1045  	)
  1046  
  1047  	CreatePolicy(func(p *user.Policy) {
  1048  		p.ID = "p1"
  1049  		p.AccessRights = map[string]user.AccessDefinition{
  1050  			"test": {
  1051  				APIID: "test",
  1052  			},
  1053  		}
  1054  	})
  1055  	CreatePolicy(func(p *user.Policy) {
  1056  		p.ID = "p2"
  1057  		p.AccessRights = map[string]user.AccessDefinition{
  1058  			"test": {
  1059  				APIID: "test",
  1060  			},
  1061  			"abc": {
  1062  				APIID: "abc",
  1063  			},
  1064  		}
  1065  	})
  1066  
  1067  	tests := map[string]struct {
  1068  		req       NewClientRequest
  1069  		code      int
  1070  		bodyMatch string
  1071  	}{
  1072  		"no api_id but policy_id provided": {
  1073  			req: NewClientRequest{
  1074  				ClientID: "client_test1",
  1075  				PolicyID: "p1",
  1076  			},
  1077  			code:      http.StatusOK,
  1078  			bodyMatch: `client_id":"client_test1"`,
  1079  		},
  1080  		"no policy_id but api_id provided": {
  1081  			req: NewClientRequest{
  1082  				ClientID: "client_test2",
  1083  				APIID:    "test",
  1084  			},
  1085  			code:      http.StatusOK,
  1086  			bodyMatch: `client_id":"client_test2"`,
  1087  		},
  1088  		// "both api_id and policy_id provided": {
  1089  		// 	req: NewClientRequest{
  1090  		// 		PolicyID: "p1",
  1091  		// 		APIID:    "test",
  1092  		// 	},
  1093  		// 	code:      http.StatusBadRequest,
  1094  		// 	bodyMatch: "both api_id and policy_id specified",
  1095  		// },
  1096  		"policy does not exist": {
  1097  			req: NewClientRequest{
  1098  				PolicyID: "unknown",
  1099  			},
  1100  			code:      http.StatusBadRequest,
  1101  			bodyMatch: "Policy doesn't exist",
  1102  		},
  1103  		"API does not exist": {
  1104  			req: NewClientRequest{
  1105  				APIID: "unknown",
  1106  			},
  1107  			code:      http.StatusBadRequest,
  1108  			bodyMatch: "API doesn't exist",
  1109  		},
  1110  		// "policy should contain only one API": {
  1111  		// 	req: NewClientRequest{
  1112  		// 		PolicyID: "p2",
  1113  		// 	},
  1114  		// 	code:      http.StatusBadRequest,
  1115  		// 	bodyMatch: "should contain only one API",
  1116  		// },
  1117  		"API is not OAuth": {
  1118  			req: NewClientRequest{
  1119  				APIID: "non_oauth_api",
  1120  			},
  1121  			code:      http.StatusBadRequest,
  1122  			bodyMatch: "API is not OAuth2",
  1123  		},
  1124  	}
  1125  
  1126  	for testName, testData := range tests {
  1127  		t.Run(testName, func(t *testing.T) {
  1128  			requestData, _ := json.Marshal(testData.req)
  1129  			ts.Run(
  1130  				t,
  1131  				test.TestCase{
  1132  					Method:    http.MethodPost,
  1133  					Path:      "/tyk/oauth/clients/create",
  1134  					AdminAuth: true,
  1135  					Data:      string(requestData),
  1136  					Code:      testData.code,
  1137  					BodyMatch: testData.bodyMatch,
  1138  				},
  1139  			)
  1140  		})
  1141  	}
  1142  }
  1143  
  1144  func TestUpdateOauthClientHandler(t *testing.T) {
  1145  
  1146  	ts := StartTest()
  1147  	defer ts.Close()
  1148  
  1149  	BuildAndLoadAPI(
  1150  		func(spec *APISpec) {
  1151  			spec.UseOauth2 = true
  1152  		},
  1153  		func(spec *APISpec) {
  1154  			spec.APIID = "non_oauth_api"
  1155  			spec.UseOauth2 = false
  1156  		},
  1157  	)
  1158  
  1159  	CreatePolicy(func(p *user.Policy) {
  1160  		p.ID = "p1"
  1161  		p.AccessRights = map[string]user.AccessDefinition{
  1162  			"test": {
  1163  				APIID: "test",
  1164  			},
  1165  		}
  1166  	})
  1167  	CreatePolicy(func(p *user.Policy) {
  1168  		p.ID = "p2"
  1169  		p.AccessRights = map[string]user.AccessDefinition{
  1170  			"test": {
  1171  				APIID: "test",
  1172  			},
  1173  			"abc": {
  1174  				APIID: "abc",
  1175  			},
  1176  		}
  1177  	})
  1178  
  1179  	var b bytes.Buffer
  1180  
  1181  	json.NewEncoder(&b).Encode(NewClientRequest{
  1182  		ClientID: "12345",
  1183  		APIID:    "test",
  1184  		PolicyID: "p1",
  1185  	})
  1186  
  1187  	ts.Run(
  1188  		t,
  1189  		test.TestCase{
  1190  			Method:    http.MethodPost,
  1191  			Path:      "/tyk/oauth/clients/create",
  1192  			AdminAuth: true,
  1193  			Data:      b.String(),
  1194  			Code:      http.StatusOK,
  1195  			BodyMatch: `"client_id":"12345"`,
  1196  		},
  1197  	)
  1198  
  1199  	tests := map[string]struct {
  1200  		req          NewClientRequest
  1201  		code         int
  1202  		bodyMatch    string
  1203  		bodyNotMatch string
  1204  	}{
  1205  		"Update description": {
  1206  			req: NewClientRequest{
  1207  				ClientID:    "12345",
  1208  				APIID:       "test",
  1209  				PolicyID:    "p1",
  1210  				Description: "Updated field",
  1211  			},
  1212  			code:         http.StatusOK,
  1213  			bodyMatch:    `"description":"Updated field"`,
  1214  			bodyNotMatch: "",
  1215  		},
  1216  		"Secret cannot be updated": {
  1217  			req: NewClientRequest{
  1218  				ClientID:     "12345",
  1219  				APIID:        "test",
  1220  				PolicyID:     "p1",
  1221  				Description:  "Updated field",
  1222  				ClientSecret: "super-new-secret",
  1223  			},
  1224  			code:         http.StatusOK,
  1225  			bodyNotMatch: `"secret":"super-new-secret"`,
  1226  			bodyMatch:    "",
  1227  		},
  1228  	}
  1229  
  1230  	for testName, testData := range tests {
  1231  		t.Run(testName, func(t *testing.T) {
  1232  			requestData, _ := json.Marshal(testData.req)
  1233  			testCase := test.TestCase{
  1234  				Method:    http.MethodPut,
  1235  				Path:      "/tyk/oauth/clients/test/12345",
  1236  				AdminAuth: true,
  1237  				Data:      string(requestData),
  1238  				Code:      testData.code,
  1239  			}
  1240  
  1241  			if testData.bodyMatch != "" {
  1242  				testCase.BodyMatch = testData.bodyMatch
  1243  			}
  1244  
  1245  			if testData.bodyNotMatch != "" {
  1246  				testCase.BodyNotMatch = testData.bodyNotMatch
  1247  			}
  1248  
  1249  			ts.Run(t, testCase)
  1250  		})
  1251  	}
  1252  }
  1253  
  1254  func TestGroupResetHandler(t *testing.T) {
  1255  	didSubscribe := make(chan bool)
  1256  	didReload := make(chan bool)
  1257  	cacheStore := storage.RedisCluster{}
  1258  	cacheStore.Connect()
  1259  
  1260  	go func() {
  1261  		err := cacheStore.StartPubSubHandler(RedisPubSubChannel, func(v interface{}) {
  1262  			switch x := v.(type) {
  1263  			case *redis.Subscription:
  1264  				didSubscribe <- true
  1265  			case *redis.Message:
  1266  				notf := Notification{}
  1267  				if err := json.Unmarshal([]byte(x.Payload), &notf); err != nil {
  1268  					t.Fatal(err)
  1269  				}
  1270  				if notf.Command == NoticeGroupReload {
  1271  					didReload <- true
  1272  				}
  1273  			}
  1274  		})
  1275  		if err != nil {
  1276  			t.Log(err)
  1277  			t.Fail()
  1278  			close(didReload)
  1279  		}
  1280  	}()
  1281  
  1282  	uri := "/tyk/reload/group"
  1283  
  1284  	apisMu.Lock()
  1285  	apisByID = make(map[string]*APISpec)
  1286  	apisMu.Unlock()
  1287  
  1288  	LoadSampleAPI(apiTestDef)
  1289  
  1290  	recorder := httptest.NewRecorder()
  1291  
  1292  	// If we don't wait for the subscription to be done, we might do
  1293  	// the reload before pub/sub is in place to receive our message.
  1294  	<-didSubscribe
  1295  	req := withAuth(TestReq(t, "GET", uri, nil))
  1296  
  1297  	mainRouter().ServeHTTP(recorder, req)
  1298  
  1299  	if recorder.Code != 200 {
  1300  		t.Fatal("Hot reload (group) failed, response code was: ", recorder.Code)
  1301  	}
  1302  
  1303  	apisMu.RLock()
  1304  	if len(apisByID) == 0 {
  1305  		t.Fatal("Hot reload (group) was triggered but no APIs were found.")
  1306  	}
  1307  	apisMu.RUnlock()
  1308  
  1309  	// We wait for the right notification (NoticeGroupReload), other
  1310  	// type of notifications may be received during tests, as this
  1311  	// is the cluster channel:
  1312  	<-didReload
  1313  }
  1314  
  1315  func TestHotReloadSingle(t *testing.T) {
  1316  	ReloadTestCase.Enable()
  1317  	defer ReloadTestCase.Disable()
  1318  	oldRouter := mainRouter()
  1319  	var wg sync.WaitGroup
  1320  	wg.Add(1)
  1321  	reloadURLStructure(wg.Done)
  1322  	ReloadTestCase.TickOk(t)
  1323  	wg.Wait()
  1324  	if mainRouter() == oldRouter {
  1325  		t.Fatal("router wasn't swapped")
  1326  	}
  1327  }
  1328  
  1329  func BenchmarkApiReload(b *testing.B) {
  1330  	b.ReportAllocs()
  1331  
  1332  	specs := make([]*APISpec, 100)
  1333  
  1334  	for i := 0; i < 100; i++ {
  1335  		specs[i] = BuildAndLoadAPI(func(spec *APISpec) {
  1336  			spec.APIID = strconv.Itoa(i + 1)
  1337  		})[0]
  1338  	}
  1339  
  1340  	b.ResetTimer()
  1341  	for i := 0; i < b.N; i++ {
  1342  		loadAPIEndpoints(nil)
  1343  		loadApps(specs)
  1344  	}
  1345  }
  1346  
  1347  func TestContextData(t *testing.T) {
  1348  	r := new(http.Request)
  1349  	if ctxGetData(r) != nil {
  1350  		t.Fatal("expected ctxGetData to return nil")
  1351  	}
  1352  	ctxSetData(r, map[string]interface{}{"foo": "bar"})
  1353  	if ctxGetData(r) == nil {
  1354  		t.Fatal("expected ctxGetData to return non-nil")
  1355  	}
  1356  	defer func() {
  1357  		if r := recover(); r == nil {
  1358  			t.Fatal("expected ctxSetData of zero val to panic")
  1359  		}
  1360  	}()
  1361  	ctxSetData(r, nil)
  1362  }
  1363  
  1364  func TestContextSession(t *testing.T) {
  1365  	r := new(http.Request)
  1366  	if ctxGetSession(r) != nil {
  1367  		t.Fatal("expected ctxGetSession to return nil")
  1368  	}
  1369  	ctxSetSession(r,
  1370  		&user.SessionState{
  1371  			Mutex: &sync.RWMutex{},
  1372  		},
  1373  		"",
  1374  		false)
  1375  	if ctxGetSession(r) == nil {
  1376  		t.Fatal("expected ctxGetSession to return non-nil")
  1377  	}
  1378  	defer func() {
  1379  		if r := recover(); r == nil {
  1380  			t.Fatal("expected ctxSetSession of zero val to panic")
  1381  		}
  1382  	}()
  1383  	ctxSetSession(r, nil, "", false)
  1384  }
  1385  
  1386  func TestApiLoaderLongestPathFirst(t *testing.T) {
  1387  	globalConf := config.Global()
  1388  	globalConf.EnableCustomDomains = true
  1389  	config.SetGlobal(globalConf)
  1390  
  1391  	defer ResetTestConfig()
  1392  
  1393  	type hostAndPath struct {
  1394  		host, path string
  1395  	}
  1396  	inputs := map[hostAndPath]bool{}
  1397  	hosts := []string{"host1.local", "host2.local", "host3.local"}
  1398  	paths := []string{"a", "ab", "a/b/c", "ab/c", "abc", "a/b/c"}
  1399  	// Use a map so that we get a somewhat random order when
  1400  	// iterating. Would be better to use math/rand.Shuffle once we
  1401  	// need only support Go 1.10 and later.
  1402  	for _, host := range hosts {
  1403  		for _, path := range paths {
  1404  			inputs[hostAndPath{host, path}] = true
  1405  		}
  1406  	}
  1407  
  1408  	var apis []*APISpec
  1409  
  1410  	for hp := range inputs {
  1411  		apis = append(apis, BuildAPI(func(spec *APISpec) {
  1412  			spec.APIID = uuid.NewV4().String()
  1413  			spec.Domain = hp.host
  1414  			spec.Proxy.ListenPath = "/" + hp.path
  1415  		})[0])
  1416  	}
  1417  
  1418  	ts := StartTest()
  1419  	defer ts.Close()
  1420  	LoadAPI(apis...)
  1421  
  1422  	var testCases []test.TestCase
  1423  
  1424  	for hp := range inputs {
  1425  		testCases = append(testCases, test.TestCase{
  1426  			Path:      "/" + hp.path,
  1427  			Domain:    hp.host,
  1428  			Code:      200,
  1429  			BodyMatch: `"Url":"/` + hp.path + `"`,
  1430  		})
  1431  	}
  1432  
  1433  	ts.Run(t, testCases...)
  1434  }