18870: Improve logging of errors from login-sync
[arvados.git] / lib / controller / router / request_test.go
index cffdccc909d216bc0b8db570f65dec5a6576aaf4..4544a6bb65f4692af7ffb15b190f6803c6f1bbc9 100644 (file)
@@ -6,24 +6,219 @@ package router
 
 import (
        "bytes"
+       "encoding/json"
+       "io"
+       "net/http"
        "net/http/httptest"
+       "net/url"
 
+       "git.arvados.org/arvados.git/sdk/go/arvadostest"
        check "gopkg.in/check.v1"
 )
 
+type testReq struct {
+       method   string
+       path     string
+       token    string // default is ActiveTokenV2; use noToken to omit
+       param    map[string]interface{}
+       attrs    map[string]interface{}
+       attrsKey string
+       header   http.Header
+
+       // variations on request formatting
+       json            bool
+       jsonAttrsTop    bool
+       jsonStringParam bool
+       tokenInBody     bool
+       tokenInQuery    bool
+       noContentType   bool
+
+       body *bytes.Buffer
+}
+
+const noToken = "(no token)"
+
+func (tr *testReq) Request() *http.Request {
+       param := map[string]interface{}{}
+       for k, v := range tr.param {
+               param[k] = v
+       }
+
+       if tr.body != nil {
+               // caller provided a buffer
+       } else if tr.json {
+               if tr.jsonAttrsTop {
+                       for k, v := range tr.attrs {
+                               if tr.jsonStringParam {
+                                       j, err := json.Marshal(v)
+                                       if err != nil {
+                                               panic(err)
+                                       }
+                                       param[k] = string(j)
+                               } else {
+                                       param[k] = v
+                               }
+                       }
+               } else if tr.attrs != nil {
+                       if tr.jsonStringParam {
+                               j, err := json.Marshal(tr.attrs)
+                               if err != nil {
+                                       panic(err)
+                               }
+                               param[tr.attrsKey] = string(j)
+                       } else {
+                               param[tr.attrsKey] = tr.attrs
+                       }
+               }
+               tr.body = bytes.NewBuffer(nil)
+               err := json.NewEncoder(tr.body).Encode(param)
+               if err != nil {
+                       panic(err)
+               }
+       } else {
+               values := make(url.Values)
+               for k, v := range param {
+                       if vs, ok := v.(string); ok && !tr.jsonStringParam {
+                               values.Set(k, vs)
+                       } else {
+                               jv, err := json.Marshal(v)
+                               if err != nil {
+                                       panic(err)
+                               }
+                               values.Set(k, string(jv))
+                       }
+               }
+               if tr.attrs != nil {
+                       jattrs, err := json.Marshal(tr.attrs)
+                       if err != nil {
+                               panic(err)
+                       }
+                       values.Set(tr.attrsKey, string(jattrs))
+               }
+               tr.body = bytes.NewBuffer(nil)
+               io.WriteString(tr.body, values.Encode())
+       }
+       method := tr.method
+       if method == "" {
+               method = "GET"
+       }
+       path := tr.path
+       if path == "" {
+               path = "example/test/path"
+       }
+       req := httptest.NewRequest(method, "https://an.example/"+path, tr.body)
+       token := tr.token
+       if token == "" {
+               token = arvadostest.ActiveTokenV2
+       }
+       if token != noToken {
+               req.Header.Set("Authorization", "Bearer "+token)
+       }
+       if tr.json {
+               req.Header.Set("Content-Type", "application/json")
+       } else {
+               req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
+       }
+       for k, v := range tr.header {
+               req.Header[k] = append([]string(nil), v...)
+       }
+       return req
+}
+
+func (tr *testReq) bodyContent() string {
+       return string(tr.body.Bytes())
+}
+
 func (s *RouterSuite) TestAttrsInBody(c *check.C) {
-       for _, body := range []string{
-               `{"foo":"bar"}`,
-               `{"model_name": {"foo":"bar"}}`,
+       attrs := map[string]interface{}{"foo": "bar"}
+       for _, tr := range []testReq{
+               {attrsKey: "model_name", json: true, attrs: attrs},
+               {attrsKey: "model_name", json: true, attrs: attrs, jsonAttrsTop: true},
+               {attrsKey: "model_name", json: true, attrs: attrs, jsonAttrsTop: true, jsonStringParam: true},
+               {attrsKey: "model_name", json: true, attrs: attrs, jsonAttrsTop: false, jsonStringParam: true},
        } {
-               c.Logf("body: %s", body)
-               req := httptest.NewRequest("POST", "https://an.example/ctrl", bytes.NewBufferString(body))
-               req.Header.Set("Content-Type", "application/json")
-               params, err := s.rtr.loadRequestParams(req, "model_name")
-               c.Assert(err, check.IsNil)
+               c.Logf("tr: %#v", tr)
+               req := tr.Request()
+               params, err := s.rtr.loadRequestParams(req, tr.attrsKey)
                c.Logf("params: %#v", params)
+               c.Assert(err, check.IsNil)
                c.Check(params, check.NotNil)
                c.Assert(params["attrs"], check.FitsTypeOf, map[string]interface{}{})
                c.Check(params["attrs"].(map[string]interface{})["foo"], check.Equals, "bar")
        }
 }
+
+func (s *RouterSuite) TestBoolParam(c *check.C) {
+       testKey := "ensure_unique_name"
+
+       for i, tr := range []testReq{
+               {method: "POST", param: map[string]interface{}{testKey: false}, json: true},
+               {method: "POST", param: map[string]interface{}{testKey: false}},
+               {method: "POST", param: map[string]interface{}{testKey: "false"}},
+               {method: "POST", param: map[string]interface{}{testKey: "0"}},
+               {method: "POST", param: map[string]interface{}{testKey: ""}},
+       } {
+               c.Logf("#%d, tr: %#v", i, tr)
+               req := tr.Request()
+               c.Logf("tr.body: %s", tr.bodyContent())
+               params, err := s.rtr.loadRequestParams(req, tr.attrsKey)
+               c.Logf("params: %#v", params)
+               c.Assert(err, check.IsNil)
+               c.Check(params, check.NotNil)
+               c.Check(params[testKey], check.Equals, false)
+       }
+
+       for i, tr := range []testReq{
+               {method: "POST", param: map[string]interface{}{testKey: true}, json: true},
+               {method: "POST", param: map[string]interface{}{testKey: true}},
+               {method: "POST", param: map[string]interface{}{testKey: "true"}},
+               {method: "POST", param: map[string]interface{}{testKey: "1"}},
+       } {
+               c.Logf("#%d, tr: %#v", i, tr)
+               req := tr.Request()
+               c.Logf("tr.body: %s", tr.bodyContent())
+               params, err := s.rtr.loadRequestParams(req, tr.attrsKey)
+               c.Logf("params: %#v", params)
+               c.Assert(err, check.IsNil)
+               c.Check(params, check.NotNil)
+               c.Check(params[testKey], check.Equals, true)
+       }
+}
+
+func (s *RouterSuite) TestOrderParam(c *check.C) {
+       for i, tr := range []testReq{
+               {method: "POST", param: map[string]interface{}{"order": ""}, json: true},
+               {method: "POST", param: map[string]interface{}{"order": ""}, json: false},
+               {method: "POST", param: map[string]interface{}{"order": []string{}}, json: true},
+               {method: "POST", param: map[string]interface{}{"order": []string{}}, json: false},
+               {method: "POST", param: map[string]interface{}{}, json: true},
+               {method: "POST", param: map[string]interface{}{}, json: false},
+       } {
+               c.Logf("#%d, tr: %#v", i, tr)
+               req := tr.Request()
+               params, err := s.rtr.loadRequestParams(req, tr.attrsKey)
+               c.Assert(err, check.IsNil)
+               c.Assert(params, check.NotNil)
+               if order, ok := params["order"]; ok && order != nil {
+                       c.Check(order, check.DeepEquals, []interface{}{})
+               }
+       }
+
+       for i, tr := range []testReq{
+               {method: "POST", param: map[string]interface{}{"order": "foo,bar desc"}, json: true},
+               {method: "POST", param: map[string]interface{}{"order": "foo,bar desc"}, json: false},
+               {method: "POST", param: map[string]interface{}{"order": "[\"foo\", \"bar desc\"]"}, json: false},
+               {method: "POST", param: map[string]interface{}{"order": []string{"foo", "bar desc"}}, json: true},
+               {method: "POST", param: map[string]interface{}{"order": []string{"foo", "bar desc"}}, json: false},
+       } {
+               c.Logf("#%d, tr: %#v", i, tr)
+               req := tr.Request()
+               params, err := s.rtr.loadRequestParams(req, tr.attrsKey)
+               c.Assert(err, check.IsNil)
+               if _, ok := params["order"].([]string); ok {
+                       c.Check(params["order"], check.DeepEquals, []string{"foo", "bar desc"})
+               } else {
+                       c.Check(params["order"], check.DeepEquals, []interface{}{"foo", "bar desc"})
+               }
+       }
+}