Bump loofah from 2.2.3 to 2.3.1 in /apps/workbench
[arvados.git] / lib / controller / router / request_test.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 package router
6
7 import (
8         "bytes"
9         "encoding/json"
10         "io"
11         "net/http"
12         "net/http/httptest"
13         "net/url"
14
15         "git.curoverse.com/arvados.git/sdk/go/arvadostest"
16         check "gopkg.in/check.v1"
17 )
18
19 type testReq struct {
20         method   string
21         path     string
22         token    string // default is ActiveTokenV2; use noToken to omit
23         param    map[string]interface{}
24         attrs    map[string]interface{}
25         attrsKey string
26         header   http.Header
27
28         // variations on request formatting
29         json            bool
30         jsonAttrsTop    bool
31         jsonStringParam bool
32         tokenInBody     bool
33         tokenInQuery    bool
34         noContentType   bool
35
36         body *bytes.Buffer
37 }
38
39 const noToken = "(no token)"
40
41 func (tr *testReq) Request() *http.Request {
42         param := map[string]interface{}{}
43         for k, v := range tr.param {
44                 param[k] = v
45         }
46
47         if tr.body != nil {
48                 // caller provided a buffer
49         } else if tr.json {
50                 if tr.jsonAttrsTop {
51                         for k, v := range tr.attrs {
52                                 param[k] = v
53                         }
54                 } else if tr.attrs != nil {
55                         param[tr.attrsKey] = tr.attrs
56                 }
57                 tr.body = bytes.NewBuffer(nil)
58                 err := json.NewEncoder(tr.body).Encode(param)
59                 if err != nil {
60                         panic(err)
61                 }
62         } else {
63                 values := make(url.Values)
64                 for k, v := range param {
65                         if vs, ok := v.(string); ok && !tr.jsonStringParam {
66                                 values.Set(k, vs)
67                         } else {
68                                 jv, err := json.Marshal(v)
69                                 if err != nil {
70                                         panic(err)
71                                 }
72                                 values.Set(k, string(jv))
73                         }
74                 }
75                 if tr.attrs != nil {
76                         jattrs, err := json.Marshal(tr.attrs)
77                         if err != nil {
78                                 panic(err)
79                         }
80                         values.Set(tr.attrsKey, string(jattrs))
81                 }
82                 tr.body = bytes.NewBuffer(nil)
83                 io.WriteString(tr.body, values.Encode())
84         }
85         method := tr.method
86         if method == "" {
87                 method = "GET"
88         }
89         path := tr.path
90         if path == "" {
91                 path = "example/test/path"
92         }
93         req := httptest.NewRequest(method, "https://an.example/"+path, tr.body)
94         token := tr.token
95         if token == "" {
96                 token = arvadostest.ActiveTokenV2
97         }
98         if token != noToken {
99                 req.Header.Set("Authorization", "Bearer "+token)
100         }
101         if tr.json {
102                 req.Header.Set("Content-Type", "application/json")
103         } else {
104                 req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
105         }
106         for k, v := range tr.header {
107                 req.Header[k] = append([]string(nil), v...)
108         }
109         return req
110 }
111
112 func (tr *testReq) bodyContent() string {
113         return string(tr.body.Bytes())
114 }
115
116 func (s *RouterSuite) TestAttrsInBody(c *check.C) {
117         attrs := map[string]interface{}{"foo": "bar"}
118         for _, tr := range []testReq{
119                 {attrsKey: "model_name", json: true, attrs: attrs},
120                 {attrsKey: "model_name", json: true, attrs: attrs, jsonAttrsTop: true},
121         } {
122                 c.Logf("tr: %#v", tr)
123                 req := tr.Request()
124                 params, err := s.rtr.loadRequestParams(req, tr.attrsKey)
125                 c.Logf("params: %#v", params)
126                 c.Assert(err, check.IsNil)
127                 c.Check(params, check.NotNil)
128                 c.Assert(params["attrs"], check.FitsTypeOf, map[string]interface{}{})
129                 c.Check(params["attrs"].(map[string]interface{})["foo"], check.Equals, "bar")
130         }
131 }
132
133 func (s *RouterSuite) TestBoolParam(c *check.C) {
134         testKey := "ensure_unique_name"
135
136         for i, tr := range []testReq{
137                 {method: "POST", param: map[string]interface{}{testKey: false}, json: true},
138                 {method: "POST", param: map[string]interface{}{testKey: false}},
139                 {method: "POST", param: map[string]interface{}{testKey: "false"}},
140                 {method: "POST", param: map[string]interface{}{testKey: "0"}},
141                 {method: "POST", param: map[string]interface{}{testKey: ""}},
142         } {
143                 c.Logf("#%d, tr: %#v", i, tr)
144                 req := tr.Request()
145                 c.Logf("tr.body: %s", tr.bodyContent())
146                 params, err := s.rtr.loadRequestParams(req, tr.attrsKey)
147                 c.Logf("params: %#v", params)
148                 c.Assert(err, check.IsNil)
149                 c.Check(params, check.NotNil)
150                 c.Check(params[testKey], check.Equals, false)
151         }
152
153         for i, tr := range []testReq{
154                 {method: "POST", param: map[string]interface{}{testKey: true}, json: true},
155                 {method: "POST", param: map[string]interface{}{testKey: true}},
156                 {method: "POST", param: map[string]interface{}{testKey: "true"}},
157                 {method: "POST", param: map[string]interface{}{testKey: "1"}},
158         } {
159                 c.Logf("#%d, tr: %#v", i, tr)
160                 req := tr.Request()
161                 c.Logf("tr.body: %s", tr.bodyContent())
162                 params, err := s.rtr.loadRequestParams(req, tr.attrsKey)
163                 c.Logf("params: %#v", params)
164                 c.Assert(err, check.IsNil)
165                 c.Check(params, check.NotNil)
166                 c.Check(params[testKey], check.Equals, true)
167         }
168 }
169
170 func (s *RouterSuite) TestOrderParam(c *check.C) {
171         for i, tr := range []testReq{
172                 {method: "POST", param: map[string]interface{}{"order": ""}, json: true},
173                 {method: "POST", param: map[string]interface{}{"order": ""}, json: false},
174                 {method: "POST", param: map[string]interface{}{"order": []string{}}, json: true},
175                 {method: "POST", param: map[string]interface{}{"order": []string{}}, json: false},
176                 {method: "POST", param: map[string]interface{}{}, json: true},
177                 {method: "POST", param: map[string]interface{}{}, json: false},
178         } {
179                 c.Logf("#%d, tr: %#v", i, tr)
180                 req := tr.Request()
181                 params, err := s.rtr.loadRequestParams(req, tr.attrsKey)
182                 c.Assert(err, check.IsNil)
183                 c.Assert(params, check.NotNil)
184                 if order, ok := params["order"]; ok && order != nil {
185                         c.Check(order, check.DeepEquals, []interface{}{})
186                 }
187         }
188
189         for i, tr := range []testReq{
190                 {method: "POST", param: map[string]interface{}{"order": "foo,bar desc"}, json: true},
191                 {method: "POST", param: map[string]interface{}{"order": "foo,bar desc"}, json: false},
192                 {method: "POST", param: map[string]interface{}{"order": "[\"foo\", \"bar desc\"]"}, json: false},
193                 {method: "POST", param: map[string]interface{}{"order": []string{"foo", "bar desc"}}, json: true},
194                 {method: "POST", param: map[string]interface{}{"order": []string{"foo", "bar desc"}}, json: false},
195         } {
196                 c.Logf("#%d, tr: %#v", i, tr)
197                 req := tr.Request()
198                 params, err := s.rtr.loadRequestParams(req, tr.attrsKey)
199                 c.Assert(err, check.IsNil)
200                 if _, ok := params["order"].([]string); ok {
201                         c.Check(params["order"], check.DeepEquals, []string{"foo", "bar desc"})
202                 } else {
203                         c.Check(params["order"], check.DeepEquals, []interface{}{"foo", "bar desc"})
204                 }
205         }
206 }