[
  {
    "path": ".circleci/config.yml",
    "content": "# Golang CircleCI 2.0 configuration file\n#\n# Check https://circleci.com/docs/2.0/language-go/ for more details\nversion: 2\njobs:\n  build:\n    docker:\n      # specify the version\n      - image: circleci/golang:1.16\n\n    working_directory: /go/src/github.com/rakyll/go-test-trace\n    steps:\n      - checkout\n\n      # specify any bash command here prefixed with `run: `\n      - run: go test $(go list ./... | grep -v /example) -v ./...\n"
  },
  {
    "path": ".gitignore",
    "content": "bin/*"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2021 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n   * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n   * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n   * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "Makefile",
    "content": "default:\n\tgo run main.go parser.go ./example\n\nstdin:\n\tgo test -v -count=1 ./example | go run main.go parser.go -stdin\n\n"
  },
  {
    "path": "README.md",
    "content": "# go-test-trace\n\n[![CircleCI](https://circleci.com/gh/rakyll/go-test-trace/tree/main.svg?style=svg)](https://circleci.com/gh/rakyll/go-test-trace/tree/main)\n\ngo-test-trace is like go test but it also generates\ndistributed traces.\n\nGenerated traces are exported in OTLP to a\n[OpenTelemetry collector](https://github.com/open-telemetry/opentelemetry-collector).\nYou need to run go-test-trace alongside a collector to export data to\ndistributed tracing service.\n\n![Honeycomb](https://i.imgur.com/E18PYk4.png)\n\n## Installation\n\n```\ngo get -u github.com/rakyll/go-test-trace\n```\n\n## Usage\n\nYou can use go-test-trace as a drop-in replacement for go test.\nThe following example will generate a distributed trace\nand export it to a collector available at \"127.0.0.1:55680\".\n\n```\n$ go-test-trace ./example\n=== RUN   TestStart\n--- PASS: TestStart (0.50s)\n=== RUN   TestStartWithOptions\n--- PASS: TestStartWithOptions (1.00s)\n=== RUN   TestFileParser\n--- FAIL: TestFileParser (0.30s)\n=== RUN   TestLoading\n=== PAUSE TestLoading\n=== RUN   TestLoading_abort\n=== PAUSE TestLoading_abort\n=== RUN   TestLoading_interrupt\n=== PAUSE TestLoading_interrupt\n=== CONT  TestLoading\n=== CONT  TestLoading_abort\n=== CONT  TestLoading_interrupt\n--- PASS: TestLoading_interrupt (0.08s)\n--- PASS: TestLoading (1.00s)\n--- PASS: TestLoading_abort (2.50s)\nFAIL\nFAIL\tgithub.com/rakyll/go-test-trace/example\t4.823s\nexit status 1\nmake: *** [default] Error 1\n```\n\nAlternatively, you can use -stdin option to parse\nthe output of go test. This option won't be as accurate\nin terms of timestamps because it will generate trace spans\nas it sees output in stdin.\n\n```\n$ go test -v ./example | go-test-trace -stdin\n```\n\nYou can export to any collector by using the endpoint flag:\n\n```\n$ go-test-trace -endpoint=my-otel-collector.io:9090 ./example\n```\n\nYou can make the go-test-trace to participate into an existing\ntrace with the traceparent flag.\n\n```\n$ go-test-trace -traceparent=00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01 ./example\n```\n\n## Running the collector\n\nAn example collector configuration is available at example/collector.yaml.\nIt exports to Honeycomb but you can choose to any other destination by\nchanging the configuration. Please edit the write key and data set\nwith your details from Honeycomb before using it.\n\nThen, you can run the collector locally by the following command\nand export the traces to Honeycomb:\n\n```\n$ docker run --rm -p 4317:4317 -p 55680:55680 -p 8888:8888 \\\n    -v \"${PWD}/example/collector.yaml\":/collector.yaml \\\n    --name awscollector public.ecr.aws/aws-observability/aws-otel-collector:latest \\\n    --config collector.yaml;\n```\n\nYou can use any configuration supported by [ADOT](https://github.com/aws-observability/aws-otel-collector)\nor export to any other OpenTelemetry collector.\n"
  },
  {
    "path": "example/collector.yaml",
    "content": "# You can modify this file with any component\n# available at https://github.com/aws-observability/aws-otel-collector#aws-otel-collector-built-in-components.\n# If you want to use components not supported\n# in this distribution, please feel free to use your\n# own distribution.\nreceivers:\n  otlp:\n    protocols:\n      grpc:\n      http:\nprocessors:\nexporters:\n  otlp:\n    endpoint: api.honeycomb.io:443\n    headers:\n      \"x-honeycomb-team\": \"<INSERT WRITE KEY>\"\n      \"x-honeycomb-dataset\": \"<INSERT DATASET>\"\n  logging:\n    loglevel: debug\n\nservice:\n  pipelines:\n    traces:\n      receivers: [otlp]\n      processors: []\n      exporters: [logging, otlp]\n"
  },
  {
    "path": "example/example_test.go",
    "content": "// Copyright 2020 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage example\n\nimport (\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestStart(t *testing.T) {\n\ttime.Sleep(500 * time.Millisecond)\n}\n\nfunc TestStartWithOptions(t *testing.T) {\n\ttime.Sleep(1000 * time.Millisecond)\n}\n\nfunc TestFileParser(t *testing.T) {\n\ttime.Sleep(300 * time.Millisecond)\n\tt.Fail()\n}\n\nfunc TestLoading(t *testing.T) {\n\tt.Parallel()\n\ttime.Sleep(time.Second)\n}\n\nfunc TestLoading_abort(t *testing.T) {\n\tt.Parallel()\n\ttime.Sleep(2500 * time.Millisecond)\n}\n\nfunc TestLoading_interrupt(t *testing.T) {\n\tt.Parallel()\n\ttime.Sleep(80 * time.Millisecond)\n}\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/rakyll/go-test-trace\n\ngo 1.14\n\nrequire (\n\tgo.opentelemetry.io/otel v1.0.0\n\tgo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.0.0\n\tgo.opentelemetry.io/otel/sdk v1.0.0\n\tgo.opentelemetry.io/otel/trace v1.0.0\n\tgolang.org/x/net v0.0.0-20210924151903-3ad01bbaa167 // indirect\n\tgolang.org/x/sys v0.0.0-20210923061019-b8560ed6a9b7 // indirect\n\tgolang.org/x/text v0.3.7 // indirect\n\tgoogle.golang.org/genproto v0.0.0-20210924002016-3dee208752a0 // indirect\n)\n"
  },
  {
    "path": "go.sum",
    "content": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=\ngithub.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=\ngithub.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ=\ngithub.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=\ngithub.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=\ngithub.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=\ngithub.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=\ngithub.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=\ngithub.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=\ngithub.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=\ngithub.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=\ngithub.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=\ngithub.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=\ngithub.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=\ngithub.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=\ngithub.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=\ngithub.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=\ngithub.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=\ngithub.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=\ngithub.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=\ngithub.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=\ngithub.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=\ngithub.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=\ngithub.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=\ngithub.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=\ngithub.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=\ngithub.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=\ngithub.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=\ngithub.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=\ngithub.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=\ngithub.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngo.opentelemetry.io/otel v1.0.0 h1:qTTn6x71GVBvoafHK/yaRUmFzI4LcONZD0/kXxl5PHI=\ngo.opentelemetry.io/otel v1.0.0/go.mod h1:AjRVh9A5/5DE7S+mZtTR6t8vpKKryam+0lREnfmS4cg=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace v1.0.0 h1:Vv4wbLEjheCTPV07jEav7fyUpJkyftQK7Ss2G7qgdSo=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace v1.0.0/go.mod h1:3VqVbIbjAycfL1C7sIu/Uh/kACIUPWHztt8ODYwR3oM=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.0.0 h1:B9VtEB1u41Ohnl8U6rMCh1jjedu8HwFh4D0QeB+1N+0=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.0.0/go.mod h1:zhEt6O5GGJ3NCAICr4hlCPoDb2GQuh4Obb4gZBgkoQQ=\ngo.opentelemetry.io/otel/sdk v1.0.0 h1:BNPMYUONPNbLneMttKSjQhOTlFLOD9U22HNG1KrIN2Y=\ngo.opentelemetry.io/otel/sdk v1.0.0/go.mod h1:PCrDHlSy5x1kjezSdL37PhbFUMjrsLRshJ2zCzeXwbM=\ngo.opentelemetry.io/otel/trace v1.0.0 h1:TSBr8GTEtKevYMG/2d21M989r5WJYVimhTHBKVEZuh4=\ngo.opentelemetry.io/otel/trace v1.0.0/go.mod h1:PXTWqayeFUlJV1YDNhsJYB184+IvAH814St6o6ajzIs=\ngo.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=\ngo.opentelemetry.io/proto/otlp v0.9.0 h1:C0g6TWmQYvjKRnljRULLWUVJGy8Uvu0NEL/5frY2/t4=\ngo.opentelemetry.io/proto/otlp v0.9.0/go.mod h1:1vKfU9rv61e9EVGthD1zNvUbiwPcimSsOPU9brfSHJg=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=\ngolang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=\ngolang.org/x/net v0.0.0-20210924151903-3ad01bbaa167 h1:eDd+TJqbgfXruGQ5sJRU7tEtp/58OAx4+Ayjxg4SM+4=\ngolang.org/x/net v0.0.0-20210924151903-3ad01bbaa167/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210923061019-b8560ed6a9b7 h1:c20P3CcPbopVp2f7099WLOqSNKURf30Z0uq66HpijZY=\ngolang.org/x/sys v0.0.0-20210923061019-b8560ed6a9b7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=\ngolang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=\ngolang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngoogle.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=\ngoogle.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=\ngoogle.golang.org/genproto v0.0.0-20210924002016-3dee208752a0 h1:5Tbluzus3QxoAJx4IefGt1W0HQZW4nuMrVk684jI74Q=\ngoogle.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=\ngoogle.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=\ngoogle.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=\ngoogle.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=\ngoogle.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=\ngoogle.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=\ngoogle.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q=\ngoogle.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=\ngoogle.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=\ngoogle.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=\ngoogle.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=\ngoogle.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=\ngoogle.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=\ngoogle.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=\ngoogle.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=\ngoogle.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=\ngoogle.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=\ngoogle.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\nhonnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\n"
  },
  {
    "path": "main.go",
    "content": "// Copyright 2021 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// go-test-trace is a tiny program that generates OpenTelemetry\n// traces when testing a Go package.\npackage main\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"flag\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"os/exec\"\n\t\"time\"\n\n\t\"go.opentelemetry.io/otel\"\n\t\"go.opentelemetry.io/otel/codes\"\n\t\"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc\"\n\t\"go.opentelemetry.io/otel/propagation\"\n\t\"go.opentelemetry.io/otel/sdk/resource\"\n\tsdktrace \"go.opentelemetry.io/otel/sdk/trace\"\n\tsemconv \"go.opentelemetry.io/otel/semconv/v1.4.0\"\n\toteltrace \"go.opentelemetry.io/otel/trace\"\n)\n\nvar (\n\tendpoint    string\n\tname        string\n\tstdin       bool\n\ttraceparent string\n\thelp        bool\n)\n\ntype spanData struct {\n\tspan      oteltrace.Span\n\tstartTime time.Time\n}\n\nvar collectedSpans = make(map[string]*spanData, 1000)\n\nfunc main() {\n\tfset := flag.NewFlagSet(\"\", flag.ContinueOnError)\n\tfset.StringVar(&endpoint, \"endpoint\", \"127.0.0.1:55680\", \"\")\n\tfset.StringVar(&name, \"name\", \"go-test-trace\", \"\")\n\tfset.BoolVar(&stdin, \"stdin\", false, \"\")\n\tfset.BoolVar(&help, \"help\", false, \"\")\n\tfset.StringVar(&traceparent, \"traceparent\", \"\", \"\")\n\tfset.Usage = func() {} // don't error instead pass remaining arguments to go test\n\tfset.Parse(os.Args[1:])\n\n\tif help {\n\t\tfmt.Println(usageText)\n\t\tos.Exit(0)\n\t}\n\tif err := trace(fset.Args()); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\nfunc trace(args []string) error {\n\tctx := context.Background()\n\ttraceExporter, err := otlptracegrpc.New(ctx,\n\t\totlptracegrpc.WithInsecure(),\n\t\totlptracegrpc.WithEndpoint(endpoint),\n\t\totlptracegrpc.WithTimeout(100*time.Millisecond),\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\tres, err := resource.New(ctx, resource.WithAttributes(\n\t\tsemconv.ServiceNameKey.String(\"go test\"),\n\t))\n\tif err != nil {\n\t\treturn err\n\t}\n\ttracerProvider := sdktrace.NewTracerProvider(\n\t\tsdktrace.WithSampler(sdktrace.AlwaysSample()),\n\t\tsdktrace.WithSpanProcessor(sdktrace.NewSimpleSpanProcessor(traceExporter)),\n\t\tsdktrace.WithResource(res),\n\t)\n\totel.SetTracerProvider(tracerProvider)\n\tt := otel.Tracer(name)\n\n\t// If there is a parent trace, participate into it.\n\t// If not, create a new root span.\n\tif traceparent != \"\" {\n\t\tpropagation := propagation.TraceContext{}\n\t\tctx = propagation.Extract(ctx, &carrier{traceparent: traceparent})\n\t}\n\n\tglobalCtx, globalSpan := t.Start(ctx, name)\n\tdefer func() {\n\t\tglobalSpan.End()\n\t\tif err := tracerProvider.Shutdown(context.Background()); err != nil {\n\t\t\tlog.Printf(\"Failed shutting down the tracer provider: %v\", err)\n\t\t}\n\t}()\n\n\tif stdin {\n\t\tp, err := newParser(globalCtx, t)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn p.parse(os.Stdin)\n\t}\n\n\t// Otherwise, act like a drop-in replacement for `go test`.\n\tgoTestArgs := append([]string{\"test\"}, args...)\n\tgoTestArgs = append(goTestArgs, \"-json\")\n\tcmd := exec.Command(\"go\", goTestArgs...)\n\tcmd.Env = append(\n\t\tos.Environ(),\n\t\tfmt.Sprintf(\"TRACEPARENT=%q\", globalSpan.SpanContext().TraceID()),\n\t)\n\tr, err := cmd.StdoutPipe()\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tdecoder := json.NewDecoder(r)\n\tgo func() {\n\t\tfor decoder.More() {\n\t\t\tvar data goTestOutput\n\t\t\tif err := decoder.Decode(&data); err != nil {\n\t\t\t\tif err == io.EOF {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tlog.Printf(\"Failed to decode JSON: %v\", err)\n\t\t\t}\n\t\t\tswitch data.Action {\n\t\t\tcase \"run\":\n\t\t\t\tvar span oteltrace.Span\n\t\t\t\t_, span = t.Start(globalCtx, data.Test, oteltrace.WithTimestamp(data.Time))\n\t\t\t\tcollectedSpans[data.Test] = &spanData{\n\t\t\t\t\tspan:      span,\n\t\t\t\t\tstartTime: data.Time,\n\t\t\t\t}\n\t\t\tcase \"pass\", \"fail\", \"skip\":\n\t\t\t\tif data.Test == \"\" {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tspanData, ok := collectedSpans[data.Test]\n\t\t\t\tif !ok {\n\t\t\t\t\treturn // should never happen\n\t\t\t\t}\n\t\t\t\tif data.Action == \"fail\" {\n\t\t\t\t\tspanData.span.SetStatus(codes.Error, \"\")\n\t\t\t\t}\n\t\t\t\tspanData.span.End(oteltrace.WithTimestamp(data.Time))\n\t\t\t}\n\t\t\tfmt.Print(data.Output)\n\t\t}\n\t}()\n\treturn cmd.Run()\n}\n\ntype goTestOutput struct {\n\tTime   time.Time\n\tAction string\n\tTest   string\n\tOutput string\n}\n\ntype carrier struct{ traceparent string }\n\nfunc (c *carrier) Get(key string) string {\n\tif key == \"traceparent\" {\n\t\treturn c.traceparent\n\t}\n\treturn \"\"\n}\n\nfunc (c *carrier) Set(key string, value string) {\n\tpanic(\"not implemented\")\n}\n\nfunc (c *carrier) Keys() []string {\n\treturn []string{\"traceparent\"}\n}\n\nconst usageText = `Usage:\ngo-test-trace [flags...] [go test flags...]\n\nFlags:\n-name        Name of the trace span created for the test, optional.\n-endpoint    OpenTelemetry gRPC collector endpoint, 127.0.0.1:55680 by default.\n-traceparent Trace to participate into if any, in W3C Trace Context format.\n-stdin       Parse go test verbose output from stdin.\n-help        Print this text.\n\nRun \"go help test\" for go test flags.`\n"
  },
  {
    "path": "parser.go",
    "content": "// Copyright 2021 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"regexp\"\n\t\"strings\"\n\t\"time\"\n\n\t\"go.opentelemetry.io/otel/codes\"\n\toteltrace \"go.opentelemetry.io/otel/trace\"\n)\n\ntype parser struct {\n\tglobalCtx context.Context\n\ttracer    oteltrace.Tracer\n}\n\nfunc newParser(ctx context.Context, tracer oteltrace.Tracer) (*parser, error) {\n\treturn &parser{globalCtx: ctx, tracer: tracer}, nil\n}\n\nfunc (p *parser) parse(r io.Reader) error {\n\treader := bufio.NewReader(r)\n\tfor {\n\t\tl, _, err := reader.ReadLine()\n\t\tif err == io.EOF {\n\t\t\treturn nil\n\t\t}\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tp.parseLine(string(l))\n\t}\n}\n\nfunc (p *parser) parseLine(line string) {\n\tdefer fmt.Printf(\"%s\\n\", line)\n\n\ttrimmed := strings.TrimSpace(line)\n\n\tswitch {\n\tcase strings.HasPrefix(trimmed, \"ok\"):\n\t\t// Do nothing.\n\tcase strings.HasPrefix(trimmed, \"PASS\"):\n\t\t// Do nothing.\n\tcase strings.HasPrefix(trimmed, \"FAIL\"):\n\t\t// Do nothing.\n\tcase strings.Contains(trimmed, \"[no test files]\"):\n\t\t// Do nothing.\n\tcase strings.HasPrefix(trimmed, \"--- SKIP\"):\n\t\t// TODO(jbd): Annotate.\n\n\tcase strings.HasPrefix(trimmed, \"=== RUN\"):\n\t\t// start span\n\t\tp.startSpanForLine(trimmed)\n\n\tcase strings.HasPrefix(trimmed, \"--- PASS\"):\n\t\t// end span\n\t\tp.endSpanForLine(trimmed, false)\n\n\tcase strings.HasPrefix(trimmed, \"--- FAIL\"):\n\t\t// end span with error\n\t\tp.endSpanForLine(trimmed, true)\n\t}\n\n}\n\nfunc (p *parser) startSpanForLine(line string) error {\n\tname := parseName(line)\n\t_, span := p.tracer.Start(p.globalCtx, name)\n\tcollectedSpans[name] = &spanData{\n\t\tspan:      span,\n\t\tstartTime: time.Now(),\n\t}\n\treturn nil\n}\n\nfunc (p *parser) endSpanForLine(line string, errored bool) {\n\tname, dur := parseNameAndDuration(line)\n\tdata, ok := collectedSpans[name]\n\tif !ok {\n\t\treturn\n\t}\n\tif errored {\n\t\tdata.span.SetStatus(codes.Error, \"\")\n\t}\n\tdata.span.End(oteltrace.WithTimestamp(data.startTime.Add(dur)))\n}\n\nfunc parseName(line string) string {\n\treturn testNameRegex.FindAllStringSubmatch(line, -1)[0][0]\n}\n\nfunc parseNameAndDuration(line string) (string, time.Duration) {\n\tm := testNameWithDurationRegex.FindAllStringSubmatch(line, -1)\n\tname := m[0][1]\n\tduration := m[0][2]\n\n\tdur, _ := time.ParseDuration(duration)\n\treturn name, dur\n}\n\nvar (\n\ttestNameRegex             = regexp.MustCompile(`(Test.+)`)\n\ttestNameWithDurationRegex = regexp.MustCompile(`(Test.+)\\s\\(([\\w|\\.]+)\\)`)\n)\n"
  },
  {
    "path": "parser_test.go",
    "content": "// Copyright 2021 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// gotest is a tiny program that shells out to `go test`\n// and prints the output in color.\npackage main\n\nimport (\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestParseNameAndDuration(t *testing.T) {\n\ttests := []struct {\n\t\tdescription string\n\t\tline        string\n\t\twantName    string\n\t\twantDur     string\n\t}{\n\t\t{\n\t\t\tdescription: \"pass sub test\",\n\t\t\tline:        \"    --- PASS: TestGetConfig/otlp#01 (1.50s)\",\n\t\t\twantName:    \"TestGetConfig/otlp#01\",\n\t\t\twantDur:     \"1.5s\",\n\t\t},\n\t\t{\n\t\t\tdescription: \"fail sub test\",\n\t\t\tline:        \"    --- FAIL: TestGetConfig/otlp#01 (1.50s)\",\n\t\t\twantName:    \"TestGetConfig/otlp#01\",\n\t\t\twantDur:     \"1.5s\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.description, func(t *testing.T) {\n\t\t\tname, dur := parseNameAndDuration(tt.line)\n\t\t\tif name != tt.wantName {\n\t\t\t\tt.Errorf(\"parseNameAndDuration() name = %v, want %v\", name, tt.wantName)\n\t\t\t}\n\t\t\tparsedWantDur, _ := time.ParseDuration(tt.wantDur)\n\t\t\tif dur != parsedWantDur {\n\t\t\t\tt.Errorf(\"parseNameAndDuration() duration = %v, want %v\", dur, tt.wantDur)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  }
]