You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

317 lines
7.5 KiB

  1. // Copyright 2018, OpenCensus Authors
  2. //
  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. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package ochttp_test
  15. import (
  16. "fmt"
  17. "io/ioutil"
  18. "net/http"
  19. "net/http/httptest"
  20. "strings"
  21. "sync"
  22. "testing"
  23. "go.opencensus.io/plugin/ochttp"
  24. "go.opencensus.io/stats/view"
  25. "go.opencensus.io/trace"
  26. )
  27. const reqCount = 5
  28. func TestClientNew(t *testing.T) {
  29. server := httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
  30. resp.Write([]byte("Hello, world!"))
  31. }))
  32. defer server.Close()
  33. if err := view.Register(
  34. ochttp.ClientSentBytesDistribution,
  35. ochttp.ClientReceivedBytesDistribution,
  36. ochttp.ClientRoundtripLatencyDistribution,
  37. ochttp.ClientCompletedCount,
  38. ); err != nil {
  39. t.Fatalf("Failed to register ochttp.DefaultClientViews error: %v", err)
  40. }
  41. views := []string{
  42. "opencensus.io/http/client/sent_bytes",
  43. "opencensus.io/http/client/received_bytes",
  44. "opencensus.io/http/client/roundtrip_latency",
  45. "opencensus.io/http/client/completed_count",
  46. }
  47. for _, name := range views {
  48. v := view.Find(name)
  49. if v == nil {
  50. t.Errorf("view not found %q", name)
  51. continue
  52. }
  53. }
  54. var wg sync.WaitGroup
  55. var tr ochttp.Transport
  56. errs := make(chan error, reqCount)
  57. wg.Add(reqCount)
  58. for i := 0; i < reqCount; i++ {
  59. go func() {
  60. defer wg.Done()
  61. req, err := http.NewRequest("POST", server.URL, strings.NewReader("req-body"))
  62. if err != nil {
  63. errs <- fmt.Errorf("error creating request: %v", err)
  64. }
  65. resp, err := tr.RoundTrip(req)
  66. if err != nil {
  67. errs <- fmt.Errorf("response error: %v", err)
  68. }
  69. if err := resp.Body.Close(); err != nil {
  70. errs <- fmt.Errorf("error closing response body: %v", err)
  71. }
  72. if got, want := resp.StatusCode, 200; got != want {
  73. errs <- fmt.Errorf("resp.StatusCode=%d; wantCount %d", got, want)
  74. }
  75. }()
  76. }
  77. go func() {
  78. wg.Wait()
  79. close(errs)
  80. }()
  81. for err := range errs {
  82. if err != nil {
  83. t.Fatal(err)
  84. }
  85. }
  86. for _, viewName := range views {
  87. v := view.Find(viewName)
  88. if v == nil {
  89. t.Errorf("view not found %q", viewName)
  90. continue
  91. }
  92. rows, err := view.RetrieveData(v.Name)
  93. if err != nil {
  94. t.Error(err)
  95. continue
  96. }
  97. if got, want := len(rows), 1; got != want {
  98. t.Errorf("len(%q) = %d; want %d", viewName, got, want)
  99. continue
  100. }
  101. data := rows[0].Data
  102. var count int64
  103. switch data := data.(type) {
  104. case *view.CountData:
  105. count = data.Value
  106. case *view.DistributionData:
  107. count = data.Count
  108. default:
  109. t.Errorf("Unknown data type: %v", data)
  110. continue
  111. }
  112. if got := count; got != reqCount {
  113. t.Fatalf("%s = %d; want %d", viewName, got, reqCount)
  114. }
  115. }
  116. }
  117. func TestClientOld(t *testing.T) {
  118. server := httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
  119. resp.Write([]byte("Hello, world!"))
  120. }))
  121. defer server.Close()
  122. if err := view.Register(ochttp.DefaultClientViews...); err != nil {
  123. t.Fatalf("Failed to register ochttp.DefaultClientViews error: %v", err)
  124. }
  125. views := []string{
  126. "opencensus.io/http/client/request_count",
  127. "opencensus.io/http/client/latency",
  128. "opencensus.io/http/client/request_bytes",
  129. "opencensus.io/http/client/response_bytes",
  130. }
  131. for _, name := range views {
  132. v := view.Find(name)
  133. if v == nil {
  134. t.Errorf("view not found %q", name)
  135. continue
  136. }
  137. }
  138. var wg sync.WaitGroup
  139. var tr ochttp.Transport
  140. errs := make(chan error, reqCount)
  141. wg.Add(reqCount)
  142. for i := 0; i < reqCount; i++ {
  143. go func() {
  144. defer wg.Done()
  145. req, err := http.NewRequest("POST", server.URL, strings.NewReader("req-body"))
  146. if err != nil {
  147. errs <- fmt.Errorf("error creating request: %v", err)
  148. }
  149. resp, err := tr.RoundTrip(req)
  150. if err != nil {
  151. errs <- fmt.Errorf("response error: %v", err)
  152. }
  153. if err := resp.Body.Close(); err != nil {
  154. errs <- fmt.Errorf("error closing response body: %v", err)
  155. }
  156. if got, want := resp.StatusCode, 200; got != want {
  157. errs <- fmt.Errorf("resp.StatusCode=%d; wantCount %d", got, want)
  158. }
  159. }()
  160. }
  161. go func() {
  162. wg.Wait()
  163. close(errs)
  164. }()
  165. for err := range errs {
  166. if err != nil {
  167. t.Fatal(err)
  168. }
  169. }
  170. for _, viewName := range views {
  171. v := view.Find(viewName)
  172. if v == nil {
  173. t.Errorf("view not found %q", viewName)
  174. continue
  175. }
  176. rows, err := view.RetrieveData(v.Name)
  177. if err != nil {
  178. t.Error(err)
  179. continue
  180. }
  181. if got, want := len(rows), 1; got != want {
  182. t.Errorf("len(%q) = %d; want %d", viewName, got, want)
  183. continue
  184. }
  185. data := rows[0].Data
  186. var count int64
  187. switch data := data.(type) {
  188. case *view.CountData:
  189. count = data.Value
  190. case *view.DistributionData:
  191. count = data.Count
  192. default:
  193. t.Errorf("Unknown data type: %v", data)
  194. continue
  195. }
  196. if got := count; got != reqCount {
  197. t.Fatalf("%s = %d; want %d", viewName, got, reqCount)
  198. }
  199. }
  200. }
  201. var noTrace = trace.StartOptions{Sampler: trace.NeverSample()}
  202. func BenchmarkTransportNoTrace(b *testing.B) {
  203. benchmarkClientServer(b, &ochttp.Transport{StartOptions: noTrace})
  204. }
  205. func BenchmarkTransport(b *testing.B) {
  206. benchmarkClientServer(b, &ochttp.Transport{})
  207. }
  208. func benchmarkClientServer(b *testing.B, transport *ochttp.Transport) {
  209. b.ReportAllocs()
  210. ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  211. fmt.Fprintf(rw, "Hello world.\n")
  212. }))
  213. defer ts.Close()
  214. transport.StartOptions.Sampler = trace.AlwaysSample()
  215. var client http.Client
  216. client.Transport = transport
  217. b.ResetTimer()
  218. for i := 0; i < b.N; i++ {
  219. res, err := client.Get(ts.URL)
  220. if err != nil {
  221. b.Fatalf("Get: %v", err)
  222. }
  223. all, err := ioutil.ReadAll(res.Body)
  224. res.Body.Close()
  225. if err != nil {
  226. b.Fatal("ReadAll:", err)
  227. }
  228. body := string(all)
  229. if body != "Hello world.\n" {
  230. b.Fatal("Got body:", body)
  231. }
  232. }
  233. }
  234. func BenchmarkTransportParallel64NoTrace(b *testing.B) {
  235. benchmarkClientServerParallel(b, 64, &ochttp.Transport{StartOptions: noTrace})
  236. }
  237. func BenchmarkTransportParallel64(b *testing.B) {
  238. benchmarkClientServerParallel(b, 64, &ochttp.Transport{})
  239. }
  240. func benchmarkClientServerParallel(b *testing.B, parallelism int, transport *ochttp.Transport) {
  241. b.ReportAllocs()
  242. ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  243. fmt.Fprintf(rw, "Hello world.\n")
  244. }))
  245. defer ts.Close()
  246. var c http.Client
  247. transport.Base = &http.Transport{
  248. MaxIdleConns: parallelism,
  249. MaxIdleConnsPerHost: parallelism,
  250. }
  251. transport.StartOptions.Sampler = trace.AlwaysSample()
  252. c.Transport = transport
  253. b.ResetTimer()
  254. // TODO(ramonza): replace with b.RunParallel (it didn't work when I tried)
  255. var wg sync.WaitGroup
  256. wg.Add(parallelism)
  257. for i := 0; i < parallelism; i++ {
  258. iterations := b.N / parallelism
  259. if i == 0 {
  260. iterations += b.N % parallelism
  261. }
  262. go func() {
  263. defer wg.Done()
  264. for j := 0; j < iterations; j++ {
  265. res, err := c.Get(ts.URL)
  266. if err != nil {
  267. b.Logf("Get: %v", err)
  268. return
  269. }
  270. all, err := ioutil.ReadAll(res.Body)
  271. res.Body.Close()
  272. if err != nil {
  273. b.Logf("ReadAll: %v", err)
  274. return
  275. }
  276. body := string(all)
  277. if body != "Hello world.\n" {
  278. panic("Got body: " + body)
  279. }
  280. }
  281. }()
  282. }
  283. wg.Wait()
  284. }