request_test.go 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package restclient
  14. import (
  15. "bytes"
  16. "errors"
  17. "fmt"
  18. "io"
  19. "io/ioutil"
  20. "net/http"
  21. "net/http/httptest"
  22. "net/url"
  23. "os"
  24. "reflect"
  25. "strings"
  26. "testing"
  27. "time"
  28. "k8s.io/kubernetes/pkg/api"
  29. apierrors "k8s.io/kubernetes/pkg/api/errors"
  30. "k8s.io/kubernetes/pkg/api/testapi"
  31. "k8s.io/kubernetes/pkg/api/unversioned"
  32. "k8s.io/kubernetes/pkg/api/v1"
  33. "k8s.io/kubernetes/pkg/labels"
  34. "k8s.io/kubernetes/pkg/runtime"
  35. "k8s.io/kubernetes/pkg/runtime/serializer/streaming"
  36. "k8s.io/kubernetes/pkg/util/clock"
  37. "k8s.io/kubernetes/pkg/util/flowcontrol"
  38. "k8s.io/kubernetes/pkg/util/httpstream"
  39. "k8s.io/kubernetes/pkg/util/intstr"
  40. utiltesting "k8s.io/kubernetes/pkg/util/testing"
  41. "k8s.io/kubernetes/pkg/watch"
  42. "k8s.io/kubernetes/pkg/watch/versioned"
  43. )
  44. func TestNewRequestSetsAccept(t *testing.T) {
  45. r := NewRequest(nil, "get", &url.URL{Path: "/path/"}, "", ContentConfig{}, Serializers{}, nil, nil)
  46. if r.headers.Get("Accept") != "" {
  47. t.Errorf("unexpected headers: %#v", r.headers)
  48. }
  49. r = NewRequest(nil, "get", &url.URL{Path: "/path/"}, "", ContentConfig{ContentType: "application/other"}, Serializers{}, nil, nil)
  50. if r.headers.Get("Accept") != "application/other, */*" {
  51. t.Errorf("unexpected headers: %#v", r.headers)
  52. }
  53. }
  54. type clientFunc func(req *http.Request) (*http.Response, error)
  55. func (f clientFunc) Do(req *http.Request) (*http.Response, error) {
  56. return f(req)
  57. }
  58. func TestRequestSetsHeaders(t *testing.T) {
  59. server := clientFunc(func(req *http.Request) (*http.Response, error) {
  60. if req.Header.Get("Accept") != "application/other, */*" {
  61. t.Errorf("unexpected headers: %#v", req.Header)
  62. }
  63. return &http.Response{
  64. StatusCode: http.StatusForbidden,
  65. Body: ioutil.NopCloser(bytes.NewReader([]byte{})),
  66. }, nil
  67. })
  68. config := defaultContentConfig()
  69. config.ContentType = "application/other"
  70. serializers := defaultSerializers()
  71. r := NewRequest(server, "get", &url.URL{Path: "/path"}, "", config, serializers, nil, nil)
  72. // Check if all "issue" methods are setting headers.
  73. _ = r.Do()
  74. _, _ = r.Watch()
  75. _, _ = r.Stream()
  76. }
  77. func TestRequestWithErrorWontChange(t *testing.T) {
  78. original := Request{
  79. err: errors.New("test"),
  80. content: ContentConfig{GroupVersion: testapi.Default.GroupVersion()},
  81. }
  82. r := original
  83. changed := r.Param("foo", "bar").
  84. LabelsSelectorParam(labels.Set{"a": "b"}.AsSelector()).
  85. UintParam("uint", 1).
  86. AbsPath("/abs").
  87. Prefix("test").
  88. Suffix("testing").
  89. Namespace("new").
  90. Resource("foos").
  91. Name("bars").
  92. Body("foo").
  93. Timeout(time.Millisecond)
  94. if changed != &r {
  95. t.Errorf("returned request should point to the same object")
  96. }
  97. if !reflect.DeepEqual(changed, &original) {
  98. t.Errorf("expected %#v, got %#v", &original, changed)
  99. }
  100. }
  101. func TestRequestPreservesBaseTrailingSlash(t *testing.T) {
  102. r := &Request{baseURL: &url.URL{}, pathPrefix: "/path/"}
  103. if s := r.URL().String(); s != "/path/" {
  104. t.Errorf("trailing slash should be preserved: %s", s)
  105. }
  106. }
  107. func TestRequestAbsPathPreservesTrailingSlash(t *testing.T) {
  108. r := (&Request{baseURL: &url.URL{}}).AbsPath("/foo/")
  109. if s := r.URL().String(); s != "/foo/" {
  110. t.Errorf("trailing slash should be preserved: %s", s)
  111. }
  112. r = (&Request{baseURL: &url.URL{}}).AbsPath("/foo/")
  113. if s := r.URL().String(); s != "/foo/" {
  114. t.Errorf("trailing slash should be preserved: %s", s)
  115. }
  116. }
  117. func TestRequestAbsPathJoins(t *testing.T) {
  118. r := (&Request{baseURL: &url.URL{}}).AbsPath("foo/bar", "baz")
  119. if s := r.URL().String(); s != "foo/bar/baz" {
  120. t.Errorf("trailing slash should be preserved: %s", s)
  121. }
  122. }
  123. func TestRequestSetsNamespace(t *testing.T) {
  124. r := (&Request{
  125. baseURL: &url.URL{
  126. Path: "/",
  127. },
  128. }).Namespace("foo")
  129. if r.namespace == "" {
  130. t.Errorf("namespace should be set: %#v", r)
  131. }
  132. if s := r.URL().String(); s != "namespaces/foo" {
  133. t.Errorf("namespace should be in path: %s", s)
  134. }
  135. }
  136. func TestRequestOrdersNamespaceInPath(t *testing.T) {
  137. r := (&Request{
  138. baseURL: &url.URL{},
  139. pathPrefix: "/test/",
  140. }).Name("bar").Resource("baz").Namespace("foo")
  141. if s := r.URL().String(); s != "/test/namespaces/foo/baz/bar" {
  142. t.Errorf("namespace should be in order in path: %s", s)
  143. }
  144. }
  145. func TestRequestOrdersSubResource(t *testing.T) {
  146. r := (&Request{
  147. baseURL: &url.URL{},
  148. pathPrefix: "/test/",
  149. }).Name("bar").Resource("baz").Namespace("foo").Suffix("test").SubResource("a", "b")
  150. if s := r.URL().String(); s != "/test/namespaces/foo/baz/bar/a/b/test" {
  151. t.Errorf("namespace should be in order in path: %s", s)
  152. }
  153. }
  154. func TestRequestSetTwiceError(t *testing.T) {
  155. if (&Request{}).Name("bar").Name("baz").err == nil {
  156. t.Errorf("setting name twice should result in error")
  157. }
  158. if (&Request{}).Namespace("bar").Namespace("baz").err == nil {
  159. t.Errorf("setting namespace twice should result in error")
  160. }
  161. if (&Request{}).Resource("bar").Resource("baz").err == nil {
  162. t.Errorf("setting resource twice should result in error")
  163. }
  164. if (&Request{}).SubResource("bar").SubResource("baz").err == nil {
  165. t.Errorf("setting subresource twice should result in error")
  166. }
  167. }
  168. func TestInvalidSegments(t *testing.T) {
  169. invalidSegments := []string{".", "..", "test/segment", "test%2bsegment"}
  170. setters := map[string]func(string, *Request){
  171. "namespace": func(s string, r *Request) { r.Namespace(s) },
  172. "resource": func(s string, r *Request) { r.Resource(s) },
  173. "name": func(s string, r *Request) { r.Name(s) },
  174. "subresource": func(s string, r *Request) { r.SubResource(s) },
  175. }
  176. for _, invalidSegment := range invalidSegments {
  177. for setterName, setter := range setters {
  178. r := &Request{}
  179. setter(invalidSegment, r)
  180. if r.err == nil {
  181. t.Errorf("%s: %s: expected error, got none", setterName, invalidSegment)
  182. }
  183. }
  184. }
  185. }
  186. func TestRequestParam(t *testing.T) {
  187. r := (&Request{}).Param("foo", "a")
  188. if !reflect.DeepEqual(r.params, url.Values{"foo": []string{"a"}}) {
  189. t.Errorf("should have set a param: %#v", r)
  190. }
  191. r.Param("bar", "1")
  192. r.Param("bar", "2")
  193. if !reflect.DeepEqual(r.params, url.Values{"foo": []string{"a"}, "bar": []string{"1", "2"}}) {
  194. t.Errorf("should have set a param: %#v", r)
  195. }
  196. }
  197. func TestRequestVersionedParams(t *testing.T) {
  198. r := (&Request{content: ContentConfig{GroupVersion: &v1.SchemeGroupVersion}}).Param("foo", "a")
  199. if !reflect.DeepEqual(r.params, url.Values{"foo": []string{"a"}}) {
  200. t.Errorf("should have set a param: %#v", r)
  201. }
  202. r.VersionedParams(&api.PodLogOptions{Follow: true, Container: "bar"}, api.ParameterCodec)
  203. if !reflect.DeepEqual(r.params, url.Values{
  204. "foo": []string{"a"},
  205. "container": []string{"bar"},
  206. "follow": []string{"true"},
  207. }) {
  208. t.Errorf("should have set a param: %#v", r)
  209. }
  210. }
  211. func TestRequestVersionedParamsFromListOptions(t *testing.T) {
  212. r := &Request{content: ContentConfig{GroupVersion: &v1.SchemeGroupVersion}}
  213. r.VersionedParams(&api.ListOptions{ResourceVersion: "1"}, api.ParameterCodec)
  214. if !reflect.DeepEqual(r.params, url.Values{
  215. "resourceVersion": []string{"1"},
  216. }) {
  217. t.Errorf("should have set a param: %#v", r)
  218. }
  219. var timeout int64 = 10
  220. r.VersionedParams(&api.ListOptions{ResourceVersion: "2", TimeoutSeconds: &timeout}, api.ParameterCodec)
  221. if !reflect.DeepEqual(r.params, url.Values{
  222. "resourceVersion": []string{"1", "2"},
  223. "timeoutSeconds": []string{"10"},
  224. }) {
  225. t.Errorf("should have set a param: %#v", r)
  226. }
  227. }
  228. func TestRequestURI(t *testing.T) {
  229. r := (&Request{}).Param("foo", "a")
  230. r.Prefix("other")
  231. r.RequestURI("/test?foo=b&a=b&c=1&c=2")
  232. if r.pathPrefix != "/test" {
  233. t.Errorf("path is wrong: %#v", r)
  234. }
  235. if !reflect.DeepEqual(r.params, url.Values{"a": []string{"b"}, "foo": []string{"b"}, "c": []string{"1", "2"}}) {
  236. t.Errorf("should have set a param: %#v", r)
  237. }
  238. }
  239. type NotAnAPIObject struct{}
  240. func (obj NotAnAPIObject) GroupVersionKind() *unversioned.GroupVersionKind { return nil }
  241. func (obj NotAnAPIObject) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) {}
  242. func defaultContentConfig() ContentConfig {
  243. return ContentConfig{
  244. GroupVersion: testapi.Default.GroupVersion(),
  245. NegotiatedSerializer: testapi.Default.NegotiatedSerializer(),
  246. }
  247. }
  248. func defaultSerializers() Serializers {
  249. return Serializers{
  250. Encoder: testapi.Default.Codec(),
  251. Decoder: testapi.Default.Codec(),
  252. StreamingSerializer: testapi.Default.Codec(),
  253. Framer: runtime.DefaultFramer,
  254. RenegotiatedDecoder: func(contentType string, params map[string]string) (runtime.Decoder, error) {
  255. return testapi.Default.Codec(), nil
  256. },
  257. }
  258. }
  259. func TestRequestBody(t *testing.T) {
  260. // test unknown type
  261. r := (&Request{}).Body([]string{"test"})
  262. if r.err == nil || r.body != nil {
  263. t.Errorf("should have set err and left body nil: %#v", r)
  264. }
  265. // test error set when failing to read file
  266. f, err := ioutil.TempFile("", "test")
  267. if err != nil {
  268. t.Fatalf("unable to create temp file")
  269. }
  270. defer f.Close()
  271. os.Remove(f.Name())
  272. r = (&Request{}).Body(f.Name())
  273. if r.err == nil || r.body != nil {
  274. t.Errorf("should have set err and left body nil: %#v", r)
  275. }
  276. // test unencodable api object
  277. r = (&Request{content: defaultContentConfig()}).Body(&NotAnAPIObject{})
  278. if r.err == nil || r.body != nil {
  279. t.Errorf("should have set err and left body nil: %#v", r)
  280. }
  281. }
  282. func TestResultIntoWithErrReturnsErr(t *testing.T) {
  283. res := Result{err: errors.New("test")}
  284. if err := res.Into(&api.Pod{}); err != res.err {
  285. t.Errorf("should have returned exact error from result")
  286. }
  287. }
  288. func TestURLTemplate(t *testing.T) {
  289. uri, _ := url.Parse("http://localhost")
  290. r := NewRequest(nil, "POST", uri, "", ContentConfig{GroupVersion: &unversioned.GroupVersion{Group: "test"}}, Serializers{}, nil, nil)
  291. r.Prefix("pre1").Resource("r1").Namespace("ns").Name("nm").Param("p0", "v0")
  292. full := r.URL()
  293. if full.String() != "http://localhost/pre1/namespaces/ns/r1/nm?p0=v0" {
  294. t.Errorf("unexpected initial URL: %s", full)
  295. }
  296. actualURL := r.finalURLTemplate()
  297. actual := actualURL.String()
  298. expected := "http://localhost/pre1/namespaces/%7Bnamespace%7D/r1/%7Bname%7D?p0=%7Bvalue%7D"
  299. if actual != expected {
  300. t.Errorf("unexpected URL template: %s %s", actual, expected)
  301. }
  302. if r.URL().String() != full.String() {
  303. t.Errorf("creating URL template changed request: %s -> %s", full.String(), r.URL().String())
  304. }
  305. }
  306. func TestTransformResponse(t *testing.T) {
  307. invalid := []byte("aaaaa")
  308. uri, _ := url.Parse("http://localhost")
  309. testCases := []struct {
  310. Response *http.Response
  311. Data []byte
  312. Created bool
  313. Error bool
  314. ErrFn func(err error) bool
  315. }{
  316. {Response: &http.Response{StatusCode: 200}, Data: []byte{}},
  317. {Response: &http.Response{StatusCode: 201}, Data: []byte{}, Created: true},
  318. {Response: &http.Response{StatusCode: 199}, Error: true},
  319. {Response: &http.Response{StatusCode: 500}, Error: true},
  320. {Response: &http.Response{StatusCode: 422}, Error: true},
  321. {Response: &http.Response{StatusCode: 409}, Error: true},
  322. {Response: &http.Response{StatusCode: 404}, Error: true},
  323. {Response: &http.Response{StatusCode: 401}, Error: true},
  324. {
  325. Response: &http.Response{
  326. StatusCode: 401,
  327. Header: http.Header{"Content-Type": []string{"application/json"}},
  328. Body: ioutil.NopCloser(bytes.NewReader(invalid)),
  329. },
  330. Error: true,
  331. ErrFn: func(err error) bool {
  332. return err.Error() != "aaaaa" && apierrors.IsUnauthorized(err)
  333. },
  334. },
  335. {
  336. Response: &http.Response{
  337. StatusCode: 401,
  338. Header: http.Header{"Content-Type": []string{"text/any"}},
  339. Body: ioutil.NopCloser(bytes.NewReader(invalid)),
  340. },
  341. Error: true,
  342. ErrFn: func(err error) bool {
  343. return strings.Contains(err.Error(), "server has asked for the client to provide") && apierrors.IsUnauthorized(err)
  344. },
  345. },
  346. {Response: &http.Response{StatusCode: 403}, Error: true},
  347. {Response: &http.Response{StatusCode: 200, Body: ioutil.NopCloser(bytes.NewReader(invalid))}, Data: invalid},
  348. {Response: &http.Response{StatusCode: 200, Body: ioutil.NopCloser(bytes.NewReader(invalid))}, Data: invalid},
  349. }
  350. for i, test := range testCases {
  351. r := NewRequest(nil, "", uri, "", defaultContentConfig(), defaultSerializers(), nil, nil)
  352. if test.Response.Body == nil {
  353. test.Response.Body = ioutil.NopCloser(bytes.NewReader([]byte{}))
  354. }
  355. result := r.transformResponse(test.Response, &http.Request{})
  356. response, created, err := result.body, result.statusCode == http.StatusCreated, result.err
  357. hasErr := err != nil
  358. if hasErr != test.Error {
  359. t.Errorf("%d: unexpected error: %t %v", i, test.Error, err)
  360. } else if hasErr && test.Response.StatusCode > 399 {
  361. status, ok := err.(apierrors.APIStatus)
  362. if !ok {
  363. t.Errorf("%d: response should have been transformable into APIStatus: %v", i, err)
  364. continue
  365. }
  366. if int(status.Status().Code) != test.Response.StatusCode {
  367. t.Errorf("%d: status code did not match response: %#v", i, status.Status())
  368. }
  369. }
  370. if test.ErrFn != nil && !test.ErrFn(err) {
  371. t.Errorf("%d: error function did not match: %v", i, err)
  372. }
  373. if !(test.Data == nil && response == nil) && !api.Semantic.DeepDerivative(test.Data, response) {
  374. t.Errorf("%d: unexpected response: %#v %#v", i, test.Data, response)
  375. }
  376. if test.Created != created {
  377. t.Errorf("%d: expected created %t, got %t", i, test.Created, created)
  378. }
  379. }
  380. }
  381. type renegotiator struct {
  382. called bool
  383. contentType string
  384. params map[string]string
  385. decoder runtime.Decoder
  386. err error
  387. }
  388. func (r *renegotiator) invoke(contentType string, params map[string]string) (runtime.Decoder, error) {
  389. r.called = true
  390. r.contentType = contentType
  391. r.params = params
  392. return r.decoder, r.err
  393. }
  394. func TestTransformResponseNegotiate(t *testing.T) {
  395. invalid := []byte("aaaaa")
  396. uri, _ := url.Parse("http://localhost")
  397. testCases := []struct {
  398. Response *http.Response
  399. Data []byte
  400. Created bool
  401. Error bool
  402. ErrFn func(err error) bool
  403. ContentType string
  404. Called bool
  405. ExpectContentType string
  406. Decoder runtime.Decoder
  407. NegotiateErr error
  408. }{
  409. {
  410. ContentType: "application/json",
  411. Response: &http.Response{
  412. StatusCode: 401,
  413. Header: http.Header{"Content-Type": []string{"application/json"}},
  414. Body: ioutil.NopCloser(bytes.NewReader(invalid)),
  415. },
  416. Error: true,
  417. ErrFn: func(err error) bool {
  418. return err.Error() != "aaaaa" && apierrors.IsUnauthorized(err)
  419. },
  420. },
  421. {
  422. ContentType: "application/json",
  423. Response: &http.Response{
  424. StatusCode: 401,
  425. Header: http.Header{"Content-Type": []string{"application/protobuf"}},
  426. Body: ioutil.NopCloser(bytes.NewReader(invalid)),
  427. },
  428. Decoder: testapi.Default.Codec(),
  429. Called: true,
  430. ExpectContentType: "application/protobuf",
  431. Error: true,
  432. ErrFn: func(err error) bool {
  433. return err.Error() != "aaaaa" && apierrors.IsUnauthorized(err)
  434. },
  435. },
  436. {
  437. ContentType: "application/json",
  438. Response: &http.Response{
  439. StatusCode: 500,
  440. Header: http.Header{"Content-Type": []string{"application/,others"}},
  441. },
  442. Decoder: testapi.Default.Codec(),
  443. Error: true,
  444. ErrFn: func(err error) bool {
  445. return err.Error() == "Internal error occurred: mime: expected token after slash" && err.(apierrors.APIStatus).Status().Code == 500
  446. },
  447. },
  448. {
  449. // no negotiation when no content type specified
  450. Response: &http.Response{
  451. StatusCode: 200,
  452. Header: http.Header{"Content-Type": []string{"text/any"}},
  453. Body: ioutil.NopCloser(bytes.NewReader(invalid)),
  454. },
  455. Decoder: testapi.Default.Codec(),
  456. },
  457. {
  458. // no negotiation when no response content type specified
  459. ContentType: "text/any",
  460. Response: &http.Response{
  461. StatusCode: 200,
  462. Body: ioutil.NopCloser(bytes.NewReader(invalid)),
  463. },
  464. Decoder: testapi.Default.Codec(),
  465. },
  466. {
  467. // unrecognized content type is not handled
  468. ContentType: "application/json",
  469. Response: &http.Response{
  470. StatusCode: 404,
  471. Header: http.Header{"Content-Type": []string{"application/unrecognized"}},
  472. Body: ioutil.NopCloser(bytes.NewReader(invalid)),
  473. },
  474. Decoder: testapi.Default.Codec(),
  475. NegotiateErr: fmt.Errorf("aaaa"),
  476. Called: true,
  477. ExpectContentType: "application/unrecognized",
  478. Error: true,
  479. ErrFn: func(err error) bool {
  480. return err.Error() != "aaaaa" && apierrors.IsNotFound(err)
  481. },
  482. },
  483. }
  484. for i, test := range testCases {
  485. serializers := defaultSerializers()
  486. negotiator := &renegotiator{
  487. decoder: test.Decoder,
  488. err: test.NegotiateErr,
  489. }
  490. serializers.RenegotiatedDecoder = negotiator.invoke
  491. contentConfig := defaultContentConfig()
  492. contentConfig.ContentType = test.ContentType
  493. r := NewRequest(nil, "", uri, "", contentConfig, serializers, nil, nil)
  494. if test.Response.Body == nil {
  495. test.Response.Body = ioutil.NopCloser(bytes.NewReader([]byte{}))
  496. }
  497. result := r.transformResponse(test.Response, &http.Request{})
  498. _, err := result.body, result.err
  499. hasErr := err != nil
  500. if hasErr != test.Error {
  501. t.Errorf("%d: unexpected error: %t %v", i, test.Error, err)
  502. continue
  503. } else if hasErr && test.Response.StatusCode > 399 {
  504. status, ok := err.(apierrors.APIStatus)
  505. if !ok {
  506. t.Errorf("%d: response should have been transformable into APIStatus: %v", i, err)
  507. continue
  508. }
  509. if int(status.Status().Code) != test.Response.StatusCode {
  510. t.Errorf("%d: status code did not match response: %#v", i, status.Status())
  511. }
  512. }
  513. if test.ErrFn != nil && !test.ErrFn(err) {
  514. t.Errorf("%d: error function did not match: %v", i, err)
  515. }
  516. if negotiator.called != test.Called {
  517. t.Errorf("%d: negotiator called %t != %t", i, negotiator.called, test.Called)
  518. }
  519. if !test.Called {
  520. continue
  521. }
  522. if negotiator.contentType != test.ExpectContentType {
  523. t.Errorf("%d: unexpected content type: %s", i, negotiator.contentType)
  524. }
  525. }
  526. }
  527. func TestTransformUnstructuredError(t *testing.T) {
  528. testCases := []struct {
  529. Req *http.Request
  530. Res *http.Response
  531. Resource string
  532. Name string
  533. ErrFn func(error) bool
  534. }{
  535. {
  536. Resource: "foo",
  537. Name: "bar",
  538. Req: &http.Request{
  539. Method: "POST",
  540. },
  541. Res: &http.Response{
  542. StatusCode: http.StatusConflict,
  543. Body: ioutil.NopCloser(bytes.NewReader(nil)),
  544. },
  545. ErrFn: apierrors.IsAlreadyExists,
  546. },
  547. {
  548. Resource: "foo",
  549. Name: "bar",
  550. Req: &http.Request{
  551. Method: "PUT",
  552. },
  553. Res: &http.Response{
  554. StatusCode: http.StatusConflict,
  555. Body: ioutil.NopCloser(bytes.NewReader(nil)),
  556. },
  557. ErrFn: apierrors.IsConflict,
  558. },
  559. {
  560. Resource: "foo",
  561. Name: "bar",
  562. Req: &http.Request{},
  563. Res: &http.Response{
  564. StatusCode: http.StatusNotFound,
  565. Body: ioutil.NopCloser(bytes.NewReader(nil)),
  566. },
  567. ErrFn: apierrors.IsNotFound,
  568. },
  569. {
  570. Req: &http.Request{},
  571. Res: &http.Response{
  572. StatusCode: http.StatusBadRequest,
  573. Body: ioutil.NopCloser(bytes.NewReader(nil)),
  574. },
  575. ErrFn: apierrors.IsBadRequest,
  576. },
  577. }
  578. for _, testCase := range testCases {
  579. r := &Request{
  580. content: defaultContentConfig(),
  581. serializers: defaultSerializers(),
  582. resourceName: testCase.Name,
  583. resource: testCase.Resource,
  584. }
  585. result := r.transformResponse(testCase.Res, testCase.Req)
  586. err := result.err
  587. if !testCase.ErrFn(err) {
  588. t.Errorf("unexpected error: %v", err)
  589. continue
  590. }
  591. if len(testCase.Name) != 0 && !strings.Contains(err.Error(), testCase.Name) {
  592. t.Errorf("unexpected error string: %s", err)
  593. }
  594. if len(testCase.Resource) != 0 && !strings.Contains(err.Error(), testCase.Resource) {
  595. t.Errorf("unexpected error string: %s", err)
  596. }
  597. }
  598. }
  599. func TestRequestWatch(t *testing.T) {
  600. testCases := []struct {
  601. Request *Request
  602. Err bool
  603. ErrFn func(error) bool
  604. Empty bool
  605. }{
  606. {
  607. Request: &Request{err: errors.New("bail")},
  608. Err: true,
  609. },
  610. {
  611. Request: &Request{baseURL: &url.URL{}, pathPrefix: "%"},
  612. Err: true,
  613. },
  614. {
  615. Request: &Request{
  616. client: clientFunc(func(req *http.Request) (*http.Response, error) {
  617. return nil, errors.New("err")
  618. }),
  619. baseURL: &url.URL{},
  620. },
  621. Err: true,
  622. },
  623. {
  624. Request: &Request{
  625. content: defaultContentConfig(),
  626. serializers: defaultSerializers(),
  627. client: clientFunc(func(req *http.Request) (*http.Response, error) {
  628. return &http.Response{
  629. StatusCode: http.StatusForbidden,
  630. Body: ioutil.NopCloser(bytes.NewReader([]byte{})),
  631. }, nil
  632. }),
  633. baseURL: &url.URL{},
  634. },
  635. Err: true,
  636. ErrFn: func(err error) bool {
  637. return apierrors.IsForbidden(err)
  638. },
  639. },
  640. {
  641. Request: &Request{
  642. content: defaultContentConfig(),
  643. serializers: defaultSerializers(),
  644. client: clientFunc(func(req *http.Request) (*http.Response, error) {
  645. return &http.Response{
  646. StatusCode: http.StatusUnauthorized,
  647. Body: ioutil.NopCloser(bytes.NewReader([]byte{})),
  648. }, nil
  649. }),
  650. baseURL: &url.URL{},
  651. },
  652. Err: true,
  653. ErrFn: func(err error) bool {
  654. return apierrors.IsUnauthorized(err)
  655. },
  656. },
  657. {
  658. Request: &Request{
  659. content: defaultContentConfig(),
  660. serializers: defaultSerializers(),
  661. client: clientFunc(func(req *http.Request) (*http.Response, error) {
  662. return &http.Response{
  663. StatusCode: http.StatusUnauthorized,
  664. Body: ioutil.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(testapi.Default.Codec(), &unversioned.Status{
  665. Status: unversioned.StatusFailure,
  666. Reason: unversioned.StatusReasonUnauthorized,
  667. })))),
  668. }, nil
  669. }),
  670. baseURL: &url.URL{},
  671. },
  672. Err: true,
  673. ErrFn: func(err error) bool {
  674. return apierrors.IsUnauthorized(err)
  675. },
  676. },
  677. {
  678. Request: &Request{
  679. serializers: defaultSerializers(),
  680. client: clientFunc(func(req *http.Request) (*http.Response, error) {
  681. return nil, io.EOF
  682. }),
  683. baseURL: &url.URL{},
  684. },
  685. Empty: true,
  686. },
  687. {
  688. Request: &Request{
  689. serializers: defaultSerializers(),
  690. client: clientFunc(func(req *http.Request) (*http.Response, error) {
  691. return nil, &url.Error{Err: io.EOF}
  692. }),
  693. baseURL: &url.URL{},
  694. },
  695. Empty: true,
  696. },
  697. {
  698. Request: &Request{
  699. serializers: defaultSerializers(),
  700. client: clientFunc(func(req *http.Request) (*http.Response, error) {
  701. return nil, errors.New("http: can't write HTTP request on broken connection")
  702. }),
  703. baseURL: &url.URL{},
  704. },
  705. Empty: true,
  706. },
  707. {
  708. Request: &Request{
  709. serializers: defaultSerializers(),
  710. client: clientFunc(func(req *http.Request) (*http.Response, error) {
  711. return nil, errors.New("foo: connection reset by peer")
  712. }),
  713. baseURL: &url.URL{},
  714. },
  715. Empty: true,
  716. },
  717. }
  718. for i, testCase := range testCases {
  719. t.Logf("testcase %v", testCase.Request)
  720. testCase.Request.backoffMgr = &NoBackoff{}
  721. watch, err := testCase.Request.Watch()
  722. hasErr := err != nil
  723. if hasErr != testCase.Err {
  724. t.Errorf("%d: expected %t, got %t: %v", i, testCase.Err, hasErr, err)
  725. continue
  726. }
  727. if testCase.ErrFn != nil && !testCase.ErrFn(err) {
  728. t.Errorf("%d: error not valid: %v", i, err)
  729. }
  730. if hasErr && watch != nil {
  731. t.Errorf("%d: watch should be nil when error is returned", i)
  732. continue
  733. }
  734. if testCase.Empty {
  735. _, ok := <-watch.ResultChan()
  736. if ok {
  737. t.Errorf("%d: expected the watch to be empty: %#v", i, watch)
  738. }
  739. }
  740. }
  741. }
  742. func TestRequestStream(t *testing.T) {
  743. testCases := []struct {
  744. Request *Request
  745. Err bool
  746. }{
  747. {
  748. Request: &Request{err: errors.New("bail")},
  749. Err: true,
  750. },
  751. {
  752. Request: &Request{baseURL: &url.URL{}, pathPrefix: "%"},
  753. Err: true,
  754. },
  755. {
  756. Request: &Request{
  757. client: clientFunc(func(req *http.Request) (*http.Response, error) {
  758. return nil, errors.New("err")
  759. }),
  760. baseURL: &url.URL{},
  761. },
  762. Err: true,
  763. },
  764. {
  765. Request: &Request{
  766. client: clientFunc(func(req *http.Request) (*http.Response, error) {
  767. return &http.Response{
  768. StatusCode: http.StatusUnauthorized,
  769. Body: ioutil.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(testapi.Default.Codec(), &unversioned.Status{
  770. Status: unversioned.StatusFailure,
  771. Reason: unversioned.StatusReasonUnauthorized,
  772. })))),
  773. }, nil
  774. }),
  775. content: defaultContentConfig(),
  776. serializers: defaultSerializers(),
  777. baseURL: &url.URL{},
  778. },
  779. Err: true,
  780. },
  781. }
  782. for i, testCase := range testCases {
  783. testCase.Request.backoffMgr = &NoBackoff{}
  784. body, err := testCase.Request.Stream()
  785. hasErr := err != nil
  786. if hasErr != testCase.Err {
  787. t.Errorf("%d: expected %t, got %t: %v", i, testCase.Err, hasErr, err)
  788. }
  789. if hasErr && body != nil {
  790. t.Errorf("%d: body should be nil when error is returned", i)
  791. }
  792. }
  793. }
  794. type fakeUpgradeConnection struct{}
  795. func (c *fakeUpgradeConnection) CreateStream(headers http.Header) (httpstream.Stream, error) {
  796. return nil, nil
  797. }
  798. func (c *fakeUpgradeConnection) Close() error {
  799. return nil
  800. }
  801. func (c *fakeUpgradeConnection) CloseChan() <-chan bool {
  802. return make(chan bool)
  803. }
  804. func (c *fakeUpgradeConnection) SetIdleTimeout(timeout time.Duration) {
  805. }
  806. type fakeUpgradeRoundTripper struct {
  807. req *http.Request
  808. conn httpstream.Connection
  809. }
  810. func (f *fakeUpgradeRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
  811. f.req = req
  812. b := []byte{}
  813. body := ioutil.NopCloser(bytes.NewReader(b))
  814. resp := &http.Response{
  815. StatusCode: 101,
  816. Body: body,
  817. }
  818. return resp, nil
  819. }
  820. func (f *fakeUpgradeRoundTripper) NewConnection(resp *http.Response) (httpstream.Connection, error) {
  821. return f.conn, nil
  822. }
  823. func TestRequestDo(t *testing.T) {
  824. testCases := []struct {
  825. Request *Request
  826. Err bool
  827. }{
  828. {
  829. Request: &Request{err: errors.New("bail")},
  830. Err: true,
  831. },
  832. {
  833. Request: &Request{baseURL: &url.URL{}, pathPrefix: "%"},
  834. Err: true,
  835. },
  836. {
  837. Request: &Request{
  838. client: clientFunc(func(req *http.Request) (*http.Response, error) {
  839. return nil, errors.New("err")
  840. }),
  841. baseURL: &url.URL{},
  842. },
  843. Err: true,
  844. },
  845. }
  846. for i, testCase := range testCases {
  847. testCase.Request.backoffMgr = &NoBackoff{}
  848. body, err := testCase.Request.Do().Raw()
  849. hasErr := err != nil
  850. if hasErr != testCase.Err {
  851. t.Errorf("%d: expected %t, got %t: %v", i, testCase.Err, hasErr, err)
  852. }
  853. if hasErr && body != nil {
  854. t.Errorf("%d: body should be nil when error is returned", i)
  855. }
  856. }
  857. }
  858. func TestDoRequestNewWay(t *testing.T) {
  859. reqBody := "request body"
  860. expectedObj := &api.Service{Spec: api.ServiceSpec{Ports: []api.ServicePort{{
  861. Protocol: "TCP",
  862. Port: 12345,
  863. TargetPort: intstr.FromInt(12345),
  864. }}}}
  865. expectedBody, _ := runtime.Encode(testapi.Default.Codec(), expectedObj)
  866. fakeHandler := utiltesting.FakeHandler{
  867. StatusCode: 200,
  868. ResponseBody: string(expectedBody),
  869. T: t,
  870. }
  871. testServer := httptest.NewServer(&fakeHandler)
  872. defer testServer.Close()
  873. c := testRESTClient(t, testServer)
  874. obj, err := c.Verb("POST").
  875. Prefix("foo", "bar").
  876. Suffix("baz").
  877. Timeout(time.Second).
  878. Body([]byte(reqBody)).
  879. Do().Get()
  880. if err != nil {
  881. t.Errorf("Unexpected error: %v %#v", err, err)
  882. return
  883. }
  884. if obj == nil {
  885. t.Error("nil obj")
  886. } else if !api.Semantic.DeepDerivative(expectedObj, obj) {
  887. t.Errorf("Expected: %#v, got %#v", expectedObj, obj)
  888. }
  889. requestURL := testapi.Default.ResourcePathWithPrefix("foo/bar", "", "", "baz")
  890. requestURL += "?timeout=1s"
  891. fakeHandler.ValidateRequest(t, requestURL, "POST", &reqBody)
  892. }
  893. // This test assumes that the client implementation backs off exponentially, for an individual request.
  894. func TestBackoffLifecycle(t *testing.T) {
  895. count := 0
  896. testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
  897. count++
  898. t.Logf("Attempt %d", count)
  899. if count == 5 || count == 9 {
  900. w.WriteHeader(http.StatusOK)
  901. return
  902. } else {
  903. w.WriteHeader(http.StatusGatewayTimeout)
  904. return
  905. }
  906. }))
  907. defer testServer.Close()
  908. c := testRESTClient(t, testServer)
  909. // Test backoff recovery and increase. This correlates to the constants
  910. // which are used in the server implementation returning StatusOK above.
  911. seconds := []int{0, 1, 2, 4, 8, 0, 1, 2, 4, 0}
  912. request := c.Verb("POST").Prefix("backofftest").Suffix("abc")
  913. clock := clock.FakeClock{}
  914. request.backoffMgr = &URLBackoff{
  915. // Use a fake backoff here to avoid flakes and speed the test up.
  916. Backoff: flowcontrol.NewFakeBackOff(
  917. time.Duration(1)*time.Second,
  918. time.Duration(200)*time.Second,
  919. &clock,
  920. )}
  921. for _, sec := range seconds {
  922. thisBackoff := request.backoffMgr.CalculateBackoff(request.URL())
  923. t.Logf("Current backoff %v", thisBackoff)
  924. if thisBackoff != time.Duration(sec)*time.Second {
  925. t.Errorf("Backoff is %v instead of %v", thisBackoff, sec)
  926. }
  927. now := clock.Now()
  928. request.DoRaw()
  929. elapsed := clock.Since(now)
  930. if clock.Since(now) != thisBackoff {
  931. t.Errorf("CalculatedBackoff not honored by clock: Expected time of %v, but got %v ", thisBackoff, elapsed)
  932. }
  933. }
  934. }
  935. type testBackoffManager struct {
  936. sleeps []time.Duration
  937. }
  938. func (b *testBackoffManager) UpdateBackoff(actualUrl *url.URL, err error, responseCode int) {
  939. }
  940. func (b *testBackoffManager) CalculateBackoff(actualUrl *url.URL) time.Duration {
  941. return time.Duration(0)
  942. }
  943. func (b *testBackoffManager) Sleep(d time.Duration) {
  944. b.sleeps = append(b.sleeps, d)
  945. }
  946. func TestCheckRetryClosesBody(t *testing.T) {
  947. count := 0
  948. ch := make(chan struct{})
  949. testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
  950. count++
  951. t.Logf("attempt %d", count)
  952. if count >= 5 {
  953. w.WriteHeader(http.StatusOK)
  954. close(ch)
  955. return
  956. }
  957. w.Header().Set("Retry-After", "1")
  958. http.Error(w, "Too many requests, please try again later.", apierrors.StatusTooManyRequests)
  959. }))
  960. defer testServer.Close()
  961. backoffMgr := &testBackoffManager{}
  962. expectedSleeps := []time.Duration{0, time.Second, 0, time.Second, 0, time.Second, 0, time.Second, 0}
  963. c := testRESTClient(t, testServer)
  964. c.createBackoffMgr = func() BackoffManager { return backoffMgr }
  965. _, err := c.Verb("POST").
  966. Prefix("foo", "bar").
  967. Suffix("baz").
  968. Timeout(time.Second).
  969. Body([]byte(strings.Repeat("abcd", 1000))).
  970. DoRaw()
  971. if err != nil {
  972. t.Fatalf("Unexpected error: %v %#v", err, err)
  973. }
  974. <-ch
  975. if count != 5 {
  976. t.Errorf("unexpected retries: %d", count)
  977. }
  978. if !reflect.DeepEqual(backoffMgr.sleeps, expectedSleeps) {
  979. t.Errorf("unexpected sleeps, expected: %v, got: %v", expectedSleeps, backoffMgr.sleeps)
  980. }
  981. }
  982. func TestCheckRetryHandles429And5xx(t *testing.T) {
  983. count := 0
  984. ch := make(chan struct{})
  985. testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
  986. data, err := ioutil.ReadAll(req.Body)
  987. if err != nil {
  988. t.Fatalf("unable to read request body: %v", err)
  989. }
  990. if !bytes.Equal(data, []byte(strings.Repeat("abcd", 1000))) {
  991. t.Fatalf("retry did not send a complete body: %s", data)
  992. }
  993. t.Logf("attempt %d", count)
  994. if count >= 4 {
  995. w.WriteHeader(http.StatusOK)
  996. close(ch)
  997. return
  998. }
  999. w.Header().Set("Retry-After", "0")
  1000. w.WriteHeader([]int{apierrors.StatusTooManyRequests, 500, 501, 504}[count])
  1001. count++
  1002. }))
  1003. defer testServer.Close()
  1004. c := testRESTClient(t, testServer)
  1005. _, err := c.Verb("POST").
  1006. Prefix("foo", "bar").
  1007. Suffix("baz").
  1008. Timeout(time.Second).
  1009. Body([]byte(strings.Repeat("abcd", 1000))).
  1010. DoRaw()
  1011. if err != nil {
  1012. t.Fatalf("Unexpected error: %v %#v", err, err)
  1013. }
  1014. <-ch
  1015. if count != 4 {
  1016. t.Errorf("unexpected retries: %d", count)
  1017. }
  1018. }
  1019. func BenchmarkCheckRetryClosesBody(b *testing.B) {
  1020. count := 0
  1021. testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
  1022. count++
  1023. if count%3 == 0 {
  1024. w.WriteHeader(http.StatusOK)
  1025. return
  1026. }
  1027. w.Header().Set("Retry-After", "0")
  1028. w.WriteHeader(apierrors.StatusTooManyRequests)
  1029. }))
  1030. defer testServer.Close()
  1031. c := testRESTClient(b, testServer)
  1032. r := c.Verb("POST").
  1033. Prefix("foo", "bar").
  1034. Suffix("baz").
  1035. Timeout(time.Second).
  1036. Body([]byte(strings.Repeat("abcd", 1000)))
  1037. for i := 0; i < b.N; i++ {
  1038. if _, err := r.DoRaw(); err != nil {
  1039. b.Fatalf("Unexpected error: %v %#v", err, err)
  1040. }
  1041. }
  1042. }
  1043. func TestDoRequestNewWayReader(t *testing.T) {
  1044. reqObj := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}}
  1045. reqBodyExpected, _ := runtime.Encode(testapi.Default.Codec(), reqObj)
  1046. expectedObj := &api.Service{Spec: api.ServiceSpec{Ports: []api.ServicePort{{
  1047. Protocol: "TCP",
  1048. Port: 12345,
  1049. TargetPort: intstr.FromInt(12345),
  1050. }}}}
  1051. expectedBody, _ := runtime.Encode(testapi.Default.Codec(), expectedObj)
  1052. fakeHandler := utiltesting.FakeHandler{
  1053. StatusCode: 200,
  1054. ResponseBody: string(expectedBody),
  1055. T: t,
  1056. }
  1057. testServer := httptest.NewServer(&fakeHandler)
  1058. defer testServer.Close()
  1059. c := testRESTClient(t, testServer)
  1060. obj, err := c.Verb("POST").
  1061. Resource("bar").
  1062. Name("baz").
  1063. Prefix("foo").
  1064. LabelsSelectorParam(labels.Set{"name": "foo"}.AsSelector()).
  1065. Timeout(time.Second).
  1066. Body(bytes.NewBuffer(reqBodyExpected)).
  1067. Do().Get()
  1068. if err != nil {
  1069. t.Errorf("Unexpected error: %v %#v", err, err)
  1070. return
  1071. }
  1072. if obj == nil {
  1073. t.Error("nil obj")
  1074. } else if !api.Semantic.DeepDerivative(expectedObj, obj) {
  1075. t.Errorf("Expected: %#v, got %#v", expectedObj, obj)
  1076. }
  1077. tmpStr := string(reqBodyExpected)
  1078. requestURL := testapi.Default.ResourcePathWithPrefix("foo", "bar", "", "baz")
  1079. requestURL += "?" + unversioned.LabelSelectorQueryParam(testapi.Default.GroupVersion().String()) + "=name%3Dfoo&timeout=1s"
  1080. fakeHandler.ValidateRequest(t, requestURL, "POST", &tmpStr)
  1081. }
  1082. func TestDoRequestNewWayObj(t *testing.T) {
  1083. reqObj := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}}
  1084. reqBodyExpected, _ := runtime.Encode(testapi.Default.Codec(), reqObj)
  1085. expectedObj := &api.Service{Spec: api.ServiceSpec{Ports: []api.ServicePort{{
  1086. Protocol: "TCP",
  1087. Port: 12345,
  1088. TargetPort: intstr.FromInt(12345),
  1089. }}}}
  1090. expectedBody, _ := runtime.Encode(testapi.Default.Codec(), expectedObj)
  1091. fakeHandler := utiltesting.FakeHandler{
  1092. StatusCode: 200,
  1093. ResponseBody: string(expectedBody),
  1094. T: t,
  1095. }
  1096. testServer := httptest.NewServer(&fakeHandler)
  1097. defer testServer.Close()
  1098. c := testRESTClient(t, testServer)
  1099. obj, err := c.Verb("POST").
  1100. Suffix("baz").
  1101. Name("bar").
  1102. Resource("foo").
  1103. LabelsSelectorParam(labels.Set{"name": "foo"}.AsSelector()).
  1104. Timeout(time.Second).
  1105. Body(reqObj).
  1106. Do().Get()
  1107. if err != nil {
  1108. t.Errorf("Unexpected error: %v %#v", err, err)
  1109. return
  1110. }
  1111. if obj == nil {
  1112. t.Error("nil obj")
  1113. } else if !api.Semantic.DeepDerivative(expectedObj, obj) {
  1114. t.Errorf("Expected: %#v, got %#v", expectedObj, obj)
  1115. }
  1116. tmpStr := string(reqBodyExpected)
  1117. requestURL := testapi.Default.ResourcePath("foo", "", "bar/baz")
  1118. requestURL += "?" + unversioned.LabelSelectorQueryParam(testapi.Default.GroupVersion().String()) + "=name%3Dfoo&timeout=1s"
  1119. fakeHandler.ValidateRequest(t, requestURL, "POST", &tmpStr)
  1120. }
  1121. func TestDoRequestNewWayFile(t *testing.T) {
  1122. reqObj := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}}
  1123. reqBodyExpected, err := runtime.Encode(testapi.Default.Codec(), reqObj)
  1124. if err != nil {
  1125. t.Errorf("unexpected error: %v", err)
  1126. }
  1127. file, err := ioutil.TempFile("", "foo")
  1128. if err != nil {
  1129. t.Errorf("unexpected error: %v", err)
  1130. }
  1131. defer file.Close()
  1132. _, err = file.Write(reqBodyExpected)
  1133. if err != nil {
  1134. t.Errorf("unexpected error: %v", err)
  1135. }
  1136. expectedObj := &api.Service{Spec: api.ServiceSpec{Ports: []api.ServicePort{{
  1137. Protocol: "TCP",
  1138. Port: 12345,
  1139. TargetPort: intstr.FromInt(12345),
  1140. }}}}
  1141. expectedBody, _ := runtime.Encode(testapi.Default.Codec(), expectedObj)
  1142. fakeHandler := utiltesting.FakeHandler{
  1143. StatusCode: 200,
  1144. ResponseBody: string(expectedBody),
  1145. T: t,
  1146. }
  1147. testServer := httptest.NewServer(&fakeHandler)
  1148. defer testServer.Close()
  1149. c := testRESTClient(t, testServer)
  1150. wasCreated := true
  1151. obj, err := c.Verb("POST").
  1152. Prefix("foo/bar", "baz").
  1153. Timeout(time.Second).
  1154. Body(file.Name()).
  1155. Do().WasCreated(&wasCreated).Get()
  1156. if err != nil {
  1157. t.Errorf("Unexpected error: %v %#v", err, err)
  1158. return
  1159. }
  1160. if obj == nil {
  1161. t.Error("nil obj")
  1162. } else if !api.Semantic.DeepDerivative(expectedObj, obj) {
  1163. t.Errorf("Expected: %#v, got %#v", expectedObj, obj)
  1164. }
  1165. if wasCreated {
  1166. t.Errorf("expected object was created")
  1167. }
  1168. tmpStr := string(reqBodyExpected)
  1169. requestURL := testapi.Default.ResourcePathWithPrefix("foo/bar/baz", "", "", "")
  1170. requestURL += "?timeout=1s"
  1171. fakeHandler.ValidateRequest(t, requestURL, "POST", &tmpStr)
  1172. }
  1173. func TestWasCreated(t *testing.T) {
  1174. reqObj := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}}
  1175. reqBodyExpected, err := runtime.Encode(testapi.Default.Codec(), reqObj)
  1176. if err != nil {
  1177. t.Errorf("unexpected error: %v", err)
  1178. }
  1179. expectedObj := &api.Service{Spec: api.ServiceSpec{Ports: []api.ServicePort{{
  1180. Protocol: "TCP",
  1181. Port: 12345,
  1182. TargetPort: intstr.FromInt(12345),
  1183. }}}}
  1184. expectedBody, _ := runtime.Encode(testapi.Default.Codec(), expectedObj)
  1185. fakeHandler := utiltesting.FakeHandler{
  1186. StatusCode: 201,
  1187. ResponseBody: string(expectedBody),
  1188. T: t,
  1189. }
  1190. testServer := httptest.NewServer(&fakeHandler)
  1191. defer testServer.Close()
  1192. c := testRESTClient(t, testServer)
  1193. wasCreated := false
  1194. obj, err := c.Verb("PUT").
  1195. Prefix("foo/bar", "baz").
  1196. Timeout(time.Second).
  1197. Body(reqBodyExpected).
  1198. Do().WasCreated(&wasCreated).Get()
  1199. if err != nil {
  1200. t.Errorf("Unexpected error: %v %#v", err, err)
  1201. return
  1202. }
  1203. if obj == nil {
  1204. t.Error("nil obj")
  1205. } else if !api.Semantic.DeepDerivative(expectedObj, obj) {
  1206. t.Errorf("Expected: %#v, got %#v", expectedObj, obj)
  1207. }
  1208. if !wasCreated {
  1209. t.Errorf("Expected object was created")
  1210. }
  1211. tmpStr := string(reqBodyExpected)
  1212. requestURL := testapi.Default.ResourcePathWithPrefix("foo/bar/baz", "", "", "")
  1213. requestURL += "?timeout=1s"
  1214. fakeHandler.ValidateRequest(t, requestURL, "PUT", &tmpStr)
  1215. }
  1216. func TestVerbs(t *testing.T) {
  1217. c := testRESTClient(t, nil)
  1218. if r := c.Post(); r.verb != "POST" {
  1219. t.Errorf("Post verb is wrong")
  1220. }
  1221. if r := c.Put(); r.verb != "PUT" {
  1222. t.Errorf("Put verb is wrong")
  1223. }
  1224. if r := c.Get(); r.verb != "GET" {
  1225. t.Errorf("Get verb is wrong")
  1226. }
  1227. if r := c.Delete(); r.verb != "DELETE" {
  1228. t.Errorf("Delete verb is wrong")
  1229. }
  1230. }
  1231. func TestAbsPath(t *testing.T) {
  1232. for i, tc := range []struct {
  1233. configPrefix string
  1234. resourcePrefix string
  1235. absPath string
  1236. wantsAbsPath string
  1237. }{
  1238. {"/", "", "", "/"},
  1239. {"", "", "/", "/"},
  1240. {"", "", "/api", "/api"},
  1241. {"", "", "/api/", "/api/"},
  1242. {"", "", "/apis", "/apis"},
  1243. {"", "/foo", "/bar/foo", "/bar/foo"},
  1244. {"", "/api/foo/123", "/bar/foo", "/bar/foo"},
  1245. {"/p1", "", "", "/p1"},
  1246. {"/p1", "", "/", "/p1/"},
  1247. {"/p1", "", "/api", "/p1/api"},
  1248. {"/p1", "", "/apis", "/p1/apis"},
  1249. {"/p1", "/r1", "/apis", "/p1/apis"},
  1250. {"/p1", "/api/r1", "/apis", "/p1/apis"},
  1251. {"/p1/api/p2", "", "", "/p1/api/p2"},
  1252. {"/p1/api/p2", "", "/", "/p1/api/p2/"},
  1253. {"/p1/api/p2", "", "/api", "/p1/api/p2/api"},
  1254. {"/p1/api/p2", "", "/api/", "/p1/api/p2/api/"},
  1255. {"/p1/api/p2", "/r1", "/api/", "/p1/api/p2/api/"},
  1256. {"/p1/api/p2", "/api/r1", "/api/", "/p1/api/p2/api/"},
  1257. } {
  1258. u, _ := url.Parse("http://localhost:123" + tc.configPrefix)
  1259. r := NewRequest(nil, "POST", u, "", ContentConfig{GroupVersion: &unversioned.GroupVersion{Group: "test"}}, Serializers{}, nil, nil).Prefix(tc.resourcePrefix).AbsPath(tc.absPath)
  1260. if r.pathPrefix != tc.wantsAbsPath {
  1261. t.Errorf("test case %d failed, unexpected path: %q, expected %q", i, r.pathPrefix, tc.wantsAbsPath)
  1262. }
  1263. }
  1264. }
  1265. func TestUintParam(t *testing.T) {
  1266. table := []struct {
  1267. name string
  1268. testVal uint64
  1269. expectStr string
  1270. }{
  1271. {"foo", 31415, "http://localhost?foo=31415"},
  1272. {"bar", 42, "http://localhost?bar=42"},
  1273. {"baz", 0, "http://localhost?baz=0"},
  1274. }
  1275. for _, item := range table {
  1276. u, _ := url.Parse("http://localhost")
  1277. r := NewRequest(nil, "GET", u, "", ContentConfig{GroupVersion: &unversioned.GroupVersion{Group: "test"}}, Serializers{}, nil, nil).AbsPath("").UintParam(item.name, item.testVal)
  1278. if e, a := item.expectStr, r.URL().String(); e != a {
  1279. t.Errorf("expected %v, got %v", e, a)
  1280. }
  1281. }
  1282. }
  1283. func TestUnacceptableParamNames(t *testing.T) {
  1284. table := []struct {
  1285. name string
  1286. testVal string
  1287. expectSuccess bool
  1288. }{
  1289. {"timeout", "42", false},
  1290. }
  1291. for _, item := range table {
  1292. c := testRESTClient(t, nil)
  1293. r := c.Get().setParam(item.name, item.testVal)
  1294. if e, a := item.expectSuccess, r.err == nil; e != a {
  1295. t.Errorf("expected %v, got %v (%v)", e, a, r.err)
  1296. }
  1297. }
  1298. }
  1299. func TestBody(t *testing.T) {
  1300. const data = "test payload"
  1301. obj := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}}
  1302. bodyExpected, _ := runtime.Encode(testapi.Default.Codec(), obj)
  1303. f, err := ioutil.TempFile("", "test_body")
  1304. if err != nil {
  1305. t.Fatalf("TempFile error: %v", err)
  1306. }
  1307. if _, err := f.WriteString(data); err != nil {
  1308. t.Fatalf("TempFile.WriteString error: %v", err)
  1309. }
  1310. f.Close()
  1311. var nilObject *api.DeleteOptions
  1312. typedObject := interface{}(nilObject)
  1313. c := testRESTClient(t, nil)
  1314. tests := []struct {
  1315. input interface{}
  1316. expected string
  1317. headers map[string]string
  1318. }{
  1319. {[]byte(data), data, nil},
  1320. {f.Name(), data, nil},
  1321. {strings.NewReader(data), data, nil},
  1322. {obj, string(bodyExpected), map[string]string{"Content-Type": "application/json"}},
  1323. {typedObject, "", nil},
  1324. }
  1325. for i, tt := range tests {
  1326. r := c.Post().Body(tt.input)
  1327. if r.err != nil {
  1328. t.Errorf("%d: r.Body(%#v) error: %v", i, tt, r.err)
  1329. continue
  1330. }
  1331. if tt.headers != nil {
  1332. for k, v := range tt.headers {
  1333. if r.headers.Get(k) != v {
  1334. t.Errorf("%d: r.headers[%q] = %q; want %q", i, k, v, v)
  1335. }
  1336. }
  1337. }
  1338. if r.body == nil {
  1339. if len(tt.expected) != 0 {
  1340. t.Errorf("%d: r.body = %q; want %q", i, r.body, tt.expected)
  1341. }
  1342. continue
  1343. }
  1344. buf := make([]byte, len(tt.expected))
  1345. if _, err := r.body.Read(buf); err != nil {
  1346. t.Errorf("%d: r.body.Read error: %v", i, err)
  1347. continue
  1348. }
  1349. body := string(buf)
  1350. if body != tt.expected {
  1351. t.Errorf("%d: r.body = %q; want %q", i, body, tt.expected)
  1352. }
  1353. }
  1354. }
  1355. func TestWatch(t *testing.T) {
  1356. var table = []struct {
  1357. t watch.EventType
  1358. obj runtime.Object
  1359. }{
  1360. {watch.Added, &api.Pod{ObjectMeta: api.ObjectMeta{Name: "first"}}},
  1361. {watch.Modified, &api.Pod{ObjectMeta: api.ObjectMeta{Name: "second"}}},
  1362. {watch.Deleted, &api.Pod{ObjectMeta: api.ObjectMeta{Name: "last"}}},
  1363. }
  1364. testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1365. flusher, ok := w.(http.Flusher)
  1366. if !ok {
  1367. panic("need flusher!")
  1368. }
  1369. w.Header().Set("Transfer-Encoding", "chunked")
  1370. w.WriteHeader(http.StatusOK)
  1371. flusher.Flush()
  1372. encoder := versioned.NewEncoder(streaming.NewEncoder(w, testapi.Default.Codec()), testapi.Default.Codec())
  1373. for _, item := range table {
  1374. if err := encoder.Encode(&watch.Event{Type: item.t, Object: item.obj}); err != nil {
  1375. panic(err)
  1376. }
  1377. flusher.Flush()
  1378. }
  1379. }))
  1380. defer testServer.Close()
  1381. s := testRESTClient(t, testServer)
  1382. watching, err := s.Get().Prefix("path/to/watch/thing").Watch()
  1383. if err != nil {
  1384. t.Fatalf("Unexpected error")
  1385. }
  1386. for _, item := range table {
  1387. got, ok := <-watching.ResultChan()
  1388. if !ok {
  1389. t.Fatalf("Unexpected early close")
  1390. }
  1391. if e, a := item.t, got.Type; e != a {
  1392. t.Errorf("Expected %v, got %v", e, a)
  1393. }
  1394. if e, a := item.obj, got.Object; !api.Semantic.DeepDerivative(e, a) {
  1395. t.Errorf("Expected %v, got %v", e, a)
  1396. }
  1397. }
  1398. _, ok := <-watching.ResultChan()
  1399. if ok {
  1400. t.Fatal("Unexpected non-close")
  1401. }
  1402. }
  1403. func TestStream(t *testing.T) {
  1404. expectedBody := "expected body"
  1405. testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1406. flusher, ok := w.(http.Flusher)
  1407. if !ok {
  1408. panic("need flusher!")
  1409. }
  1410. w.Header().Set("Transfer-Encoding", "chunked")
  1411. w.WriteHeader(http.StatusOK)
  1412. w.Write([]byte(expectedBody))
  1413. flusher.Flush()
  1414. }))
  1415. defer testServer.Close()
  1416. s := testRESTClient(t, testServer)
  1417. readCloser, err := s.Get().Prefix("path/to/stream/thing").Stream()
  1418. if err != nil {
  1419. t.Fatalf("unexpected error: %v", err)
  1420. }
  1421. defer readCloser.Close()
  1422. buf := new(bytes.Buffer)
  1423. buf.ReadFrom(readCloser)
  1424. resultBody := buf.String()
  1425. if expectedBody != resultBody {
  1426. t.Errorf("Expected %s, got %s", expectedBody, resultBody)
  1427. }
  1428. }
  1429. func testRESTClient(t testing.TB, srv *httptest.Server) *RESTClient {
  1430. baseURL, _ := url.Parse("http://localhost")
  1431. if srv != nil {
  1432. var err error
  1433. baseURL, err = url.Parse(srv.URL)
  1434. if err != nil {
  1435. t.Fatalf("failed to parse test URL: %v", err)
  1436. }
  1437. }
  1438. versionedAPIPath := testapi.Default.ResourcePath("", "", "")
  1439. client, err := NewRESTClient(baseURL, versionedAPIPath, defaultContentConfig(), 0, 0, nil, nil)
  1440. if err != nil {
  1441. t.Fatalf("failed to create a client: %v", err)
  1442. }
  1443. return client
  1444. }