github.com/dbernstein1/tyk@v2.9.0-beta9-dl-apic+incompatible/coprocess/python/coprocess_python_test.go (about)

     1  // +build coprocess
     2  // +build python
     3  
     4  package python
     5  
     6  import (
     7  	"bytes"
     8  	"mime/multipart"
     9  	"os"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/TykTechnologies/tyk/config"
    14  	"github.com/TykTechnologies/tyk/gateway"
    15  	"github.com/TykTechnologies/tyk/test"
    16  	"github.com/TykTechnologies/tyk/user"
    17  )
    18  
    19  var pythonBundleWithAuthCheck = map[string]string{
    20  	"manifest.json": `
    21  		{
    22  		    "file_list": [
    23  		        "middleware.py"
    24  		    ],
    25  		    "custom_middleware": {
    26  		        "driver": "python",
    27  		        "auth_check": {
    28  		            "name": "MyAuthHook"
    29  		        }
    30  		    }
    31  		}
    32  	`,
    33  	"middleware.py": `
    34  from tyk.decorators import *
    35  from gateway import TykGateway as tyk
    36  
    37  @Hook
    38  def MyAuthHook(request, session, metadata, spec):
    39      auth_header = request.get_header('Authorization')
    40      if auth_header == 'valid_token':
    41          session.rate = 1000.0
    42          session.per = 1.0
    43          metadata["token"] = "valid_token"
    44      return request, session, metadata
    45  
    46  	`,
    47  }
    48  
    49  var pythonBundleWithPostHook = map[string]string{
    50  	"manifest.json": `
    51  		{
    52  		    "file_list": [
    53  		        "middleware.py"
    54  		    ],
    55  		    "custom_middleware": {
    56  		        "driver": "python",
    57  		        "post": [{
    58  		            "name": "MyPostHook"
    59  		        }]
    60  		    }
    61  		}
    62  	`,
    63  	"middleware.py": `
    64  from tyk.decorators import *
    65  from gateway import TykGateway as tyk
    66  import json
    67  
    68  @Hook
    69  def MyPostHook(request, session, spec):
    70      if "testkey" not in session.metadata.keys():
    71          request.object.return_overrides.response_code = 400
    72          request.object.return_overrides.response_error = "'testkey' not found in metadata"
    73          return request, session
    74      nested_data = json.loads(session.metadata["testkey"])
    75      if "nestedkey" not in nested_data:
    76          request.object.return_overrides.response_code = 400
    77          request.object.return_overrides.response_error = "'nestedkey' not found in nested metadata"
    78          return request, session
    79      if "stringkey" not in session.metadata.keys():
    80          request.object.return_overrides.response_code = 400
    81          request.object.return_overrides.response_error = "'stringkey' not found in metadata"
    82          return request, session
    83      stringkey = session.metadata["stringkey"]
    84      if stringkey != "testvalue":
    85          request.object.return_overrides.response_code = 400
    86          request.object.return_overrides.response_error = "'stringkey' value doesn't match"
    87          return request, session	
    88      return request, session
    89  
    90  `,
    91  }
    92  
    93  var pythonBundleWithPreHook = map[string]string{
    94  	"manifest.json": `
    95  		{
    96  		    "file_list": [
    97  		        "middleware.py"
    98  		    ],
    99  		    "custom_middleware": {
   100  		        "driver": "python",
   101  		        "pre": [{
   102  		            "name": "MyPreHook"
   103  		        }]
   104  		    }
   105  		}
   106  	`,
   107  	"middleware.py": `
   108  from tyk.decorators import *
   109  from gateway import TykGateway as tyk
   110  
   111  @Hook
   112  def MyPreHook(request, session, metadata, spec):
   113      content_type = request.get_header("Content-Type")
   114      if "json" in content_type:
   115        if len(request.object.raw_body) <= 0:
   116          request.object.return_overrides.response_code = 400
   117          request.object.return_overrides.response_error = "Raw body field is empty"
   118          return request, session, metadata
   119        if "{}" not in request.object.body:
   120          request.object.return_overrides.response_code = 400
   121          request.object.return_overrides.response_error = "Body field doesn't match"
   122          return request, session, metadata
   123      if "multipart" in content_type:
   124        if len(request.object.body) != 0:
   125          request.object.return_overrides.response_code = 400
   126          request.object.return_overrides.response_error = "Body field isn't empty"
   127        if len(request.object.raw_body) <= 0:
   128          request.object.return_overrides.response_code = 400
   129          request.object.return_overrides.response_error = "Raw body field is empty"
   130      return request, session, metadata
   131  
   132  `,
   133  }
   134  
   135  func TestMain(m *testing.M) {
   136  	os.Exit(gateway.InitTestMain(m))
   137  }
   138  
   139  func TestPythonBundles(t *testing.T) {
   140  	ts := gateway.StartTest(gateway.TestConfig{
   141  		CoprocessConfig: config.CoProcessConfig{
   142  			EnableCoProcess: true,
   143  		}})
   144  	defer ts.Close()
   145  
   146  	authCheckBundle := gateway.RegisterBundle("python_with_auth_check", pythonBundleWithAuthCheck)
   147  	postHookBundle := gateway.RegisterBundle("python_with_post_hook", pythonBundleWithPostHook)
   148  	preHookBundle := gateway.RegisterBundle("python_with_pre_hook", pythonBundleWithPreHook)
   149  
   150  	t.Run("Single-file bundle with authentication hook", func(t *testing.T) {
   151  		gateway.BuildAndLoadAPI(func(spec *gateway.APISpec) {
   152  			spec.Proxy.ListenPath = "/test-api/"
   153  			spec.UseKeylessAccess = false
   154  			spec.EnableCoProcessAuth = true
   155  			spec.CustomMiddlewareBundle = authCheckBundle
   156  			spec.VersionData.NotVersioned = true
   157  		})
   158  
   159  		time.Sleep(1 * time.Second)
   160  
   161  		validAuth := map[string]string{"Authorization": "valid_token"}
   162  		invalidAuth := map[string]string{"Authorization": "invalid_token"}
   163  
   164  		ts.Run(t, []test.TestCase{
   165  			{Path: "/test-api/", Code: 200, Headers: validAuth},
   166  			{Path: "/test-api/", Code: 403, Headers: invalidAuth},
   167  		}...)
   168  	})
   169  
   170  	t.Run("Single-file bundle with post hook", func(t *testing.T) {
   171  
   172  		keyID := gateway.CreateSession(func(s *user.SessionState) {
   173  			s.MetaData = map[string]interface{}{
   174  				"testkey":   map[string]interface{}{"nestedkey": "nestedvalue"},
   175  				"stringkey": "testvalue",
   176  			}
   177  		})
   178  
   179  		gateway.BuildAndLoadAPI(func(spec *gateway.APISpec) {
   180  			spec.Proxy.ListenPath = "/test-api-2/"
   181  			spec.UseKeylessAccess = false
   182  			spec.EnableCoProcessAuth = false
   183  			spec.CustomMiddlewareBundle = postHookBundle
   184  			spec.VersionData.NotVersioned = true
   185  		})
   186  
   187  		time.Sleep(1 * time.Second)
   188  
   189  		auth := map[string]string{"Authorization": keyID}
   190  
   191  		ts.Run(t, []test.TestCase{
   192  			{Path: "/test-api-2/", Code: 200, Headers: auth},
   193  		}...)
   194  	})
   195  
   196  	t.Run("Single-file bundle with pre hook and UTF-8/non-UTF-8 request data", func(t *testing.T) {
   197  		gateway.BuildAndLoadAPI(func(spec *gateway.APISpec) {
   198  			spec.Proxy.ListenPath = "/test-api-2/"
   199  			spec.UseKeylessAccess = true
   200  			spec.EnableCoProcessAuth = false
   201  			spec.CustomMiddlewareBundle = preHookBundle
   202  			spec.VersionData.NotVersioned = true
   203  		})
   204  
   205  		time.Sleep(1 * time.Second)
   206  
   207  		fileData := gateway.GenerateTestBinaryData()
   208  		var buf bytes.Buffer
   209  		multipartWriter := multipart.NewWriter(&buf)
   210  		file, err := multipartWriter.CreateFormFile("file", "test.bin")
   211  		if err != nil {
   212  			t.Fatalf("Couldn't use multipart writer: %s", err.Error())
   213  		}
   214  		_, err = fileData.WriteTo(file)
   215  		if err != nil {
   216  			t.Fatalf("Couldn't write to multipart file: %s", err.Error())
   217  		}
   218  		field, err := multipartWriter.CreateFormField("testfield")
   219  		if err != nil {
   220  			t.Fatalf("Couldn't use multipart writer: %s", err.Error())
   221  		}
   222  		_, err = field.Write([]byte("testvalue"))
   223  		if err != nil {
   224  			t.Fatalf("Couldn't write to form field: %s", err.Error())
   225  		}
   226  		err = multipartWriter.Close()
   227  		if err != nil {
   228  			t.Fatalf("Couldn't close multipart writer: %s", err.Error())
   229  		}
   230  
   231  		ts.Run(t, []test.TestCase{
   232  			{Path: "/test-api-2/", Code: 200, Data: &buf, Headers: map[string]string{"Content-Type": multipartWriter.FormDataContentType()}},
   233  			{Path: "/test-api-2/", Code: 200, Data: "{}", Headers: map[string]string{"Content-Type": "application/json"}},
   234  		}...)
   235  	})
   236  }