googleapi_test.go 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. // Copyright 2011 Google Inc. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package googleapi
  5. import (
  6. "bytes"
  7. "encoding/json"
  8. "fmt"
  9. "io/ioutil"
  10. "net/http"
  11. "net/url"
  12. "reflect"
  13. "strings"
  14. "testing"
  15. )
  16. type SetOpaqueTest struct {
  17. in *url.URL
  18. wantRequestURI string
  19. }
  20. var setOpaqueTests = []SetOpaqueTest{
  21. // no path
  22. {
  23. &url.URL{
  24. Scheme: "http",
  25. Host: "www.golang.org",
  26. },
  27. "http://www.golang.org",
  28. },
  29. // path
  30. {
  31. &url.URL{
  32. Scheme: "http",
  33. Host: "www.golang.org",
  34. Path: "/",
  35. },
  36. "http://www.golang.org/",
  37. },
  38. // file with hex escaping
  39. {
  40. &url.URL{
  41. Scheme: "https",
  42. Host: "www.golang.org",
  43. Path: "/file%20one&two",
  44. },
  45. "https://www.golang.org/file%20one&two",
  46. },
  47. // query
  48. {
  49. &url.URL{
  50. Scheme: "http",
  51. Host: "www.golang.org",
  52. Path: "/",
  53. RawQuery: "q=go+language",
  54. },
  55. "http://www.golang.org/?q=go+language",
  56. },
  57. // file with hex escaping in path plus query
  58. {
  59. &url.URL{
  60. Scheme: "https",
  61. Host: "www.golang.org",
  62. Path: "/file%20one&two",
  63. RawQuery: "q=go+language",
  64. },
  65. "https://www.golang.org/file%20one&two?q=go+language",
  66. },
  67. // query with hex escaping
  68. {
  69. &url.URL{
  70. Scheme: "http",
  71. Host: "www.golang.org",
  72. Path: "/",
  73. RawQuery: "q=go%20language",
  74. },
  75. "http://www.golang.org/?q=go%20language",
  76. },
  77. }
  78. // prefixTmpl is a template for the expected prefix of the output of writing
  79. // an HTTP request.
  80. const prefixTmpl = "GET %v HTTP/1.1\r\nHost: %v\r\n"
  81. func TestSetOpaque(t *testing.T) {
  82. for _, test := range setOpaqueTests {
  83. u := *test.in
  84. SetOpaque(&u)
  85. w := &bytes.Buffer{}
  86. r := &http.Request{URL: &u}
  87. if err := r.Write(w); err != nil {
  88. t.Errorf("write request: %v", err)
  89. continue
  90. }
  91. prefix := fmt.Sprintf(prefixTmpl, test.wantRequestURI, test.in.Host)
  92. if got := string(w.Bytes()); !strings.HasPrefix(got, prefix) {
  93. t.Errorf("got %q expected prefix %q", got, prefix)
  94. }
  95. }
  96. }
  97. type ExpandTest struct {
  98. in string
  99. expansions map[string]string
  100. want string
  101. }
  102. var expandTests = []ExpandTest{
  103. // no expansions
  104. {
  105. "http://www.golang.org/",
  106. map[string]string{},
  107. "http://www.golang.org/",
  108. },
  109. // one expansion, no escaping
  110. {
  111. "http://www.golang.org/{bucket}/delete",
  112. map[string]string{
  113. "bucket": "red",
  114. },
  115. "http://www.golang.org/red/delete",
  116. },
  117. // one expansion, with hex escapes
  118. {
  119. "http://www.golang.org/{bucket}/delete",
  120. map[string]string{
  121. "bucket": "red/blue",
  122. },
  123. "http://www.golang.org/red%2Fblue/delete",
  124. },
  125. // one expansion, with space
  126. {
  127. "http://www.golang.org/{bucket}/delete",
  128. map[string]string{
  129. "bucket": "red or blue",
  130. },
  131. "http://www.golang.org/red%20or%20blue/delete",
  132. },
  133. // expansion not found
  134. {
  135. "http://www.golang.org/{object}/delete",
  136. map[string]string{
  137. "bucket": "red or blue",
  138. },
  139. "http://www.golang.org//delete",
  140. },
  141. // multiple expansions
  142. {
  143. "http://www.golang.org/{one}/{two}/{three}/get",
  144. map[string]string{
  145. "one": "ONE",
  146. "two": "TWO",
  147. "three": "THREE",
  148. },
  149. "http://www.golang.org/ONE/TWO/THREE/get",
  150. },
  151. // utf-8 characters
  152. {
  153. "http://www.golang.org/{bucket}/get",
  154. map[string]string{
  155. "bucket": "£100",
  156. },
  157. "http://www.golang.org/%C2%A3100/get",
  158. },
  159. // punctuations
  160. {
  161. "http://www.golang.org/{bucket}/get",
  162. map[string]string{
  163. "bucket": `/\@:,.`,
  164. },
  165. "http://www.golang.org/%2F%5C%40%3A%2C./get",
  166. },
  167. // mis-matched brackets
  168. {
  169. "http://www.golang.org/{bucket/get",
  170. map[string]string{
  171. "bucket": "red",
  172. },
  173. "http://www.golang.org/{bucket/get",
  174. },
  175. // "+" prefix for suppressing escape
  176. // See also: http://tools.ietf.org/html/rfc6570#section-3.2.3
  177. {
  178. "http://www.golang.org/{+topic}",
  179. map[string]string{
  180. "topic": "/topics/myproject/mytopic",
  181. },
  182. // The double slashes here look weird, but it's intentional
  183. "http://www.golang.org//topics/myproject/mytopic",
  184. },
  185. }
  186. func TestExpand(t *testing.T) {
  187. for i, test := range expandTests {
  188. u := url.URL{
  189. Path: test.in,
  190. }
  191. Expand(&u, test.expansions)
  192. got := u.Path
  193. if got != test.want {
  194. t.Errorf("got %q expected %q in test %d", got, test.want, i+1)
  195. }
  196. }
  197. }
  198. type CheckResponseTest struct {
  199. in *http.Response
  200. bodyText string
  201. want error
  202. errText string
  203. }
  204. var checkResponseTests = []CheckResponseTest{
  205. {
  206. &http.Response{
  207. StatusCode: http.StatusOK,
  208. },
  209. "",
  210. nil,
  211. "",
  212. },
  213. {
  214. &http.Response{
  215. StatusCode: http.StatusInternalServerError,
  216. },
  217. `{"error":{}}`,
  218. &Error{
  219. Code: http.StatusInternalServerError,
  220. Body: `{"error":{}}`,
  221. },
  222. `googleapi: got HTTP response code 500 with body: {"error":{}}`,
  223. },
  224. {
  225. &http.Response{
  226. StatusCode: http.StatusNotFound,
  227. },
  228. `{"error":{"message":"Error message for StatusNotFound."}}`,
  229. &Error{
  230. Code: http.StatusNotFound,
  231. Message: "Error message for StatusNotFound.",
  232. Body: `{"error":{"message":"Error message for StatusNotFound."}}`,
  233. },
  234. "googleapi: Error 404: Error message for StatusNotFound.",
  235. },
  236. {
  237. &http.Response{
  238. StatusCode: http.StatusBadRequest,
  239. },
  240. `{"error":"invalid_token","error_description":"Invalid Value"}`,
  241. &Error{
  242. Code: http.StatusBadRequest,
  243. Body: `{"error":"invalid_token","error_description":"Invalid Value"}`,
  244. },
  245. `googleapi: got HTTP response code 400 with body: {"error":"invalid_token","error_description":"Invalid Value"}`,
  246. },
  247. {
  248. &http.Response{
  249. StatusCode: http.StatusBadRequest,
  250. },
  251. `{"error":{"errors":[{"domain":"usageLimits","reason":"keyInvalid","message":"Bad Request"}],"code":400,"message":"Bad Request"}}`,
  252. &Error{
  253. Code: http.StatusBadRequest,
  254. Errors: []ErrorItem{
  255. {
  256. Reason: "keyInvalid",
  257. Message: "Bad Request",
  258. },
  259. },
  260. Body: `{"error":{"errors":[{"domain":"usageLimits","reason":"keyInvalid","message":"Bad Request"}],"code":400,"message":"Bad Request"}}`,
  261. Message: "Bad Request",
  262. },
  263. "googleapi: Error 400: Bad Request, keyInvalid",
  264. },
  265. }
  266. func TestCheckResponse(t *testing.T) {
  267. for _, test := range checkResponseTests {
  268. res := test.in
  269. if test.bodyText != "" {
  270. res.Body = ioutil.NopCloser(strings.NewReader(test.bodyText))
  271. }
  272. g := CheckResponse(res)
  273. if !reflect.DeepEqual(g, test.want) {
  274. t.Errorf("CheckResponse: got %v, want %v", g, test.want)
  275. gotJson, err := json.Marshal(g)
  276. if err != nil {
  277. t.Error(err)
  278. }
  279. wantJson, err := json.Marshal(test.want)
  280. if err != nil {
  281. t.Error(err)
  282. }
  283. t.Errorf("json(got): %q\njson(want): %q", string(gotJson), string(wantJson))
  284. }
  285. if g != nil && g.Error() != test.errText {
  286. t.Errorf("CheckResponse: unexpected error message.\nGot: %q\nwant: %q", g, test.errText)
  287. }
  288. }
  289. }
  290. type VariantPoint struct {
  291. Type string
  292. Coordinates []float64
  293. }
  294. type VariantTest struct {
  295. in map[string]interface{}
  296. result bool
  297. want VariantPoint
  298. }
  299. var coords = []interface{}{1.0, 2.0}
  300. var variantTests = []VariantTest{
  301. {
  302. in: map[string]interface{}{
  303. "type": "Point",
  304. "coordinates": coords,
  305. },
  306. result: true,
  307. want: VariantPoint{
  308. Type: "Point",
  309. Coordinates: []float64{1.0, 2.0},
  310. },
  311. },
  312. {
  313. in: map[string]interface{}{
  314. "type": "Point",
  315. "bogus": coords,
  316. },
  317. result: true,
  318. want: VariantPoint{
  319. Type: "Point",
  320. },
  321. },
  322. }
  323. func TestVariantType(t *testing.T) {
  324. for _, test := range variantTests {
  325. if g := VariantType(test.in); g != test.want.Type {
  326. t.Errorf("VariantType(%v): got %v, want %v", test.in, g, test.want.Type)
  327. }
  328. }
  329. }
  330. func TestConvertVariant(t *testing.T) {
  331. for _, test := range variantTests {
  332. g := VariantPoint{}
  333. r := ConvertVariant(test.in, &g)
  334. if r != test.result {
  335. t.Errorf("ConvertVariant(%v): got %v, want %v", test.in, r, test.result)
  336. }
  337. if !reflect.DeepEqual(g, test.want) {
  338. t.Errorf("ConvertVariant(%v): got %v, want %v", test.in, g, test.want)
  339. }
  340. }
  341. }
  342. func TestRoundChunkSize(t *testing.T) {
  343. type testCase struct {
  344. in int
  345. want int
  346. }
  347. for _, tc := range []testCase{
  348. {0, 0},
  349. {256*1024 - 1, 256 * 1024},
  350. {256 * 1024, 256 * 1024},
  351. {256*1024 + 1, 2 * 256 * 1024},
  352. } {
  353. mo := &MediaOptions{}
  354. ChunkSize(tc.in).setOptions(mo)
  355. if got := mo.ChunkSize; got != tc.want {
  356. t.Errorf("rounding chunk size: got: %v; want %v", got, tc.want)
  357. }
  358. }
  359. }