github.com/dbernstein1/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>&lt;</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>&lt;</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  }