util.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. // Copyright 2018 The go-ethereum Authors
  2. // This file is part of go-ethereum.
  3. //
  4. // go-ethereum is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // go-ethereum is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
  16. package main
  17. import (
  18. "bytes"
  19. "context"
  20. "crypto/md5"
  21. crand "crypto/rand"
  22. "errors"
  23. "fmt"
  24. "io"
  25. "io/ioutil"
  26. "math/rand"
  27. "net/http"
  28. "net/http/httptrace"
  29. "os"
  30. "strings"
  31. "time"
  32. "github.com/ethereum/go-ethereum/log"
  33. "github.com/ethereum/go-ethereum/metrics"
  34. "github.com/ethereum/go-ethereum/swarm/api"
  35. "github.com/ethereum/go-ethereum/swarm/api/client"
  36. "github.com/ethereum/go-ethereum/swarm/spancontext"
  37. opentracing "github.com/opentracing/opentracing-go"
  38. cli "gopkg.in/urfave/cli.v1"
  39. )
  40. var (
  41. commandName = ""
  42. seed = int(time.Now().UTC().UnixNano())
  43. )
  44. func init() {
  45. rand.Seed(int64(seed))
  46. }
  47. func httpEndpoint(host string) string {
  48. return fmt.Sprintf("http://%s:%d", host, httpPort)
  49. }
  50. func wsEndpoint(host string) string {
  51. return fmt.Sprintf("ws://%s:%d", host, wsPort)
  52. }
  53. func wrapCliCommand(name string, command func(*cli.Context) error) func(*cli.Context) error {
  54. return func(ctx *cli.Context) error {
  55. log.PrintOrigins(true)
  56. log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(verbosity), log.StreamHandler(os.Stdout, log.TerminalFormat(false))))
  57. commandName = name
  58. hosts = strings.Split(allhosts, ",")
  59. defer func(now time.Time) {
  60. totalTime := time.Since(now)
  61. log.Info("total time", "time", totalTime, "kb", filesize)
  62. metrics.GetOrRegisterResettingTimer(name+".total-time", nil).Update(totalTime)
  63. }(time.Now())
  64. log.Info("smoke test starting", "task", name, "timeout", timeout)
  65. metrics.GetOrRegisterCounter(name, nil).Inc(1)
  66. return command(ctx)
  67. }
  68. }
  69. func fetchFeed(topic string, user string, endpoint string, original []byte, ruid string) error {
  70. ctx, sp := spancontext.StartSpan(context.Background(), "feed-and-sync.fetch")
  71. defer sp.Finish()
  72. log.Trace("sleeping", "ruid", ruid)
  73. time.Sleep(3 * time.Second)
  74. log.Trace("http get request (feed)", "ruid", ruid, "api", endpoint, "topic", topic, "user", user)
  75. var tn time.Time
  76. reqUri := endpoint + "/bzz-feed:/?topic=" + topic + "&user=" + user
  77. req, _ := http.NewRequest("GET", reqUri, nil)
  78. opentracing.GlobalTracer().Inject(
  79. sp.Context(),
  80. opentracing.HTTPHeaders,
  81. opentracing.HTTPHeadersCarrier(req.Header))
  82. trace := client.GetClientTrace("feed-and-sync - http get", "feed-and-sync", ruid, &tn)
  83. req = req.WithContext(httptrace.WithClientTrace(ctx, trace))
  84. transport := http.DefaultTransport
  85. //transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
  86. tn = time.Now()
  87. res, err := transport.RoundTrip(req)
  88. if err != nil {
  89. log.Error(err.Error(), "ruid", ruid)
  90. return err
  91. }
  92. log.Trace("http get response (feed)", "ruid", ruid, "api", endpoint, "topic", topic, "user", user, "code", res.StatusCode, "len", res.ContentLength)
  93. if res.StatusCode != 200 {
  94. return fmt.Errorf("expected status code %d, got %v (ruid %v)", 200, res.StatusCode, ruid)
  95. }
  96. defer res.Body.Close()
  97. rdigest, err := digest(res.Body)
  98. if err != nil {
  99. log.Warn(err.Error(), "ruid", ruid)
  100. return err
  101. }
  102. if !bytes.Equal(rdigest, original) {
  103. err := fmt.Errorf("downloaded imported file md5=%x is not the same as the generated one=%x", rdigest, original)
  104. log.Warn(err.Error(), "ruid", ruid)
  105. return err
  106. }
  107. log.Trace("downloaded file matches random file", "ruid", ruid, "len", res.ContentLength)
  108. return nil
  109. }
  110. // fetch is getting the requested `hash` from the `endpoint` and compares it with the `original` file
  111. func fetch(hash string, endpoint string, original []byte, ruid string) error {
  112. ctx, sp := spancontext.StartSpan(context.Background(), "upload-and-sync.fetch")
  113. defer sp.Finish()
  114. log.Info("http get request", "ruid", ruid, "endpoint", endpoint, "hash", hash)
  115. var tn time.Time
  116. reqUri := endpoint + "/bzz:/" + hash + "/"
  117. req, _ := http.NewRequest("GET", reqUri, nil)
  118. opentracing.GlobalTracer().Inject(
  119. sp.Context(),
  120. opentracing.HTTPHeaders,
  121. opentracing.HTTPHeadersCarrier(req.Header))
  122. trace := client.GetClientTrace(commandName+" - http get", commandName, ruid, &tn)
  123. req = req.WithContext(httptrace.WithClientTrace(ctx, trace))
  124. transport := http.DefaultTransport
  125. //transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
  126. tn = time.Now()
  127. res, err := transport.RoundTrip(req)
  128. if err != nil {
  129. log.Error(err.Error(), "ruid", ruid)
  130. return err
  131. }
  132. log.Info("http get response", "ruid", ruid, "endpoint", endpoint, "hash", hash, "code", res.StatusCode, "len", res.ContentLength)
  133. if res.StatusCode != 200 {
  134. err := fmt.Errorf("expected status code %d, got %v", 200, res.StatusCode)
  135. log.Warn(err.Error(), "ruid", ruid)
  136. return err
  137. }
  138. defer res.Body.Close()
  139. rdigest, err := digest(res.Body)
  140. if err != nil {
  141. log.Warn(err.Error(), "ruid", ruid)
  142. return err
  143. }
  144. if !bytes.Equal(rdigest, original) {
  145. err := fmt.Errorf("downloaded imported file md5=%x is not the same as the generated one=%x", rdigest, original)
  146. log.Warn(err.Error(), "ruid", ruid)
  147. return err
  148. }
  149. log.Trace("downloaded file matches random file", "ruid", ruid, "len", res.ContentLength)
  150. return nil
  151. }
  152. // upload an arbitrary byte as a plaintext file to `endpoint` using the api client
  153. func upload(data []byte, endpoint string) (string, error) {
  154. swarm := client.NewClient(endpoint)
  155. f := &client.File{
  156. ReadCloser: ioutil.NopCloser(bytes.NewReader(data)),
  157. ManifestEntry: api.ManifestEntry{
  158. ContentType: "text/plain",
  159. Mode: 0660,
  160. Size: int64(len(data)),
  161. },
  162. }
  163. // upload data to bzz:// and retrieve the content-addressed manifest hash, hex-encoded.
  164. return swarm.Upload(f, "", false)
  165. }
  166. func digest(r io.Reader) ([]byte, error) {
  167. h := md5.New()
  168. _, err := io.Copy(h, r)
  169. if err != nil {
  170. return nil, err
  171. }
  172. return h.Sum(nil), nil
  173. }
  174. // generates random data in heap buffer
  175. func generateRandomData(datasize int) ([]byte, error) {
  176. b := make([]byte, datasize)
  177. c, err := crand.Read(b)
  178. if err != nil {
  179. return nil, err
  180. } else if c != datasize {
  181. return nil, errors.New("short read")
  182. }
  183. return b, nil
  184. }