httpcache_test.go 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360
  1. package httpcache
  2. import (
  3. "bytes"
  4. "errors"
  5. "flag"
  6. "io"
  7. "io/ioutil"
  8. "net/http"
  9. "net/http/httptest"
  10. "os"
  11. "strconv"
  12. "testing"
  13. "time"
  14. )
  15. var s struct {
  16. server *httptest.Server
  17. client http.Client
  18. transport *Transport
  19. done chan struct{} // Closed to unlock infinite handlers.
  20. }
  21. type fakeClock struct {
  22. elapsed time.Duration
  23. }
  24. func (c *fakeClock) since(t time.Time) time.Duration {
  25. return c.elapsed
  26. }
  27. func TestMain(m *testing.M) {
  28. flag.Parse()
  29. setup()
  30. code := m.Run()
  31. teardown()
  32. os.Exit(code)
  33. }
  34. func setup() {
  35. tp := NewMemoryCacheTransport()
  36. client := http.Client{Transport: tp}
  37. s.transport = tp
  38. s.client = client
  39. s.done = make(chan struct{})
  40. mux := http.NewServeMux()
  41. s.server = httptest.NewServer(mux)
  42. mux.HandleFunc("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  43. w.Header().Set("Cache-Control", "max-age=3600")
  44. }))
  45. mux.HandleFunc("/method", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  46. w.Header().Set("Cache-Control", "max-age=3600")
  47. w.Write([]byte(r.Method))
  48. }))
  49. mux.HandleFunc("/range", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  50. lm := "Fri, 14 Dec 2010 01:01:50 GMT"
  51. if r.Header.Get("if-modified-since") == lm {
  52. w.WriteHeader(http.StatusNotModified)
  53. return
  54. }
  55. w.Header().Set("last-modified", lm)
  56. if r.Header.Get("range") == "bytes=4-9" {
  57. w.WriteHeader(http.StatusPartialContent)
  58. w.Write([]byte(" text "))
  59. return
  60. }
  61. w.Write([]byte("Some text content"))
  62. }))
  63. mux.HandleFunc("/nostore", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  64. w.Header().Set("Cache-Control", "no-store")
  65. }))
  66. mux.HandleFunc("/etag", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  67. etag := "124567"
  68. if r.Header.Get("if-none-match") == etag {
  69. w.WriteHeader(http.StatusNotModified)
  70. return
  71. }
  72. w.Header().Set("etag", etag)
  73. }))
  74. mux.HandleFunc("/lastmodified", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  75. lm := "Fri, 14 Dec 2010 01:01:50 GMT"
  76. if r.Header.Get("if-modified-since") == lm {
  77. w.WriteHeader(http.StatusNotModified)
  78. return
  79. }
  80. w.Header().Set("last-modified", lm)
  81. }))
  82. mux.HandleFunc("/varyaccept", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  83. w.Header().Set("Cache-Control", "max-age=3600")
  84. w.Header().Set("Content-Type", "text/plain")
  85. w.Header().Set("Vary", "Accept")
  86. w.Write([]byte("Some text content"))
  87. }))
  88. mux.HandleFunc("/doublevary", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  89. w.Header().Set("Cache-Control", "max-age=3600")
  90. w.Header().Set("Content-Type", "text/plain")
  91. w.Header().Set("Vary", "Accept, Accept-Language")
  92. w.Write([]byte("Some text content"))
  93. }))
  94. mux.HandleFunc("/2varyheaders", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  95. w.Header().Set("Cache-Control", "max-age=3600")
  96. w.Header().Set("Content-Type", "text/plain")
  97. w.Header().Add("Vary", "Accept")
  98. w.Header().Add("Vary", "Accept-Language")
  99. w.Write([]byte("Some text content"))
  100. }))
  101. mux.HandleFunc("/varyunused", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  102. w.Header().Set("Cache-Control", "max-age=3600")
  103. w.Header().Set("Content-Type", "text/plain")
  104. w.Header().Set("Vary", "X-Madeup-Header")
  105. w.Write([]byte("Some text content"))
  106. }))
  107. updateFieldsCounter := 0
  108. mux.HandleFunc("/updatefields", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  109. w.Header().Set("X-Counter", strconv.Itoa(updateFieldsCounter))
  110. w.Header().Set("Etag", `"e"`)
  111. updateFieldsCounter++
  112. if r.Header.Get("if-none-match") != "" {
  113. w.WriteHeader(http.StatusNotModified)
  114. return
  115. }
  116. w.Write([]byte("Some text content"))
  117. }))
  118. // Take 3 seconds to return 200 OK (for testing client timeouts).
  119. mux.HandleFunc("/3seconds", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  120. time.Sleep(3 * time.Second)
  121. }))
  122. mux.HandleFunc("/infinite", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  123. for {
  124. select {
  125. case <-s.done:
  126. return
  127. default:
  128. w.Write([]byte{0})
  129. }
  130. }
  131. }))
  132. }
  133. func teardown() {
  134. close(s.done)
  135. s.server.Close()
  136. }
  137. func resetTest() {
  138. s.transport.Cache = NewMemoryCache()
  139. clock = &realClock{}
  140. }
  141. // TestCacheableMethod ensures that uncacheable method does not get stored
  142. // in cache and get incorrectly used for a following cacheable method request.
  143. func TestCacheableMethod(t *testing.T) {
  144. resetTest()
  145. {
  146. req, err := http.NewRequest("POST", s.server.URL+"/method", nil)
  147. if err != nil {
  148. t.Fatal(err)
  149. }
  150. resp, err := s.client.Do(req)
  151. if err != nil {
  152. t.Fatal(err)
  153. }
  154. var buf bytes.Buffer
  155. _, err = io.Copy(&buf, resp.Body)
  156. if err != nil {
  157. t.Fatal(err)
  158. }
  159. err = resp.Body.Close()
  160. if err != nil {
  161. t.Fatal(err)
  162. }
  163. if got, want := buf.String(), "POST"; got != want {
  164. t.Errorf("got %q, want %q", got, want)
  165. }
  166. if resp.StatusCode != http.StatusOK {
  167. t.Errorf("response status code isn't 200 OK: %v", resp.StatusCode)
  168. }
  169. }
  170. {
  171. req, err := http.NewRequest("GET", s.server.URL+"/method", nil)
  172. if err != nil {
  173. t.Fatal(err)
  174. }
  175. resp, err := s.client.Do(req)
  176. if err != nil {
  177. t.Fatal(err)
  178. }
  179. var buf bytes.Buffer
  180. _, err = io.Copy(&buf, resp.Body)
  181. if err != nil {
  182. t.Fatal(err)
  183. }
  184. err = resp.Body.Close()
  185. if err != nil {
  186. t.Fatal(err)
  187. }
  188. if got, want := buf.String(), "GET"; got != want {
  189. t.Errorf("got wrong body %q, want %q", got, want)
  190. }
  191. if resp.StatusCode != http.StatusOK {
  192. t.Errorf("response status code isn't 200 OK: %v", resp.StatusCode)
  193. }
  194. if resp.Header.Get(XFromCache) != "" {
  195. t.Errorf("XFromCache header isn't blank")
  196. }
  197. }
  198. }
  199. func TestDontStorePartialRangeInCache(t *testing.T) {
  200. resetTest()
  201. {
  202. req, err := http.NewRequest("GET", s.server.URL+"/range", nil)
  203. if err != nil {
  204. t.Fatal(err)
  205. }
  206. req.Header.Set("range", "bytes=4-9")
  207. resp, err := s.client.Do(req)
  208. if err != nil {
  209. t.Fatal(err)
  210. }
  211. var buf bytes.Buffer
  212. _, err = io.Copy(&buf, resp.Body)
  213. if err != nil {
  214. t.Fatal(err)
  215. }
  216. err = resp.Body.Close()
  217. if err != nil {
  218. t.Fatal(err)
  219. }
  220. if got, want := buf.String(), " text "; got != want {
  221. t.Errorf("got %q, want %q", got, want)
  222. }
  223. if resp.StatusCode != http.StatusPartialContent {
  224. t.Errorf("response status code isn't 206 Partial Content: %v", resp.StatusCode)
  225. }
  226. }
  227. {
  228. req, err := http.NewRequest("GET", s.server.URL+"/range", nil)
  229. if err != nil {
  230. t.Fatal(err)
  231. }
  232. resp, err := s.client.Do(req)
  233. if err != nil {
  234. t.Fatal(err)
  235. }
  236. var buf bytes.Buffer
  237. _, err = io.Copy(&buf, resp.Body)
  238. if err != nil {
  239. t.Fatal(err)
  240. }
  241. err = resp.Body.Close()
  242. if err != nil {
  243. t.Fatal(err)
  244. }
  245. if got, want := buf.String(), "Some text content"; got != want {
  246. t.Errorf("got %q, want %q", got, want)
  247. }
  248. if resp.StatusCode != http.StatusOK {
  249. t.Errorf("response status code isn't 200 OK: %v", resp.StatusCode)
  250. }
  251. if resp.Header.Get(XFromCache) != "" {
  252. t.Error("XFromCache header isn't blank")
  253. }
  254. }
  255. {
  256. req, err := http.NewRequest("GET", s.server.URL+"/range", nil)
  257. if err != nil {
  258. t.Fatal(err)
  259. }
  260. resp, err := s.client.Do(req)
  261. if err != nil {
  262. t.Fatal(err)
  263. }
  264. var buf bytes.Buffer
  265. _, err = io.Copy(&buf, resp.Body)
  266. if err != nil {
  267. t.Fatal(err)
  268. }
  269. err = resp.Body.Close()
  270. if err != nil {
  271. t.Fatal(err)
  272. }
  273. if got, want := buf.String(), "Some text content"; got != want {
  274. t.Errorf("got %q, want %q", got, want)
  275. }
  276. if resp.StatusCode != http.StatusOK {
  277. t.Errorf("response status code isn't 200 OK: %v", resp.StatusCode)
  278. }
  279. if resp.Header.Get(XFromCache) != "1" {
  280. t.Errorf(`XFromCache header isn't "1": %v`, resp.Header.Get(XFromCache))
  281. }
  282. }
  283. {
  284. req, err := http.NewRequest("GET", s.server.URL+"/range", nil)
  285. if err != nil {
  286. t.Fatal(err)
  287. }
  288. req.Header.Set("range", "bytes=4-9")
  289. resp, err := s.client.Do(req)
  290. if err != nil {
  291. t.Fatal(err)
  292. }
  293. var buf bytes.Buffer
  294. _, err = io.Copy(&buf, resp.Body)
  295. if err != nil {
  296. t.Fatal(err)
  297. }
  298. err = resp.Body.Close()
  299. if err != nil {
  300. t.Fatal(err)
  301. }
  302. if got, want := buf.String(), " text "; got != want {
  303. t.Errorf("got %q, want %q", got, want)
  304. }
  305. if resp.StatusCode != http.StatusPartialContent {
  306. t.Errorf("response status code isn't 206 Partial Content: %v", resp.StatusCode)
  307. }
  308. }
  309. }
  310. func TestCacheOnlyIfBodyRead(t *testing.T) {
  311. resetTest()
  312. {
  313. req, err := http.NewRequest("GET", s.server.URL, nil)
  314. if err != nil {
  315. t.Fatal(err)
  316. }
  317. resp, err := s.client.Do(req)
  318. if err != nil {
  319. t.Fatal(err)
  320. }
  321. if resp.Header.Get(XFromCache) != "" {
  322. t.Fatal("XFromCache header isn't blank")
  323. }
  324. // We do not read the body
  325. resp.Body.Close()
  326. }
  327. {
  328. req, err := http.NewRequest("GET", s.server.URL, nil)
  329. if err != nil {
  330. t.Fatal(err)
  331. }
  332. resp, err := s.client.Do(req)
  333. if err != nil {
  334. t.Fatal(err)
  335. }
  336. defer resp.Body.Close()
  337. if resp.Header.Get(XFromCache) != "" {
  338. t.Fatalf("XFromCache header isn't blank")
  339. }
  340. }
  341. }
  342. func TestOnlyReadBodyOnDemand(t *testing.T) {
  343. resetTest()
  344. req, err := http.NewRequest("GET", s.server.URL+"/infinite", nil)
  345. if err != nil {
  346. t.Fatal(err)
  347. }
  348. resp, err := s.client.Do(req) // This shouldn't hang forever.
  349. if err != nil {
  350. t.Fatal(err)
  351. }
  352. buf := make([]byte, 10) // Only partially read the body.
  353. _, err = resp.Body.Read(buf)
  354. if err != nil {
  355. t.Fatal(err)
  356. }
  357. resp.Body.Close()
  358. }
  359. func TestGetOnlyIfCachedHit(t *testing.T) {
  360. resetTest()
  361. {
  362. req, err := http.NewRequest("GET", s.server.URL, nil)
  363. if err != nil {
  364. t.Fatal(err)
  365. }
  366. resp, err := s.client.Do(req)
  367. if err != nil {
  368. t.Fatal(err)
  369. }
  370. defer resp.Body.Close()
  371. if resp.Header.Get(XFromCache) != "" {
  372. t.Fatal("XFromCache header isn't blank")
  373. }
  374. _, err = ioutil.ReadAll(resp.Body)
  375. if err != nil {
  376. t.Fatal(err)
  377. }
  378. }
  379. {
  380. req, err := http.NewRequest("GET", s.server.URL, nil)
  381. if err != nil {
  382. t.Fatal(err)
  383. }
  384. req.Header.Add("cache-control", "only-if-cached")
  385. resp, err := s.client.Do(req)
  386. if err != nil {
  387. t.Fatal(err)
  388. }
  389. defer resp.Body.Close()
  390. if resp.Header.Get(XFromCache) != "1" {
  391. t.Fatalf(`XFromCache header isn't "1": %v`, resp.Header.Get(XFromCache))
  392. }
  393. if resp.StatusCode != http.StatusOK {
  394. t.Fatalf("response status code isn't 200 OK: %v", resp.StatusCode)
  395. }
  396. }
  397. }
  398. func TestGetOnlyIfCachedMiss(t *testing.T) {
  399. resetTest()
  400. req, err := http.NewRequest("GET", s.server.URL, nil)
  401. if err != nil {
  402. t.Fatal(err)
  403. }
  404. req.Header.Add("cache-control", "only-if-cached")
  405. resp, err := s.client.Do(req)
  406. if err != nil {
  407. t.Fatal(err)
  408. }
  409. defer resp.Body.Close()
  410. if resp.Header.Get(XFromCache) != "" {
  411. t.Fatal("XFromCache header isn't blank")
  412. }
  413. if resp.StatusCode != http.StatusGatewayTimeout {
  414. t.Fatalf("response status code isn't 504 GatewayTimeout: %v", resp.StatusCode)
  415. }
  416. }
  417. func TestGetNoStoreRequest(t *testing.T) {
  418. resetTest()
  419. req, err := http.NewRequest("GET", s.server.URL, nil)
  420. if err != nil {
  421. t.Fatal(err)
  422. }
  423. req.Header.Add("Cache-Control", "no-store")
  424. {
  425. resp, err := s.client.Do(req)
  426. if err != nil {
  427. t.Fatal(err)
  428. }
  429. defer resp.Body.Close()
  430. if resp.Header.Get(XFromCache) != "" {
  431. t.Fatal("XFromCache header isn't blank")
  432. }
  433. }
  434. {
  435. resp, err := s.client.Do(req)
  436. if err != nil {
  437. t.Fatal(err)
  438. }
  439. defer resp.Body.Close()
  440. if resp.Header.Get(XFromCache) != "" {
  441. t.Fatal("XFromCache header isn't blank")
  442. }
  443. }
  444. }
  445. func TestGetNoStoreResponse(t *testing.T) {
  446. resetTest()
  447. req, err := http.NewRequest("GET", s.server.URL+"/nostore", nil)
  448. if err != nil {
  449. t.Fatal(err)
  450. }
  451. {
  452. resp, err := s.client.Do(req)
  453. if err != nil {
  454. t.Fatal(err)
  455. }
  456. defer resp.Body.Close()
  457. if resp.Header.Get(XFromCache) != "" {
  458. t.Fatal("XFromCache header isn't blank")
  459. }
  460. }
  461. {
  462. resp, err := s.client.Do(req)
  463. if err != nil {
  464. t.Fatal(err)
  465. }
  466. defer resp.Body.Close()
  467. if resp.Header.Get(XFromCache) != "" {
  468. t.Fatal("XFromCache header isn't blank")
  469. }
  470. }
  471. }
  472. func TestGetWithEtag(t *testing.T) {
  473. resetTest()
  474. req, err := http.NewRequest("GET", s.server.URL+"/etag", nil)
  475. if err != nil {
  476. t.Fatal(err)
  477. }
  478. {
  479. resp, err := s.client.Do(req)
  480. if err != nil {
  481. t.Fatal(err)
  482. }
  483. defer resp.Body.Close()
  484. if resp.Header.Get(XFromCache) != "" {
  485. t.Fatal("XFromCache header isn't blank")
  486. }
  487. _, err = ioutil.ReadAll(resp.Body)
  488. if err != nil {
  489. t.Fatal(err)
  490. }
  491. }
  492. {
  493. resp, err := s.client.Do(req)
  494. if err != nil {
  495. t.Fatal(err)
  496. }
  497. defer resp.Body.Close()
  498. if resp.Header.Get(XFromCache) != "1" {
  499. t.Fatalf(`XFromCache header isn't "1": %v`, resp.Header.Get(XFromCache))
  500. }
  501. // additional assertions to verify that 304 response is converted properly
  502. if resp.StatusCode != http.StatusOK {
  503. t.Fatalf("response status code isn't 200 OK: %v", resp.StatusCode)
  504. }
  505. if _, ok := resp.Header["Connection"]; ok {
  506. t.Fatalf("Connection header isn't absent")
  507. }
  508. }
  509. }
  510. func TestGetWithLastModified(t *testing.T) {
  511. resetTest()
  512. req, err := http.NewRequest("GET", s.server.URL+"/lastmodified", nil)
  513. if err != nil {
  514. t.Fatal(err)
  515. }
  516. {
  517. resp, err := s.client.Do(req)
  518. if err != nil {
  519. t.Fatal(err)
  520. }
  521. defer resp.Body.Close()
  522. if resp.Header.Get(XFromCache) != "" {
  523. t.Fatal("XFromCache header isn't blank")
  524. }
  525. _, err = ioutil.ReadAll(resp.Body)
  526. if err != nil {
  527. t.Fatal(err)
  528. }
  529. }
  530. {
  531. resp, err := s.client.Do(req)
  532. if err != nil {
  533. t.Fatal(err)
  534. }
  535. defer resp.Body.Close()
  536. if resp.Header.Get(XFromCache) != "1" {
  537. t.Fatalf(`XFromCache header isn't "1": %v`, resp.Header.Get(XFromCache))
  538. }
  539. }
  540. }
  541. func TestGetWithVary(t *testing.T) {
  542. resetTest()
  543. req, err := http.NewRequest("GET", s.server.URL+"/varyaccept", nil)
  544. if err != nil {
  545. t.Fatal(err)
  546. }
  547. req.Header.Set("Accept", "text/plain")
  548. {
  549. resp, err := s.client.Do(req)
  550. if err != nil {
  551. t.Fatal(err)
  552. }
  553. defer resp.Body.Close()
  554. if resp.Header.Get("Vary") != "Accept" {
  555. t.Fatalf(`Vary header isn't "Accept": %v`, resp.Header.Get("Vary"))
  556. }
  557. _, err = ioutil.ReadAll(resp.Body)
  558. if err != nil {
  559. t.Fatal(err)
  560. }
  561. }
  562. {
  563. resp, err := s.client.Do(req)
  564. if err != nil {
  565. t.Fatal(err)
  566. }
  567. defer resp.Body.Close()
  568. if resp.Header.Get(XFromCache) != "1" {
  569. t.Fatalf(`XFromCache header isn't "1": %v`, resp.Header.Get(XFromCache))
  570. }
  571. }
  572. req.Header.Set("Accept", "text/html")
  573. {
  574. resp, err := s.client.Do(req)
  575. if err != nil {
  576. t.Fatal(err)
  577. }
  578. defer resp.Body.Close()
  579. if resp.Header.Get(XFromCache) != "" {
  580. t.Fatal("XFromCache header isn't blank")
  581. }
  582. }
  583. req.Header.Set("Accept", "")
  584. {
  585. resp, err := s.client.Do(req)
  586. if err != nil {
  587. t.Fatal(err)
  588. }
  589. defer resp.Body.Close()
  590. if resp.Header.Get(XFromCache) != "" {
  591. t.Fatal("XFromCache header isn't blank")
  592. }
  593. }
  594. }
  595. func TestGetWithDoubleVary(t *testing.T) {
  596. resetTest()
  597. req, err := http.NewRequest("GET", s.server.URL+"/doublevary", nil)
  598. if err != nil {
  599. t.Fatal(err)
  600. }
  601. req.Header.Set("Accept", "text/plain")
  602. req.Header.Set("Accept-Language", "da, en-gb;q=0.8, en;q=0.7")
  603. {
  604. resp, err := s.client.Do(req)
  605. if err != nil {
  606. t.Fatal(err)
  607. }
  608. defer resp.Body.Close()
  609. if resp.Header.Get("Vary") == "" {
  610. t.Fatalf(`Vary header is blank`)
  611. }
  612. _, err = ioutil.ReadAll(resp.Body)
  613. if err != nil {
  614. t.Fatal(err)
  615. }
  616. }
  617. {
  618. resp, err := s.client.Do(req)
  619. if err != nil {
  620. t.Fatal(err)
  621. }
  622. defer resp.Body.Close()
  623. if resp.Header.Get(XFromCache) != "1" {
  624. t.Fatalf(`XFromCache header isn't "1": %v`, resp.Header.Get(XFromCache))
  625. }
  626. }
  627. req.Header.Set("Accept-Language", "")
  628. {
  629. resp, err := s.client.Do(req)
  630. if err != nil {
  631. t.Fatal(err)
  632. }
  633. defer resp.Body.Close()
  634. if resp.Header.Get(XFromCache) != "" {
  635. t.Fatal("XFromCache header isn't blank")
  636. }
  637. }
  638. req.Header.Set("Accept-Language", "da")
  639. {
  640. resp, err := s.client.Do(req)
  641. if err != nil {
  642. t.Fatal(err)
  643. }
  644. defer resp.Body.Close()
  645. if resp.Header.Get(XFromCache) != "" {
  646. t.Fatal("XFromCache header isn't blank")
  647. }
  648. }
  649. }
  650. func TestGetWith2VaryHeaders(t *testing.T) {
  651. resetTest()
  652. // Tests that multiple Vary headers' comma-separated lists are
  653. // merged. See https://github.com/gregjones/httpcache/issues/27.
  654. const (
  655. accept = "text/plain"
  656. acceptLanguage = "da, en-gb;q=0.8, en;q=0.7"
  657. )
  658. req, err := http.NewRequest("GET", s.server.URL+"/2varyheaders", nil)
  659. if err != nil {
  660. t.Fatal(err)
  661. }
  662. req.Header.Set("Accept", accept)
  663. req.Header.Set("Accept-Language", acceptLanguage)
  664. {
  665. resp, err := s.client.Do(req)
  666. if err != nil {
  667. t.Fatal(err)
  668. }
  669. defer resp.Body.Close()
  670. if resp.Header.Get("Vary") == "" {
  671. t.Fatalf(`Vary header is blank`)
  672. }
  673. _, err = ioutil.ReadAll(resp.Body)
  674. if err != nil {
  675. t.Fatal(err)
  676. }
  677. }
  678. {
  679. resp, err := s.client.Do(req)
  680. if err != nil {
  681. t.Fatal(err)
  682. }
  683. defer resp.Body.Close()
  684. if resp.Header.Get(XFromCache) != "1" {
  685. t.Fatalf(`XFromCache header isn't "1": %v`, resp.Header.Get(XFromCache))
  686. }
  687. }
  688. req.Header.Set("Accept-Language", "")
  689. {
  690. resp, err := s.client.Do(req)
  691. if err != nil {
  692. t.Fatal(err)
  693. }
  694. defer resp.Body.Close()
  695. if resp.Header.Get(XFromCache) != "" {
  696. t.Fatal("XFromCache header isn't blank")
  697. }
  698. }
  699. req.Header.Set("Accept-Language", "da")
  700. {
  701. resp, err := s.client.Do(req)
  702. if err != nil {
  703. t.Fatal(err)
  704. }
  705. defer resp.Body.Close()
  706. if resp.Header.Get(XFromCache) != "" {
  707. t.Fatal("XFromCache header isn't blank")
  708. }
  709. }
  710. req.Header.Set("Accept-Language", acceptLanguage)
  711. req.Header.Set("Accept", "")
  712. {
  713. resp, err := s.client.Do(req)
  714. if err != nil {
  715. t.Fatal(err)
  716. }
  717. defer resp.Body.Close()
  718. if resp.Header.Get(XFromCache) != "" {
  719. t.Fatal("XFromCache header isn't blank")
  720. }
  721. }
  722. req.Header.Set("Accept", "image/png")
  723. {
  724. resp, err := s.client.Do(req)
  725. if err != nil {
  726. t.Fatal(err)
  727. }
  728. defer resp.Body.Close()
  729. if resp.Header.Get(XFromCache) != "" {
  730. t.Fatal("XFromCache header isn't blank")
  731. }
  732. _, err = ioutil.ReadAll(resp.Body)
  733. if err != nil {
  734. t.Fatal(err)
  735. }
  736. }
  737. {
  738. resp, err := s.client.Do(req)
  739. if err != nil {
  740. t.Fatal(err)
  741. }
  742. defer resp.Body.Close()
  743. if resp.Header.Get(XFromCache) != "1" {
  744. t.Fatalf(`XFromCache header isn't "1": %v`, resp.Header.Get(XFromCache))
  745. }
  746. }
  747. }
  748. func TestGetVaryUnused(t *testing.T) {
  749. resetTest()
  750. req, err := http.NewRequest("GET", s.server.URL+"/varyunused", nil)
  751. if err != nil {
  752. t.Fatal(err)
  753. }
  754. req.Header.Set("Accept", "text/plain")
  755. {
  756. resp, err := s.client.Do(req)
  757. if err != nil {
  758. t.Fatal(err)
  759. }
  760. defer resp.Body.Close()
  761. if resp.Header.Get("Vary") == "" {
  762. t.Fatalf(`Vary header is blank`)
  763. }
  764. _, err = ioutil.ReadAll(resp.Body)
  765. if err != nil {
  766. t.Fatal(err)
  767. }
  768. }
  769. {
  770. resp, err := s.client.Do(req)
  771. if err != nil {
  772. t.Fatal(err)
  773. }
  774. defer resp.Body.Close()
  775. if resp.Header.Get(XFromCache) != "1" {
  776. t.Fatalf(`XFromCache header isn't "1": %v`, resp.Header.Get(XFromCache))
  777. }
  778. }
  779. }
  780. func TestUpdateFields(t *testing.T) {
  781. resetTest()
  782. req, err := http.NewRequest("GET", s.server.URL+"/updatefields", nil)
  783. if err != nil {
  784. t.Fatal(err)
  785. }
  786. var counter, counter2 string
  787. {
  788. resp, err := s.client.Do(req)
  789. if err != nil {
  790. t.Fatal(err)
  791. }
  792. defer resp.Body.Close()
  793. counter = resp.Header.Get("x-counter")
  794. _, err = ioutil.ReadAll(resp.Body)
  795. if err != nil {
  796. t.Fatal(err)
  797. }
  798. }
  799. {
  800. resp, err := s.client.Do(req)
  801. if err != nil {
  802. t.Fatal(err)
  803. }
  804. defer resp.Body.Close()
  805. if resp.Header.Get(XFromCache) != "1" {
  806. t.Fatalf(`XFromCache header isn't "1": %v`, resp.Header.Get(XFromCache))
  807. }
  808. counter2 = resp.Header.Get("x-counter")
  809. }
  810. if counter == counter2 {
  811. t.Fatalf(`both "x-counter" values are equal: %v %v`, counter, counter2)
  812. }
  813. }
  814. func TestParseCacheControl(t *testing.T) {
  815. resetTest()
  816. h := http.Header{}
  817. for range parseCacheControl(h) {
  818. t.Fatal("cacheControl should be empty")
  819. }
  820. h.Set("cache-control", "no-cache")
  821. {
  822. cc := parseCacheControl(h)
  823. if _, ok := cc["foo"]; ok {
  824. t.Error(`Value "foo" shouldn't exist`)
  825. }
  826. noCache, ok := cc["no-cache"]
  827. if !ok {
  828. t.Fatalf(`"no-cache" value isn't set`)
  829. }
  830. if noCache != "" {
  831. t.Fatalf(`"no-cache" value isn't blank: %v`, noCache)
  832. }
  833. }
  834. h.Set("cache-control", "no-cache, max-age=3600")
  835. {
  836. cc := parseCacheControl(h)
  837. noCache, ok := cc["no-cache"]
  838. if !ok {
  839. t.Fatalf(`"no-cache" value isn't set`)
  840. }
  841. if noCache != "" {
  842. t.Fatalf(`"no-cache" value isn't blank: %v`, noCache)
  843. }
  844. if cc["max-age"] != "3600" {
  845. t.Fatalf(`"max-age" value isn't "3600": %v`, cc["max-age"])
  846. }
  847. }
  848. }
  849. func TestNoCacheRequestExpiration(t *testing.T) {
  850. resetTest()
  851. respHeaders := http.Header{}
  852. respHeaders.Set("Cache-Control", "max-age=7200")
  853. reqHeaders := http.Header{}
  854. reqHeaders.Set("Cache-Control", "no-cache")
  855. if getFreshness(respHeaders, reqHeaders) != transparent {
  856. t.Fatal("freshness isn't transparent")
  857. }
  858. }
  859. func TestNoCacheResponseExpiration(t *testing.T) {
  860. resetTest()
  861. respHeaders := http.Header{}
  862. respHeaders.Set("Cache-Control", "no-cache")
  863. respHeaders.Set("Expires", "Wed, 19 Apr 3000 11:43:00 GMT")
  864. reqHeaders := http.Header{}
  865. if getFreshness(respHeaders, reqHeaders) != stale {
  866. t.Fatal("freshness isn't stale")
  867. }
  868. }
  869. func TestReqMustRevalidate(t *testing.T) {
  870. resetTest()
  871. // not paying attention to request setting max-stale means never returning stale
  872. // responses, so always acting as if must-revalidate is set
  873. respHeaders := http.Header{}
  874. reqHeaders := http.Header{}
  875. reqHeaders.Set("Cache-Control", "must-revalidate")
  876. if getFreshness(respHeaders, reqHeaders) != stale {
  877. t.Fatal("freshness isn't stale")
  878. }
  879. }
  880. func TestRespMustRevalidate(t *testing.T) {
  881. resetTest()
  882. respHeaders := http.Header{}
  883. respHeaders.Set("Cache-Control", "must-revalidate")
  884. reqHeaders := http.Header{}
  885. if getFreshness(respHeaders, reqHeaders) != stale {
  886. t.Fatal("freshness isn't stale")
  887. }
  888. }
  889. func TestFreshExpiration(t *testing.T) {
  890. resetTest()
  891. now := time.Now()
  892. respHeaders := http.Header{}
  893. respHeaders.Set("date", now.Format(time.RFC1123))
  894. respHeaders.Set("expires", now.Add(time.Duration(2)*time.Second).Format(time.RFC1123))
  895. reqHeaders := http.Header{}
  896. if getFreshness(respHeaders, reqHeaders) != fresh {
  897. t.Fatal("freshness isn't fresh")
  898. }
  899. clock = &fakeClock{elapsed: 3 * time.Second}
  900. if getFreshness(respHeaders, reqHeaders) != stale {
  901. t.Fatal("freshness isn't stale")
  902. }
  903. }
  904. func TestMaxAge(t *testing.T) {
  905. resetTest()
  906. now := time.Now()
  907. respHeaders := http.Header{}
  908. respHeaders.Set("date", now.Format(time.RFC1123))
  909. respHeaders.Set("cache-control", "max-age=2")
  910. reqHeaders := http.Header{}
  911. if getFreshness(respHeaders, reqHeaders) != fresh {
  912. t.Fatal("freshness isn't fresh")
  913. }
  914. clock = &fakeClock{elapsed: 3 * time.Second}
  915. if getFreshness(respHeaders, reqHeaders) != stale {
  916. t.Fatal("freshness isn't stale")
  917. }
  918. }
  919. func TestMaxAgeZero(t *testing.T) {
  920. resetTest()
  921. now := time.Now()
  922. respHeaders := http.Header{}
  923. respHeaders.Set("date", now.Format(time.RFC1123))
  924. respHeaders.Set("cache-control", "max-age=0")
  925. reqHeaders := http.Header{}
  926. if getFreshness(respHeaders, reqHeaders) != stale {
  927. t.Fatal("freshness isn't stale")
  928. }
  929. }
  930. func TestBothMaxAge(t *testing.T) {
  931. resetTest()
  932. now := time.Now()
  933. respHeaders := http.Header{}
  934. respHeaders.Set("date", now.Format(time.RFC1123))
  935. respHeaders.Set("cache-control", "max-age=2")
  936. reqHeaders := http.Header{}
  937. reqHeaders.Set("cache-control", "max-age=0")
  938. if getFreshness(respHeaders, reqHeaders) != stale {
  939. t.Fatal("freshness isn't stale")
  940. }
  941. }
  942. func TestMinFreshWithExpires(t *testing.T) {
  943. resetTest()
  944. now := time.Now()
  945. respHeaders := http.Header{}
  946. respHeaders.Set("date", now.Format(time.RFC1123))
  947. respHeaders.Set("expires", now.Add(time.Duration(2)*time.Second).Format(time.RFC1123))
  948. reqHeaders := http.Header{}
  949. reqHeaders.Set("cache-control", "min-fresh=1")
  950. if getFreshness(respHeaders, reqHeaders) != fresh {
  951. t.Fatal("freshness isn't fresh")
  952. }
  953. reqHeaders = http.Header{}
  954. reqHeaders.Set("cache-control", "min-fresh=2")
  955. if getFreshness(respHeaders, reqHeaders) != stale {
  956. t.Fatal("freshness isn't stale")
  957. }
  958. }
  959. func TestEmptyMaxStale(t *testing.T) {
  960. resetTest()
  961. now := time.Now()
  962. respHeaders := http.Header{}
  963. respHeaders.Set("date", now.Format(time.RFC1123))
  964. respHeaders.Set("cache-control", "max-age=20")
  965. reqHeaders := http.Header{}
  966. reqHeaders.Set("cache-control", "max-stale")
  967. clock = &fakeClock{elapsed: 10 * time.Second}
  968. if getFreshness(respHeaders, reqHeaders) != fresh {
  969. t.Fatal("freshness isn't fresh")
  970. }
  971. clock = &fakeClock{elapsed: 60 * time.Second}
  972. if getFreshness(respHeaders, reqHeaders) != fresh {
  973. t.Fatal("freshness isn't fresh")
  974. }
  975. }
  976. func TestMaxStaleValue(t *testing.T) {
  977. resetTest()
  978. now := time.Now()
  979. respHeaders := http.Header{}
  980. respHeaders.Set("date", now.Format(time.RFC1123))
  981. respHeaders.Set("cache-control", "max-age=10")
  982. reqHeaders := http.Header{}
  983. reqHeaders.Set("cache-control", "max-stale=20")
  984. clock = &fakeClock{elapsed: 5 * time.Second}
  985. if getFreshness(respHeaders, reqHeaders) != fresh {
  986. t.Fatal("freshness isn't fresh")
  987. }
  988. clock = &fakeClock{elapsed: 15 * time.Second}
  989. if getFreshness(respHeaders, reqHeaders) != fresh {
  990. t.Fatal("freshness isn't fresh")
  991. }
  992. clock = &fakeClock{elapsed: 30 * time.Second}
  993. if getFreshness(respHeaders, reqHeaders) != stale {
  994. t.Fatal("freshness isn't stale")
  995. }
  996. }
  997. func containsHeader(headers []string, header string) bool {
  998. for _, v := range headers {
  999. if http.CanonicalHeaderKey(v) == http.CanonicalHeaderKey(header) {
  1000. return true
  1001. }
  1002. }
  1003. return false
  1004. }
  1005. func TestGetEndToEndHeaders(t *testing.T) {
  1006. resetTest()
  1007. var (
  1008. headers http.Header
  1009. end2end []string
  1010. )
  1011. headers = http.Header{}
  1012. headers.Set("content-type", "text/html")
  1013. headers.Set("te", "deflate")
  1014. end2end = getEndToEndHeaders(headers)
  1015. if !containsHeader(end2end, "content-type") {
  1016. t.Fatal(`doesn't contain "content-type" header`)
  1017. }
  1018. if containsHeader(end2end, "te") {
  1019. t.Fatal(`doesn't contain "te" header`)
  1020. }
  1021. headers = http.Header{}
  1022. headers.Set("connection", "content-type")
  1023. headers.Set("content-type", "text/csv")
  1024. headers.Set("te", "deflate")
  1025. end2end = getEndToEndHeaders(headers)
  1026. if containsHeader(end2end, "connection") {
  1027. t.Fatal(`doesn't contain "connection" header`)
  1028. }
  1029. if containsHeader(end2end, "content-type") {
  1030. t.Fatal(`doesn't contain "content-type" header`)
  1031. }
  1032. if containsHeader(end2end, "te") {
  1033. t.Fatal(`doesn't contain "te" header`)
  1034. }
  1035. headers = http.Header{}
  1036. end2end = getEndToEndHeaders(headers)
  1037. if len(end2end) != 0 {
  1038. t.Fatal(`non-zero end2end headers`)
  1039. }
  1040. headers = http.Header{}
  1041. headers.Set("connection", "content-type")
  1042. end2end = getEndToEndHeaders(headers)
  1043. if len(end2end) != 0 {
  1044. t.Fatal(`non-zero end2end headers`)
  1045. }
  1046. }
  1047. type transportMock struct {
  1048. response *http.Response
  1049. err error
  1050. }
  1051. func (t transportMock) RoundTrip(req *http.Request) (resp *http.Response, err error) {
  1052. return t.response, t.err
  1053. }
  1054. func TestStaleIfErrorRequest(t *testing.T) {
  1055. resetTest()
  1056. now := time.Now()
  1057. tmock := transportMock{
  1058. response: &http.Response{
  1059. Status: http.StatusText(http.StatusOK),
  1060. StatusCode: http.StatusOK,
  1061. Header: http.Header{
  1062. "Date": []string{now.Format(time.RFC1123)},
  1063. "Cache-Control": []string{"no-cache"},
  1064. },
  1065. Body: ioutil.NopCloser(bytes.NewBuffer([]byte("some data"))),
  1066. },
  1067. err: nil,
  1068. }
  1069. tp := NewMemoryCacheTransport()
  1070. tp.Transport = &tmock
  1071. // First time, response is cached on success
  1072. r, _ := http.NewRequest("GET", "http://somewhere.com/", nil)
  1073. r.Header.Set("Cache-Control", "stale-if-error")
  1074. resp, err := tp.RoundTrip(r)
  1075. if err != nil {
  1076. t.Fatal(err)
  1077. }
  1078. if resp == nil {
  1079. t.Fatal("resp is nil")
  1080. }
  1081. _, err = ioutil.ReadAll(resp.Body)
  1082. if err != nil {
  1083. t.Fatal(err)
  1084. }
  1085. // On failure, response is returned from the cache
  1086. tmock.response = nil
  1087. tmock.err = errors.New("some error")
  1088. resp, err = tp.RoundTrip(r)
  1089. if err != nil {
  1090. t.Fatal(err)
  1091. }
  1092. if resp == nil {
  1093. t.Fatal("resp is nil")
  1094. }
  1095. }
  1096. func TestStaleIfErrorRequestLifetime(t *testing.T) {
  1097. resetTest()
  1098. now := time.Now()
  1099. tmock := transportMock{
  1100. response: &http.Response{
  1101. Status: http.StatusText(http.StatusOK),
  1102. StatusCode: http.StatusOK,
  1103. Header: http.Header{
  1104. "Date": []string{now.Format(time.RFC1123)},
  1105. "Cache-Control": []string{"no-cache"},
  1106. },
  1107. Body: ioutil.NopCloser(bytes.NewBuffer([]byte("some data"))),
  1108. },
  1109. err: nil,
  1110. }
  1111. tp := NewMemoryCacheTransport()
  1112. tp.Transport = &tmock
  1113. // First time, response is cached on success
  1114. r, _ := http.NewRequest("GET", "http://somewhere.com/", nil)
  1115. r.Header.Set("Cache-Control", "stale-if-error=100")
  1116. resp, err := tp.RoundTrip(r)
  1117. if err != nil {
  1118. t.Fatal(err)
  1119. }
  1120. if resp == nil {
  1121. t.Fatal("resp is nil")
  1122. }
  1123. _, err = ioutil.ReadAll(resp.Body)
  1124. if err != nil {
  1125. t.Fatal(err)
  1126. }
  1127. // On failure, response is returned from the cache
  1128. tmock.response = nil
  1129. tmock.err = errors.New("some error")
  1130. resp, err = tp.RoundTrip(r)
  1131. if err != nil {
  1132. t.Fatal(err)
  1133. }
  1134. if resp == nil {
  1135. t.Fatal("resp is nil")
  1136. }
  1137. // Same for http errors
  1138. tmock.response = &http.Response{StatusCode: http.StatusInternalServerError}
  1139. tmock.err = nil
  1140. resp, err = tp.RoundTrip(r)
  1141. if err != nil {
  1142. t.Fatal(err)
  1143. }
  1144. if resp == nil {
  1145. t.Fatal("resp is nil")
  1146. }
  1147. // If failure last more than max stale, error is returned
  1148. clock = &fakeClock{elapsed: 200 * time.Second}
  1149. _, err = tp.RoundTrip(r)
  1150. if err != tmock.err {
  1151. t.Fatalf("got err %v, want %v", err, tmock.err)
  1152. }
  1153. }
  1154. func TestStaleIfErrorResponse(t *testing.T) {
  1155. resetTest()
  1156. now := time.Now()
  1157. tmock := transportMock{
  1158. response: &http.Response{
  1159. Status: http.StatusText(http.StatusOK),
  1160. StatusCode: http.StatusOK,
  1161. Header: http.Header{
  1162. "Date": []string{now.Format(time.RFC1123)},
  1163. "Cache-Control": []string{"no-cache, stale-if-error"},
  1164. },
  1165. Body: ioutil.NopCloser(bytes.NewBuffer([]byte("some data"))),
  1166. },
  1167. err: nil,
  1168. }
  1169. tp := NewMemoryCacheTransport()
  1170. tp.Transport = &tmock
  1171. // First time, response is cached on success
  1172. r, _ := http.NewRequest("GET", "http://somewhere.com/", nil)
  1173. resp, err := tp.RoundTrip(r)
  1174. if err != nil {
  1175. t.Fatal(err)
  1176. }
  1177. if resp == nil {
  1178. t.Fatal("resp is nil")
  1179. }
  1180. _, err = ioutil.ReadAll(resp.Body)
  1181. if err != nil {
  1182. t.Fatal(err)
  1183. }
  1184. // On failure, response is returned from the cache
  1185. tmock.response = nil
  1186. tmock.err = errors.New("some error")
  1187. resp, err = tp.RoundTrip(r)
  1188. if err != nil {
  1189. t.Fatal(err)
  1190. }
  1191. if resp == nil {
  1192. t.Fatal("resp is nil")
  1193. }
  1194. }
  1195. func TestStaleIfErrorResponseLifetime(t *testing.T) {
  1196. resetTest()
  1197. now := time.Now()
  1198. tmock := transportMock{
  1199. response: &http.Response{
  1200. Status: http.StatusText(http.StatusOK),
  1201. StatusCode: http.StatusOK,
  1202. Header: http.Header{
  1203. "Date": []string{now.Format(time.RFC1123)},
  1204. "Cache-Control": []string{"no-cache, stale-if-error=100"},
  1205. },
  1206. Body: ioutil.NopCloser(bytes.NewBuffer([]byte("some data"))),
  1207. },
  1208. err: nil,
  1209. }
  1210. tp := NewMemoryCacheTransport()
  1211. tp.Transport = &tmock
  1212. // First time, response is cached on success
  1213. r, _ := http.NewRequest("GET", "http://somewhere.com/", nil)
  1214. resp, err := tp.RoundTrip(r)
  1215. if err != nil {
  1216. t.Fatal(err)
  1217. }
  1218. if resp == nil {
  1219. t.Fatal("resp is nil")
  1220. }
  1221. _, err = ioutil.ReadAll(resp.Body)
  1222. if err != nil {
  1223. t.Fatal(err)
  1224. }
  1225. // On failure, response is returned from the cache
  1226. tmock.response = nil
  1227. tmock.err = errors.New("some error")
  1228. resp, err = tp.RoundTrip(r)
  1229. if err != nil {
  1230. t.Fatal(err)
  1231. }
  1232. if resp == nil {
  1233. t.Fatal("resp is nil")
  1234. }
  1235. // If failure last more than max stale, error is returned
  1236. clock = &fakeClock{elapsed: 200 * time.Second}
  1237. _, err = tp.RoundTrip(r)
  1238. if err != tmock.err {
  1239. t.Fatalf("got err %v, want %v", err, tmock.err)
  1240. }
  1241. }
  1242. // Test that http.Client.Timeout is respected when cache transport is used.
  1243. // That is so as long as request cancellation is propagated correctly.
  1244. // In the past, that required CancelRequest to be implemented correctly,
  1245. // but modern http.Client uses Request.Cancel (or request context) instead,
  1246. // so we don't have to do anything.
  1247. func TestClientTimeout(t *testing.T) {
  1248. if testing.Short() {
  1249. t.Skip("skipping timeout test in short mode") // Because it takes at least 3 seconds to run.
  1250. }
  1251. resetTest()
  1252. client := &http.Client{
  1253. Transport: NewMemoryCacheTransport(),
  1254. Timeout: time.Second,
  1255. }
  1256. started := time.Now()
  1257. resp, err := client.Get(s.server.URL + "/3seconds")
  1258. taken := time.Since(started)
  1259. if err == nil {
  1260. t.Error("got nil error, want timeout error")
  1261. }
  1262. if resp != nil {
  1263. t.Error("got non-nil resp, want nil resp")
  1264. }
  1265. if taken >= 2*time.Second {
  1266. t.Error("client.Do took 2+ seconds, want < 2 seconds")
  1267. }
  1268. }