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 }