github.com/anuvu/tyk@v2.9.0-beta9-dl-apic+incompatible/gateway/looping_test.go (about)

     1  // +build !race
     2  
     3  // Looping by itself has race nature
     4  package gateway
     5  
     6  import (
     7  	"encoding/json"
     8  	"sync"
     9  	"testing"
    10  
    11  	"github.com/TykTechnologies/tyk/test"
    12  	"github.com/TykTechnologies/tyk/user"
    13  )
    14  
    15  func TestLooping(t *testing.T) {
    16  	ts := StartTest()
    17  	defer ts.Close()
    18  
    19  	postAction := `<operation action="https://example.com/post_action">data</operation>`
    20  	getAction := `<operation action="https://example.com/get_action">data</operation>`
    21  
    22  	t.Run("Using advanced URL rewrite", func(t *testing.T) {
    23  		// We defined internnal advanced rewrite based on body data
    24  		// which rewrites to internal paths (marked as blacklist so they protected from outside world)
    25  		BuildAndLoadAPI(func(spec *APISpec) {
    26  			version := spec.VersionData.Versions["v1"]
    27  			json.Unmarshal([]byte(`{
    28                  "use_extended_paths": true,
    29                  "extended_paths": {
    30                      "internal": [{
    31                          "path": "/get_action",
    32                          "method": "GET"
    33                      },{
    34                          "path": "/post_action",
    35                          "method": "POST"
    36                      }],
    37                      "white_list": [{
    38                          "path": "/xml",
    39                          "method_actions": {"POST": {"action": "no_action"}}
    40                      }],
    41                      "url_rewrites": [{
    42                          "path": "/xml",
    43                          "method": "POST",
    44                          "match_pattern": "/xml(.*)",
    45                          "rewrite_to": "/xml$1",
    46                          "triggers": [
    47                            {
    48                              "on": "all",
    49                              "options": {
    50                                "payload_matches": {
    51                                  "match_rx": "post_action"
    52                                }
    53                              },
    54                              "rewrite_to": "tyk://self/post_action"
    55                            },
    56                            {
    57                              "on": "all",
    58                              "options": {
    59                                "payload_matches": {
    60                                  "match_rx": "get_action"
    61                                }
    62                              },
    63                              "rewrite_to": "tyk://self/get_action?method=GET"
    64                            }
    65                          ]
    66                      }]
    67                  }
    68              }`), &version)
    69  
    70  			spec.VersionData.Versions["v1"] = version
    71  
    72  			spec.Proxy.ListenPath = "/"
    73  		})
    74  
    75  		ts.Run(t, []test.TestCase{
    76  			{Method: "POST", Path: "/xml", Data: postAction, BodyMatch: `"Url":"/post_action`},
    77  
    78  			// Should retain original query params
    79  			{Method: "POST", Path: "/xml?a=b", Data: getAction, BodyMatch: `"Url":"/get_action`},
    80  
    81  			// Should rewrite http method, if loop rewrite param passed
    82  			{Method: "POST", Path: "/xml", Data: getAction, BodyMatch: `"Method":"GET"`},
    83  
    84  			// Internal endpoint can be accessed only via looping
    85  			{Method: "GET", Path: "/get_action", Code: 403},
    86  
    87  			{Method: "POST", Path: "/get_action", Code: 403},
    88  		}...)
    89  	})
    90  
    91  	t.Run("Test multiple url rewrites", func(t *testing.T) {
    92  		BuildAndLoadAPI(func(spec *APISpec) {
    93  			version := spec.VersionData.Versions["v1"]
    94  			json.Unmarshal([]byte(`{
    95                  "use_extended_paths": true,
    96                  "extended_paths": {
    97  			"internal": [{
    98                          	"path": "/hidden_path",
    99                          	"method": "GET"
   100                      	}],
   101  			"url_rewrites": [{
   102                          	"path": "/test",
   103                          	"match_pattern": "/test",
   104                          	"method": "GET",
   105  				"rewrite_to":"tyk://self/hidden_path_1"
   106                      	},{
   107                          	"path": "/hidden_path_1",
   108                          	"match_pattern": "/hidden_path_1",
   109                          	"method": "GET",
   110  				"rewrite_to":"tyk://self/hidden_path_2"
   111                      	},{
   112                          	"path": "/hidden_path_2",
   113                          	"match_pattern": "/hidden_path_2",
   114                          	"method": "GET",
   115  				"rewrite_to":"/upstream"
   116  		    	}]
   117                  }
   118              }`), &version)
   119  
   120  			spec.VersionData.Versions["v1"] = version
   121  			spec.Proxy.ListenPath = "/"
   122  		})
   123  
   124  		//addHeaders := map[string]string{"X-Test": "test", "X-Internal": "test"}
   125  
   126  		ts.Run(t, []test.TestCase{
   127  			{Method: "GET", Path: "/test", BodyMatch: `"Url":"/upstream"`},
   128  		}...)
   129  	})
   130  
   131  	t.Run("Loop to another API", func(t *testing.T) {
   132  		BuildAndLoadAPI(func(spec *APISpec) {
   133  			spec.APIID = "testid"
   134  			spec.Name = "hidden api"
   135  			spec.Proxy.ListenPath = "/somesecret"
   136  			spec.Internal = true
   137  			version := spec.VersionData.Versions["v1"]
   138  			json.Unmarshal([]byte(`{
   139                  "use_extended_paths": true,
   140                  "global_headers": {
   141                      "X-Name":"internal"
   142                  }
   143              }`), &version)
   144  			spec.VersionData.Versions["v1"] = version
   145  		}, func(spec *APISpec) {
   146  			spec.Proxy.ListenPath = "/test"
   147  
   148  			version := spec.VersionData.Versions["v1"]
   149  			json.Unmarshal([]byte(`{
   150                  "use_extended_paths": true,
   151                  "extended_paths": {
   152                      "url_rewrites": [{
   153                          "path": "/by_name",
   154                          "match_pattern": "/by_name(.*)",
   155                          "method": "GET",
   156                          "rewrite_to": "tyk://hidden api/get"
   157                      },{
   158                          "path": "/by_id",
   159                          "match_pattern": "/by_id(.*)",
   160                          "method": "GET",
   161                          "rewrite_to": "tyk://testid/get"
   162                      },{
   163                          "path": "/wrong",
   164                          "match_pattern": "/wrong(.*)",
   165                          "method": "GET",
   166                          "rewrite_to": "tyk://wrong/get"
   167                      }]
   168                  }
   169              }`), &version)
   170  
   171  			spec.VersionData.Versions["v1"] = version
   172  		})
   173  
   174  		ts.Run(t, []test.TestCase{
   175  			{Path: "/somesecret", Code: 404},
   176  			{Path: "/test/by_name", Code: 200, BodyMatch: `"X-Name":"internal"`},
   177  			{Path: "/test/by_id", Code: 200, BodyMatch: `"X-Name":"internal"`},
   178  			{Path: "/test/wrong", Code: 500},
   179  		}...)
   180  	})
   181  
   182  	t.Run("VirtualEndpoint or plugins", func(t *testing.T) {
   183  		testPrepareVirtualEndpoint(`
   184              function testVirtData(request, session, config) {
   185                  var loopLocation = "/default"
   186  
   187                  if (request.Body.match("post_action")) {
   188                      loopLocation = "tyk://self/post_action"
   189                  } else if (request.Body.match("get_action")) {
   190                      loopLocation = "tyk://self/get_action?method=GET"
   191                  }
   192  
   193                  var resp = {
   194                      Headers: {
   195                          "Location": loopLocation,
   196                      },
   197                      Code: 302
   198                  }
   199                  return TykJsResponse(resp, session.meta_data)
   200              }
   201          `, "POST", "/virt", true)
   202  
   203  		ts.Run(t, []test.TestCase{
   204  			{Method: "POST", Path: "/virt", Data: postAction, BodyMatch: `"Url":"/post_action`},
   205  
   206  			// Should retain original query params
   207  			{Method: "POST", Path: "/virt?a=b", Data: getAction, BodyMatch: `"Url":"/get_action`},
   208  
   209  			// Should rewrite http method, if loop rewrite param passed
   210  			{Method: "POST", Path: "/virt", Data: getAction, BodyMatch: `"Method":"GET"`},
   211  		}...)
   212  	})
   213  
   214  	t.Run("Loop limit", func(t *testing.T) {
   215  		BuildAndLoadAPI(func(spec *APISpec) {
   216  			version := spec.VersionData.Versions["v1"]
   217  			json.Unmarshal([]byte(`{
   218                  "use_extended_paths": true,
   219                  "extended_paths": {
   220                      "url_rewrites": [{
   221                          "path": "/recursion",
   222                          "match_pattern": "/recursion(.*)",
   223                          "method": "GET",
   224                          "rewrite_to": "tyk://self/recursion?loop_limit=2"
   225                      }]
   226                  }
   227              }`), &version)
   228  
   229  			spec.VersionData.Versions["v1"] = version
   230  			spec.Proxy.ListenPath = "/"
   231  		})
   232  
   233  		ts.Run(t, []test.TestCase{
   234  			{Method: "GET", Path: "/recursion", Code: 500, BodyMatch: "Loop level too deep. Found more than 2 loops in single request"},
   235  		}...)
   236  	})
   237  
   238  	t.Run("Quota and rate limit calculation", func(t *testing.T) {
   239  		BuildAndLoadAPI(func(spec *APISpec) {
   240  			version := spec.VersionData.Versions["v1"]
   241  			json.Unmarshal([]byte(`{
   242                  "use_extended_paths": true,
   243                  "extended_paths": {
   244                      "url_rewrites": [{
   245                          "path": "/recursion",
   246                          "match_pattern": "/recursion(.*)",
   247                          "method": "GET",
   248                          "rewrite_to": "tyk://self/recursion?loop_limit=2"
   249                      }]
   250                  }
   251              }`), &version)
   252  
   253  			spec.VersionData.Versions["v1"] = version
   254  			spec.Proxy.ListenPath = "/"
   255  			spec.UseKeylessAccess = false
   256  		})
   257  
   258  		keyID := CreateSession(func(s *user.SessionState) {
   259  			s.QuotaMax = 2
   260  		})
   261  
   262  		authHeaders := map[string]string{"authorization": keyID}
   263  
   264  		ts.Run(t, []test.TestCase{
   265  			{Method: "GET", Path: "/recursion", Headers: authHeaders, BodyNotMatch: "Quota exceeded"},
   266  		}...)
   267  	})
   268  }
   269  
   270  func TestConcurrencyReloads(t *testing.T) {
   271  	var wg sync.WaitGroup
   272  
   273  	ts := StartTest()
   274  	defer ts.Close()
   275  
   276  	BuildAndLoadAPI()
   277  
   278  	for i := 0; i < 10; i++ {
   279  		wg.Add(1)
   280  		go func() {
   281  			ts.Run(t, test.TestCase{Path: "/sample", Code: 200})
   282  			wg.Done()
   283  		}()
   284  	}
   285  
   286  	for j := 0; j < 5; j++ {
   287  		BuildAndLoadAPI()
   288  	}
   289  
   290  	wg.Wait()
   291  }