github.com/anuvu/tyk@v2.9.0-beta9-dl-apic+incompatible/gateway/mw_transform_test.go (about) 1 package gateway 2 3 import ( 4 "encoding/base64" 5 "io/ioutil" 6 "strings" 7 "testing" 8 "text/template" 9 10 "github.com/TykTechnologies/tyk/test" 11 12 "github.com/TykTechnologies/tyk/apidef" 13 ) 14 15 func testPrepareTransformNonAscii() (*TransformSpec, string) { 16 in := `<?xml version="1.0" encoding="utf-8"?> 17 <names> 18 <name>Jyväskylä</name> 19 <name>Hyvinkää</name> 20 </names>` 21 tmpl := `[{{range $x, $s := .names.name}}"{{$s}}"{{if not $x}}, {{end}}{{end}}]` 22 tmeta := &TransformSpec{} 23 tmeta.TemplateData.Input = apidef.RequestXML 24 tmeta.Template = template.Must(template.New("blob").Parse(tmpl)) 25 return tmeta, in 26 } 27 28 func TestTransformNonAscii(t *testing.T) { 29 tmeta, in := testPrepareTransformNonAscii() 30 want := `["Jyväskylä", "Hyvinkää"]` 31 32 r := TestReq(t, "GET", "/", in) 33 if err := transformBody(r, tmeta, false); err != nil { 34 t.Fatalf("wanted nil error, got %v", err) 35 } 36 gotBs, err := ioutil.ReadAll(r.Body) 37 if err != nil { 38 t.Fatal(err) 39 } 40 if got := string(gotBs); got != want { 41 t.Fatalf("wanted body %q, got %q", want, got) 42 } 43 } 44 45 func BenchmarkTransformNonAscii(b *testing.B) { 46 b.ReportAllocs() 47 48 tmeta, in := testPrepareTransformNonAscii() 49 for i := 0; i < b.N; i++ { 50 r := TestReq(b, "GET", "/", in) 51 if err := transformBody(r, tmeta, false); err != nil { 52 b.Fatalf("wanted nil error, got %v", err) 53 } 54 } 55 } 56 57 func TestTransformXMLCrash(t *testing.T) { 58 // mxj.NewMapXmlReader used to take forever and crash the 59 // process by eating up all the memory. 60 in := strings.NewReader("not xml") 61 r := TestReq(t, "GET", "/", in) 62 tmeta := &TransformSpec{} 63 tmeta.TemplateData.Input = apidef.RequestXML 64 tmeta.Template = template.Must(apidef.Template.New("").Parse("")) 65 if err := transformBody(r, tmeta, false); err == nil { 66 t.Fatalf("wanted error, got nil") 67 } 68 } 69 70 func testPrepareTransformJSONMarshal(inputType string) (tmeta *TransformSpec, in string) { 71 tmeta = &TransformSpec{} 72 tmpl := `[{{range $x, $s := .names.name}}{{$s | jsonMarshal}}{{if not $x}}, {{end}}{{end}}]` 73 tmeta.TemplateData.Input = apidef.RequestXML 74 tmeta.Template = template.Must(apidef.Template.New("").Parse(tmpl)) 75 76 switch inputType { 77 case "json": 78 tmeta.TemplateData.Input = apidef.RequestJSON 79 in = `{"names": { "name": ["Foo\"oo", "Bàr"] }}` 80 case "xml": 81 tmeta.TemplateData.Input = apidef.RequestXML 82 in = `<names> 83 <name>Foo"oo</name> 84 <name>Bàr</name> 85 </names>` 86 } 87 88 return tmeta, in 89 } 90 91 func testPrepareTransformXMLMarshal(tmpl string, inputType apidef.RequestInputType) (tmeta *TransformSpec) { 92 tmeta = &TransformSpec{} 93 tmeta.Template = template.Must(apidef.Template.New("").Parse(tmpl)) 94 95 switch inputType { 96 case apidef.RequestJSON: 97 tmeta.TemplateData.Input = apidef.RequestJSON 98 case apidef.RequestXML: 99 tmeta.TemplateData.Input = apidef.RequestXML 100 } 101 102 return tmeta 103 } 104 105 func TestTransformJSONMarshalXMLInput(t *testing.T) { 106 tmeta, in := testPrepareTransformJSONMarshal("xml") 107 108 want := `["Foo\"oo", "Bàr"]` 109 r := TestReq(t, "GET", "/", in) 110 if err := transformBody(r, tmeta, false); err != nil { 111 t.Fatalf("wanted nil error, got %v", err) 112 } 113 gotBs, err := ioutil.ReadAll(r.Body) 114 if err != nil { 115 t.Fatal(err) 116 } 117 if got := string(gotBs); got != want { 118 t.Fatalf("wanted body %q, got %q", want, got) 119 } 120 } 121 122 func TestTransformJSONMarshalJSONInput(t *testing.T) { 123 tmeta, in := testPrepareTransformJSONMarshal("json") 124 125 want := `["Foo\"oo", "Bàr"]` 126 r := TestReq(t, "GET", "/", in) 127 if err := transformBody(r, tmeta, false); err != nil { 128 t.Fatalf("wanted nil error, got %v", err) 129 } 130 gotBs, err := ioutil.ReadAll(r.Body) 131 if err != nil { 132 t.Fatal(err) 133 } 134 if got := string(gotBs); got != want { 135 t.Fatalf("wanted body %q, got %q", want, got) 136 } 137 } 138 139 func testPrepareTransformJSONMarshalArray(tb testing.TB) (tmeta *TransformSpec, in string) { 140 tmeta = &TransformSpec{} 141 tmpl := `[{{ range $key, $value := .array }}{{ if $key }},{{ end }}{{ .abc }}{{ end }}]` 142 tmeta.TemplateData.Input = apidef.RequestXML 143 tmeta.Template = template.Must(apidef.Template.New("").Parse(tmpl)) 144 145 tmeta.TemplateData.Input = apidef.RequestJSON 146 in = `[{"abc": 123}, {"abc": 456}]` 147 148 return tmeta, in 149 } 150 151 func TestTransformJSONMarshalJSONArrayInput(t *testing.T) { 152 tmeta, in := testPrepareTransformJSONMarshalArray(t) 153 154 want := `[123,456]` 155 r := TestReq(t, "GET", "/", in) 156 if err := transformBody(r, tmeta, false); err != nil { 157 t.Fatalf("wanted nil error, got %v", err) 158 } 159 gotBs, err := ioutil.ReadAll(r.Body) 160 if err != nil { 161 t.Fatal(err) 162 } 163 if got := string(gotBs); got != want { 164 t.Fatalf("wanted body %q, got %q", want, got) 165 } 166 } 167 168 func BenchmarkTransformJSONMarshal(b *testing.B) { 169 b.ReportAllocs() 170 171 tmeta, in := testPrepareTransformJSONMarshal("xml") 172 173 for i := 0; i < b.N; i++ { 174 r := TestReq(b, "GET", "/", in) 175 if err := transformBody(r, tmeta, false); err != nil { 176 b.Fatalf("wanted nil error, got %v", err) 177 } 178 } 179 } 180 181 func TestTransformXMLMarshal(t *testing.T) { 182 assert := func(t *testing.T, input string, tmpl string, output string, inputType apidef.RequestInputType) { 183 tmeta := testPrepareTransformXMLMarshal(tmpl, inputType) 184 r := TestReq(t, "GET", "/", input) 185 if err := transformBody(r, tmeta, false); err != nil { 186 t.Fatalf("wanted nil error, got %v", err) 187 } 188 gotBs, err := ioutil.ReadAll(r.Body) 189 if err != nil { 190 t.Fatal(err) 191 } 192 if got := string(gotBs); got != output { 193 t.Fatalf("wanted body %q, got %q", output, got) 194 } 195 } 196 197 tmpl := `{{. | xmlMarshal}}` 198 output := `<brothers><name>Furkan</name><name>Ahmet</name><name>Mohammad Ali</name></brothers>` 199 t.Run("XMLInput", func(t *testing.T) { 200 input := `<brothers><name>Furkan</name><name>Ahmet</name><name>Mohammad Ali</name></brothers>` 201 assert(t, input, tmpl, output, apidef.RequestXML) 202 }) 203 204 t.Run("JSONInput", func(t *testing.T) { 205 input := `{"brothers": { "name": ["Furkan", "Ahmet", "Mohammad Ali"] }}` 206 assert(t, input, tmpl, output, apidef.RequestJSON) 207 }) 208 209 t.Run("JSONInput with escaped char", func(t *testing.T) { 210 input := `{"test":"<"}` 211 output = `<test><</test>` 212 assert(t, input, tmpl, output, apidef.RequestJSON) 213 }) 214 215 t.Run("JSONInput with escaped char, template applied to a single value", func(t *testing.T) { 216 input := `{"test":"<"}` 217 tmpl = `{{ index . "test" | xmlMarshal }}` 218 output = `<string><</string>` 219 assert(t, input, tmpl, output, apidef.RequestJSON) 220 }) 221 } 222 223 func TestBodyTransformCaseSensitivity(t *testing.T) { 224 ts := StartTest() 225 defer ts.Close() 226 227 assert := func(relativePath string, requestedPath string, bodyMatch string) { 228 transformResponseConf := apidef.TemplateMeta{ 229 Path: relativePath, 230 Method: "GET", 231 TemplateData: apidef.TemplateData{ 232 Mode: "blob", 233 TemplateSource: base64.StdEncoding.EncodeToString([]byte(`{"http_method":"{{.Method}}"}`)), 234 }, 235 } 236 237 responseProcessorConf := []apidef.ResponseProcessor{{Name: "response_body_transform"}} 238 239 BuildAndLoadAPI(func(spec *APISpec) { 240 spec.Proxy.ListenPath = "/" 241 spec.ResponseProcessors = responseProcessorConf 242 UpdateAPIVersion(spec, "v1", func(v *apidef.VersionInfo) { 243 v.ExtendedPaths.TransformResponse = []apidef.TemplateMeta{transformResponseConf} 244 }) 245 }) 246 247 ts.Run(t, test.TestCase{ 248 Path: requestedPath, Code: 200, BodyMatch: bodyMatch, 249 }) 250 } 251 252 // Matches and transforms 253 t.Run("Relative path lower, requested path lower", func(t *testing.T) { 254 assert("/get", "/get", `{"http_method":"GET"}`) 255 }) 256 257 // Doesn't match and doesn't transform 258 t.Run("Relative path lower, requested path upper", func(t *testing.T) { 259 assert("/get", "/Get", `"Method":"GET"`) 260 }) 261 262 // Doesn't match and doesn't transform 263 t.Run("Relative path upper, requested path lower", func(t *testing.T) { 264 assert("/Get", "/get", `"Method":"GET"`) 265 }) 266 267 // Matches and transforms 268 t.Run("Relative path upper, requested path upper", func(t *testing.T) { 269 assert("/Get", "/Get", `{"http_method":"GET"}`) 270 }) 271 }