githubapi_test.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
  2. // Use of this source code is governed by a MIT style
  3. // license that can be found in the LICENSE file.
  4. package gin
  5. import (
  6. "bytes"
  7. "fmt"
  8. "math/rand"
  9. "net/http"
  10. "net/http/httptest"
  11. "os"
  12. "testing"
  13. "github.com/stretchr/testify/assert"
  14. )
  15. type route struct {
  16. method string
  17. path string
  18. }
  19. // http://developer.github.com/v3/
  20. var githubAPI = []route{
  21. // OAuth Authorizations
  22. {http.MethodGet, "/authorizations"},
  23. {http.MethodGet, "/authorizations/:id"},
  24. {http.MethodPost, "/authorizations"},
  25. //{http.MethodPut, "/authorizations/clients/:client_id"},
  26. //{http.MethodPatch, "/authorizations/:id"},
  27. {http.MethodDelete, "/authorizations/:id"},
  28. {http.MethodGet, "/applications/:client_id/tokens/:access_token"},
  29. {http.MethodDelete, "/applications/:client_id/tokens"},
  30. {http.MethodDelete, "/applications/:client_id/tokens/:access_token"},
  31. // Activity
  32. {http.MethodGet, "/events"},
  33. {http.MethodGet, "/repos/:owner/:repo/events"},
  34. {http.MethodGet, "/networks/:owner/:repo/events"},
  35. {http.MethodGet, "/orgs/:org/events"},
  36. {http.MethodGet, "/users/:user/received_events"},
  37. {http.MethodGet, "/users/:user/received_events/public"},
  38. {http.MethodGet, "/users/:user/events"},
  39. {http.MethodGet, "/users/:user/events/public"},
  40. {http.MethodGet, "/users/:user/events/orgs/:org"},
  41. {http.MethodGet, "/feeds"},
  42. {http.MethodGet, "/notifications"},
  43. {http.MethodGet, "/repos/:owner/:repo/notifications"},
  44. {http.MethodPut, "/notifications"},
  45. {http.MethodPut, "/repos/:owner/:repo/notifications"},
  46. {http.MethodGet, "/notifications/threads/:id"},
  47. //{http.MethodPatch, "/notifications/threads/:id"},
  48. {http.MethodGet, "/notifications/threads/:id/subscription"},
  49. {http.MethodPut, "/notifications/threads/:id/subscription"},
  50. {http.MethodDelete, "/notifications/threads/:id/subscription"},
  51. {http.MethodGet, "/repos/:owner/:repo/stargazers"},
  52. {http.MethodGet, "/users/:user/starred"},
  53. {http.MethodGet, "/user/starred"},
  54. {http.MethodGet, "/user/starred/:owner/:repo"},
  55. {http.MethodPut, "/user/starred/:owner/:repo"},
  56. {http.MethodDelete, "/user/starred/:owner/:repo"},
  57. {http.MethodGet, "/repos/:owner/:repo/subscribers"},
  58. {http.MethodGet, "/users/:user/subscriptions"},
  59. {http.MethodGet, "/user/subscriptions"},
  60. {http.MethodGet, "/repos/:owner/:repo/subscription"},
  61. {http.MethodPut, "/repos/:owner/:repo/subscription"},
  62. {http.MethodDelete, "/repos/:owner/:repo/subscription"},
  63. {http.MethodGet, "/user/subscriptions/:owner/:repo"},
  64. {http.MethodPut, "/user/subscriptions/:owner/:repo"},
  65. {http.MethodDelete, "/user/subscriptions/:owner/:repo"},
  66. // Gists
  67. {http.MethodGet, "/users/:user/gists"},
  68. {http.MethodGet, "/gists"},
  69. //{http.MethodGet, "/gists/public"},
  70. //{http.MethodGet, "/gists/starred"},
  71. {http.MethodGet, "/gists/:id"},
  72. {http.MethodPost, "/gists"},
  73. //{http.MethodPatch, "/gists/:id"},
  74. {http.MethodPut, "/gists/:id/star"},
  75. {http.MethodDelete, "/gists/:id/star"},
  76. {http.MethodGet, "/gists/:id/star"},
  77. {http.MethodPost, "/gists/:id/forks"},
  78. {http.MethodDelete, "/gists/:id"},
  79. // Git Data
  80. {http.MethodGet, "/repos/:owner/:repo/git/blobs/:sha"},
  81. {http.MethodPost, "/repos/:owner/:repo/git/blobs"},
  82. {http.MethodGet, "/repos/:owner/:repo/git/commits/:sha"},
  83. {http.MethodPost, "/repos/:owner/:repo/git/commits"},
  84. //{http.MethodGet, "/repos/:owner/:repo/git/refs/*ref"},
  85. {http.MethodGet, "/repos/:owner/:repo/git/refs"},
  86. {http.MethodPost, "/repos/:owner/:repo/git/refs"},
  87. //{http.MethodPatch, "/repos/:owner/:repo/git/refs/*ref"},
  88. //{http.MethodDelete, "/repos/:owner/:repo/git/refs/*ref"},
  89. {http.MethodGet, "/repos/:owner/:repo/git/tags/:sha"},
  90. {http.MethodPost, "/repos/:owner/:repo/git/tags"},
  91. {http.MethodGet, "/repos/:owner/:repo/git/trees/:sha"},
  92. {http.MethodPost, "/repos/:owner/:repo/git/trees"},
  93. // Issues
  94. {http.MethodGet, "/issues"},
  95. {http.MethodGet, "/user/issues"},
  96. {http.MethodGet, "/orgs/:org/issues"},
  97. {http.MethodGet, "/repos/:owner/:repo/issues"},
  98. {http.MethodGet, "/repos/:owner/:repo/issues/:number"},
  99. {http.MethodPost, "/repos/:owner/:repo/issues"},
  100. //{http.MethodPatch, "/repos/:owner/:repo/issues/:number"},
  101. {http.MethodGet, "/repos/:owner/:repo/assignees"},
  102. {http.MethodGet, "/repos/:owner/:repo/assignees/:assignee"},
  103. {http.MethodGet, "/repos/:owner/:repo/issues/:number/comments"},
  104. //{http.MethodGet, "/repos/:owner/:repo/issues/comments"},
  105. //{http.MethodGet, "/repos/:owner/:repo/issues/comments/:id"},
  106. {http.MethodPost, "/repos/:owner/:repo/issues/:number/comments"},
  107. //{http.MethodPatch, "/repos/:owner/:repo/issues/comments/:id"},
  108. //{http.MethodDelete, "/repos/:owner/:repo/issues/comments/:id"},
  109. {http.MethodGet, "/repos/:owner/:repo/issues/:number/events"},
  110. //{http.MethodGet, "/repos/:owner/:repo/issues/events"},
  111. //{http.MethodGet, "/repos/:owner/:repo/issues/events/:id"},
  112. {http.MethodGet, "/repos/:owner/:repo/labels"},
  113. {http.MethodGet, "/repos/:owner/:repo/labels/:name"},
  114. {http.MethodPost, "/repos/:owner/:repo/labels"},
  115. //{http.MethodPatch, "/repos/:owner/:repo/labels/:name"},
  116. {http.MethodDelete, "/repos/:owner/:repo/labels/:name"},
  117. {http.MethodGet, "/repos/:owner/:repo/issues/:number/labels"},
  118. {http.MethodPost, "/repos/:owner/:repo/issues/:number/labels"},
  119. {http.MethodDelete, "/repos/:owner/:repo/issues/:number/labels/:name"},
  120. {http.MethodPut, "/repos/:owner/:repo/issues/:number/labels"},
  121. {http.MethodDelete, "/repos/:owner/:repo/issues/:number/labels"},
  122. {http.MethodGet, "/repos/:owner/:repo/milestones/:number/labels"},
  123. {http.MethodGet, "/repos/:owner/:repo/milestones"},
  124. {http.MethodGet, "/repos/:owner/:repo/milestones/:number"},
  125. {http.MethodPost, "/repos/:owner/:repo/milestones"},
  126. //{http.MethodPatch, "/repos/:owner/:repo/milestones/:number"},
  127. {http.MethodDelete, "/repos/:owner/:repo/milestones/:number"},
  128. // Miscellaneous
  129. {http.MethodGet, "/emojis"},
  130. {http.MethodGet, "/gitignore/templates"},
  131. {http.MethodGet, "/gitignore/templates/:name"},
  132. {http.MethodPost, "/markdown"},
  133. {http.MethodPost, "/markdown/raw"},
  134. {http.MethodGet, "/meta"},
  135. {http.MethodGet, "/rate_limit"},
  136. // Organizations
  137. {http.MethodGet, "/users/:user/orgs"},
  138. {http.MethodGet, "/user/orgs"},
  139. {http.MethodGet, "/orgs/:org"},
  140. //{http.MethodPatch, "/orgs/:org"},
  141. {http.MethodGet, "/orgs/:org/members"},
  142. {http.MethodGet, "/orgs/:org/members/:user"},
  143. {http.MethodDelete, "/orgs/:org/members/:user"},
  144. {http.MethodGet, "/orgs/:org/public_members"},
  145. {http.MethodGet, "/orgs/:org/public_members/:user"},
  146. {http.MethodPut, "/orgs/:org/public_members/:user"},
  147. {http.MethodDelete, "/orgs/:org/public_members/:user"},
  148. {http.MethodGet, "/orgs/:org/teams"},
  149. {http.MethodGet, "/teams/:id"},
  150. {http.MethodPost, "/orgs/:org/teams"},
  151. //{http.MethodPatch, "/teams/:id"},
  152. {http.MethodDelete, "/teams/:id"},
  153. {http.MethodGet, "/teams/:id/members"},
  154. {http.MethodGet, "/teams/:id/members/:user"},
  155. {http.MethodPut, "/teams/:id/members/:user"},
  156. {http.MethodDelete, "/teams/:id/members/:user"},
  157. {http.MethodGet, "/teams/:id/repos"},
  158. {http.MethodGet, "/teams/:id/repos/:owner/:repo"},
  159. {http.MethodPut, "/teams/:id/repos/:owner/:repo"},
  160. {http.MethodDelete, "/teams/:id/repos/:owner/:repo"},
  161. {http.MethodGet, "/user/teams"},
  162. // Pull Requests
  163. {http.MethodGet, "/repos/:owner/:repo/pulls"},
  164. {http.MethodGet, "/repos/:owner/:repo/pulls/:number"},
  165. {http.MethodPost, "/repos/:owner/:repo/pulls"},
  166. //{http.MethodPatch, "/repos/:owner/:repo/pulls/:number"},
  167. {http.MethodGet, "/repos/:owner/:repo/pulls/:number/commits"},
  168. {http.MethodGet, "/repos/:owner/:repo/pulls/:number/files"},
  169. {http.MethodGet, "/repos/:owner/:repo/pulls/:number/merge"},
  170. {http.MethodPut, "/repos/:owner/:repo/pulls/:number/merge"},
  171. {http.MethodGet, "/repos/:owner/:repo/pulls/:number/comments"},
  172. //{http.MethodGet, "/repos/:owner/:repo/pulls/comments"},
  173. //{http.MethodGet, "/repos/:owner/:repo/pulls/comments/:number"},
  174. {http.MethodPut, "/repos/:owner/:repo/pulls/:number/comments"},
  175. //{http.MethodPatch, "/repos/:owner/:repo/pulls/comments/:number"},
  176. //{http.MethodDelete, "/repos/:owner/:repo/pulls/comments/:number"},
  177. // Repositories
  178. {http.MethodGet, "/user/repos"},
  179. {http.MethodGet, "/users/:user/repos"},
  180. {http.MethodGet, "/orgs/:org/repos"},
  181. {http.MethodGet, "/repositories"},
  182. {http.MethodPost, "/user/repos"},
  183. {http.MethodPost, "/orgs/:org/repos"},
  184. {http.MethodGet, "/repos/:owner/:repo"},
  185. //{http.MethodPatch, "/repos/:owner/:repo"},
  186. {http.MethodGet, "/repos/:owner/:repo/contributors"},
  187. {http.MethodGet, "/repos/:owner/:repo/languages"},
  188. {http.MethodGet, "/repos/:owner/:repo/teams"},
  189. {http.MethodGet, "/repos/:owner/:repo/tags"},
  190. {http.MethodGet, "/repos/:owner/:repo/branches"},
  191. {http.MethodGet, "/repos/:owner/:repo/branches/:branch"},
  192. {http.MethodDelete, "/repos/:owner/:repo"},
  193. {http.MethodGet, "/repos/:owner/:repo/collaborators"},
  194. {http.MethodGet, "/repos/:owner/:repo/collaborators/:user"},
  195. {http.MethodPut, "/repos/:owner/:repo/collaborators/:user"},
  196. {http.MethodDelete, "/repos/:owner/:repo/collaborators/:user"},
  197. {http.MethodGet, "/repos/:owner/:repo/comments"},
  198. {http.MethodGet, "/repos/:owner/:repo/commits/:sha/comments"},
  199. {http.MethodPost, "/repos/:owner/:repo/commits/:sha/comments"},
  200. {http.MethodGet, "/repos/:owner/:repo/comments/:id"},
  201. //{http.MethodPatch, "/repos/:owner/:repo/comments/:id"},
  202. {http.MethodDelete, "/repos/:owner/:repo/comments/:id"},
  203. {http.MethodGet, "/repos/:owner/:repo/commits"},
  204. {http.MethodGet, "/repos/:owner/:repo/commits/:sha"},
  205. {http.MethodGet, "/repos/:owner/:repo/readme"},
  206. //{http.MethodGet, "/repos/:owner/:repo/contents/*path"},
  207. //{http.MethodPut, "/repos/:owner/:repo/contents/*path"},
  208. //{http.MethodDelete, "/repos/:owner/:repo/contents/*path"},
  209. //{http.MethodGet, "/repos/:owner/:repo/:archive_format/:ref"},
  210. {http.MethodGet, "/repos/:owner/:repo/keys"},
  211. {http.MethodGet, "/repos/:owner/:repo/keys/:id"},
  212. {http.MethodPost, "/repos/:owner/:repo/keys"},
  213. //{http.MethodPatch, "/repos/:owner/:repo/keys/:id"},
  214. {http.MethodDelete, "/repos/:owner/:repo/keys/:id"},
  215. {http.MethodGet, "/repos/:owner/:repo/downloads"},
  216. {http.MethodGet, "/repos/:owner/:repo/downloads/:id"},
  217. {http.MethodDelete, "/repos/:owner/:repo/downloads/:id"},
  218. {http.MethodGet, "/repos/:owner/:repo/forks"},
  219. {http.MethodPost, "/repos/:owner/:repo/forks"},
  220. {http.MethodGet, "/repos/:owner/:repo/hooks"},
  221. {http.MethodGet, "/repos/:owner/:repo/hooks/:id"},
  222. {http.MethodPost, "/repos/:owner/:repo/hooks"},
  223. //{http.MethodPatch, "/repos/:owner/:repo/hooks/:id"},
  224. {http.MethodPost, "/repos/:owner/:repo/hooks/:id/tests"},
  225. {http.MethodDelete, "/repos/:owner/:repo/hooks/:id"},
  226. {http.MethodPost, "/repos/:owner/:repo/merges"},
  227. {http.MethodGet, "/repos/:owner/:repo/releases"},
  228. {http.MethodGet, "/repos/:owner/:repo/releases/:id"},
  229. {http.MethodPost, "/repos/:owner/:repo/releases"},
  230. //{http.MethodPatch, "/repos/:owner/:repo/releases/:id"},
  231. {http.MethodDelete, "/repos/:owner/:repo/releases/:id"},
  232. {http.MethodGet, "/repos/:owner/:repo/releases/:id/assets"},
  233. {http.MethodGet, "/repos/:owner/:repo/stats/contributors"},
  234. {http.MethodGet, "/repos/:owner/:repo/stats/commit_activity"},
  235. {http.MethodGet, "/repos/:owner/:repo/stats/code_frequency"},
  236. {http.MethodGet, "/repos/:owner/:repo/stats/participation"},
  237. {http.MethodGet, "/repos/:owner/:repo/stats/punch_card"},
  238. {http.MethodGet, "/repos/:owner/:repo/statuses/:ref"},
  239. {http.MethodPost, "/repos/:owner/:repo/statuses/:ref"},
  240. // Search
  241. {http.MethodGet, "/search/repositories"},
  242. {http.MethodGet, "/search/code"},
  243. {http.MethodGet, "/search/issues"},
  244. {http.MethodGet, "/search/users"},
  245. {http.MethodGet, "/legacy/issues/search/:owner/:repository/:state/:keyword"},
  246. {http.MethodGet, "/legacy/repos/search/:keyword"},
  247. {http.MethodGet, "/legacy/user/search/:keyword"},
  248. {http.MethodGet, "/legacy/user/email/:email"},
  249. // Users
  250. {http.MethodGet, "/users/:user"},
  251. {http.MethodGet, "/user"},
  252. //{http.MethodPatch, "/user"},
  253. {http.MethodGet, "/users"},
  254. {http.MethodGet, "/user/emails"},
  255. {http.MethodPost, "/user/emails"},
  256. {http.MethodDelete, "/user/emails"},
  257. {http.MethodGet, "/users/:user/followers"},
  258. {http.MethodGet, "/user/followers"},
  259. {http.MethodGet, "/users/:user/following"},
  260. {http.MethodGet, "/user/following"},
  261. {http.MethodGet, "/user/following/:user"},
  262. {http.MethodGet, "/users/:user/following/:target_user"},
  263. {http.MethodPut, "/user/following/:user"},
  264. {http.MethodDelete, "/user/following/:user"},
  265. {http.MethodGet, "/users/:user/keys"},
  266. {http.MethodGet, "/user/keys"},
  267. {http.MethodGet, "/user/keys/:id"},
  268. {http.MethodPost, "/user/keys"},
  269. //{http.MethodPatch, "/user/keys/:id"},
  270. {http.MethodDelete, "/user/keys/:id"},
  271. }
  272. func TestShouldBindUri(t *testing.T) {
  273. DefaultWriter = os.Stdout
  274. router := New()
  275. type Person struct {
  276. Name string `uri:"name" binding:"required"`
  277. Id string `uri:"id" binding:"required"`
  278. }
  279. router.Handle(http.MethodGet, "/rest/:name/:id", func(c *Context) {
  280. var person Person
  281. assert.NoError(t, c.ShouldBindUri(&person))
  282. assert.True(t, "" != person.Name)
  283. assert.True(t, "" != person.Id)
  284. c.String(http.StatusOK, "ShouldBindUri test OK")
  285. })
  286. path, _ := exampleFromPath("/rest/:name/:id")
  287. w := performRequest(router, http.MethodGet, path)
  288. assert.Equal(t, "ShouldBindUri test OK", w.Body.String())
  289. assert.Equal(t, http.StatusOK, w.Code)
  290. }
  291. func TestBindUri(t *testing.T) {
  292. DefaultWriter = os.Stdout
  293. router := New()
  294. type Person struct {
  295. Name string `uri:"name" binding:"required"`
  296. Id string `uri:"id" binding:"required"`
  297. }
  298. router.Handle(http.MethodGet, "/rest/:name/:id", func(c *Context) {
  299. var person Person
  300. assert.NoError(t, c.BindUri(&person))
  301. assert.True(t, "" != person.Name)
  302. assert.True(t, "" != person.Id)
  303. c.String(http.StatusOK, "BindUri test OK")
  304. })
  305. path, _ := exampleFromPath("/rest/:name/:id")
  306. w := performRequest(router, http.MethodGet, path)
  307. assert.Equal(t, "BindUri test OK", w.Body.String())
  308. assert.Equal(t, http.StatusOK, w.Code)
  309. }
  310. func TestBindUriError(t *testing.T) {
  311. DefaultWriter = os.Stdout
  312. router := New()
  313. type Member struct {
  314. Number string `uri:"num" binding:"required,uuid"`
  315. }
  316. router.Handle(http.MethodGet, "/new/rest/:num", func(c *Context) {
  317. var m Member
  318. assert.Error(t, c.BindUri(&m))
  319. })
  320. path1, _ := exampleFromPath("/new/rest/:num")
  321. w1 := performRequest(router, http.MethodGet, path1)
  322. assert.Equal(t, http.StatusBadRequest, w1.Code)
  323. }
  324. func TestRaceContextCopy(t *testing.T) {
  325. DefaultWriter = os.Stdout
  326. router := Default()
  327. router.GET("/test/copy/race", func(c *Context) {
  328. c.Set("1", 0)
  329. c.Set("2", 0)
  330. // Sending a copy of the Context to two separate routines
  331. go readWriteKeys(c.Copy())
  332. go readWriteKeys(c.Copy())
  333. c.String(http.StatusOK, "run OK, no panics")
  334. })
  335. w := performRequest(router, http.MethodGet, "/test/copy/race")
  336. assert.Equal(t, "run OK, no panics", w.Body.String())
  337. }
  338. func readWriteKeys(c *Context) {
  339. for {
  340. c.Set("1", rand.Int())
  341. c.Set("2", c.Value("1"))
  342. }
  343. }
  344. func githubConfigRouter(router *Engine) {
  345. for _, route := range githubAPI {
  346. router.Handle(route.method, route.path, func(c *Context) {
  347. output := make(map[string]string, len(c.Params)+1)
  348. output["status"] = "good"
  349. for _, param := range c.Params {
  350. output[param.Key] = param.Value
  351. }
  352. c.JSON(http.StatusOK, output)
  353. })
  354. }
  355. }
  356. func TestGithubAPI(t *testing.T) {
  357. DefaultWriter = os.Stdout
  358. router := New()
  359. githubConfigRouter(router)
  360. for _, route := range githubAPI {
  361. path, values := exampleFromPath(route.path)
  362. w := performRequest(router, route.method, path)
  363. // TEST
  364. assert.Contains(t, w.Body.String(), "\"status\":\"good\"")
  365. for _, value := range values {
  366. str := fmt.Sprintf("\"%s\":\"%s\"", value.Key, value.Value)
  367. assert.Contains(t, w.Body.String(), str)
  368. }
  369. }
  370. }
  371. func exampleFromPath(path string) (string, Params) {
  372. output := new(bytes.Buffer)
  373. params := make(Params, 0, 6)
  374. start := -1
  375. for i, c := range path {
  376. if c == ':' {
  377. start = i + 1
  378. }
  379. if start >= 0 {
  380. if c == '/' {
  381. value := fmt.Sprint(rand.Intn(100000))
  382. params = append(params, Param{
  383. Key: path[start:i],
  384. Value: value,
  385. })
  386. output.WriteString(value)
  387. output.WriteRune(c)
  388. start = -1
  389. }
  390. } else {
  391. output.WriteRune(c)
  392. }
  393. }
  394. if start >= 0 {
  395. value := fmt.Sprint(rand.Intn(100000))
  396. params = append(params, Param{
  397. Key: path[start:],
  398. Value: value,
  399. })
  400. output.WriteString(value)
  401. }
  402. return output.String(), params
  403. }
  404. func BenchmarkGithub(b *testing.B) {
  405. router := New()
  406. githubConfigRouter(router)
  407. runRequest(b, router, http.MethodGet, "/legacy/issues/search/:owner/:repository/:state/:keyword")
  408. }
  409. func BenchmarkParallelGithub(b *testing.B) {
  410. DefaultWriter = os.Stdout
  411. router := New()
  412. githubConfigRouter(router)
  413. req, _ := http.NewRequest(http.MethodPost, "/repos/manucorporat/sse/git/blobs", nil)
  414. b.RunParallel(func(pb *testing.PB) {
  415. // Each goroutine has its own bytes.Buffer.
  416. for pb.Next() {
  417. w := httptest.NewRecorder()
  418. router.ServeHTTP(w, req)
  419. }
  420. })
  421. }
  422. func BenchmarkParallelGithubDefault(b *testing.B) {
  423. DefaultWriter = os.Stdout
  424. router := New()
  425. githubConfigRouter(router)
  426. req, _ := http.NewRequest(http.MethodPost, "/repos/manucorporat/sse/git/blobs", nil)
  427. b.RunParallel(func(pb *testing.PB) {
  428. // Each goroutine has its own bytes.Buffer.
  429. for pb.Next() {
  430. w := httptest.NewRecorder()
  431. router.ServeHTTP(w, req)
  432. }
  433. })
  434. }