1package chttp 2 3import ( 4 "io/ioutil" 5 "net/http" 6 "strings" 7 "testing" 8 9 "github.com/flimzy/diff" 10 11 "github.com/go-kivik/kivik" 12) 13 14func TestResponseError(t *testing.T) { 15 tests := []struct { 16 name string 17 resp *http.Response 18 expected interface{} 19 }{ 20 { 21 name: "non error", 22 resp: &http.Response{StatusCode: 200}, 23 expected: nil, 24 }, 25 { 26 name: "HEAD error", 27 resp: &http.Response{ 28 StatusCode: 404, 29 Request: &http.Request{Method: "HEAD"}, 30 Body: Body(""), 31 }, 32 expected: &HTTPError{Code: 404}, 33 }, 34 { 35 name: "2.0.0 error", 36 resp: &http.Response{ 37 StatusCode: 400, 38 Header: http.Header{ 39 "Cache-Control": {"must-revalidate"}, 40 "Content-Length": {"194"}, 41 "Content-Type": {"application/json"}, 42 "Date": {"Fri, 27 Oct 2017 15:34:07 GMT"}, 43 "Server": {"CouchDB/2.0.0 (Erlang OTP/17)"}, 44 "X-Couch-Request-ID": {"92d05bd015"}, 45 "X-CouchDB-Body-Time": {"0"}, 46 }, 47 ContentLength: 194, 48 Body: Body(`{"error":"illegal_database_name","reason":"Name: '_foo'. Only lowercase characters (a-z), digits (0-9), and any of the characters _, $, (, ), +, -, and / are allowed. Must begin with a letter."}`), 49 Request: &http.Request{Method: "PUT"}, 50 }, 51 expected: &HTTPError{ 52 Code: 400, 53 Reason: "Name: '_foo'. Only lowercase characters (a-z), digits (0-9), and any of the characters _, $, (, ), +, -, and / are allowed. Must begin with a letter.", 54 }, 55 }, 56 { 57 name: "invalid json error", 58 resp: &http.Response{ 59 StatusCode: 400, 60 Header: http.Header{ 61 "Server": {"CouchDB/1.6.1 (Erlang OTP/17)"}, 62 "Date": {"Fri, 27 Oct 2017 15:42:34 GMT"}, 63 "Content-Type": {"application/json"}, 64 "Content-Length": {"194"}, 65 "Cache-Control": {"must-revalidate"}, 66 }, 67 ContentLength: 194, 68 Body: Body("invalid json"), 69 Request: &http.Request{Method: "PUT"}, 70 }, 71 expected: &HTTPError{Code: 400}, 72 }, 73 } 74 for _, test := range tests { 75 t.Run(test.name, func(t *testing.T) { 76 err := ResponseError(test.resp) 77 if d := diff.Interface(test.expected, err); d != nil { 78 t.Error(d) 79 } 80 }) 81 } 82} 83 84func xTestErrors(t *testing.T) { 85 type errTest struct { 86 Name string 87 Func func() error 88 ExpectedStatus int 89 ExpectedMsg string 90 } 91 tests := []errTest{ 92 { 93 Name: "200Response", 94 Func: func() error { return ResponseError(&http.Response{StatusCode: 200}) }, 95 }, 96 { 97 Name: "HEADError", 98 Func: func() error { 99 return ResponseError(&http.Response{ 100 StatusCode: 400, 101 Request: &http.Request{ 102 Method: "HEAD", 103 }, 104 Body: ioutil.NopCloser(strings.NewReader("")), 105 }) 106 }, 107 ExpectedStatus: 400, 108 ExpectedMsg: "Bad Request", 109 }, 110 { 111 Name: "WithReason", 112 Func: func() error { 113 return ResponseError(&http.Response{ 114 StatusCode: 404, 115 Request: &http.Request{ 116 Method: "GET", 117 }, 118 Header: map[string][]string{"Content-Type": {"application/json"}}, 119 ContentLength: 1, // Just non-zero for this test 120 Body: ioutil.NopCloser(strings.NewReader(`{"code":404,"reason":"db_not_found"}`)), 121 }) 122 }, 123 ExpectedStatus: 404, 124 ExpectedMsg: "Not Found: db_not_found", 125 }, 126 { 127 Name: "WithoutReason", 128 Func: func() error { 129 return ResponseError(&http.Response{ 130 StatusCode: 404, 131 Request: &http.Request{ 132 Method: "GET", 133 }, 134 Header: map[string][]string{"Content-Type": {"application/json"}}, 135 ContentLength: 1, // Just non-zero for this test 136 Body: ioutil.NopCloser(strings.NewReader(`{"code":404}`)), 137 }) 138 }, 139 ExpectedStatus: 404, 140 ExpectedMsg: "Not Found", 141 }, 142 { 143 Name: "BadJSON", 144 Func: func() error { 145 return ResponseError(&http.Response{ 146 StatusCode: 404, 147 Request: &http.Request{ 148 Method: "GET", 149 }, 150 Header: map[string][]string{"Content-Type": {"application/json"}}, 151 ContentLength: 1, // Just non-zero for this test 152 Body: ioutil.NopCloser(strings.NewReader(`asdf`)), 153 }) 154 }, 155 ExpectedStatus: 404, 156 ExpectedMsg: "Not Found: unknown (failed to decode error response: invalid character 'a' looking for beginning of value)", 157 }, 158 } 159 for _, test := range tests { 160 func(test errTest) { 161 t.Run(test.Name, func(t *testing.T) { 162 err := test.Func() 163 if err == nil { 164 if test.ExpectedStatus == 0 { 165 return 166 } 167 t.Errorf("Got an error when none expected: %s", err) 168 } 169 if status := kivik.StatusCode(err); status != test.ExpectedStatus { 170 t.Errorf("Status. Expected %d, Actual %d", test.ExpectedStatus, status) 171 } 172 if msg := err.Error(); msg != test.ExpectedMsg { 173 t.Errorf("Error. Expected '%s', Actual '%s'", test.ExpectedMsg, msg) 174 } 175 }) 176 }(test) 177 } 178} 179