Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 

275 řádky
7.3 KiB

  1. // Copyright 2017 Google LLC
  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. // +build integration,go1.7
  15. package profiler
  16. import (
  17. "bytes"
  18. "flag"
  19. "fmt"
  20. "os"
  21. "strings"
  22. "testing"
  23. "text/template"
  24. "time"
  25. "cloud.google.com/go/profiler/proftest"
  26. "golang.org/x/net/context"
  27. "golang.org/x/oauth2/google"
  28. compute "google.golang.org/api/compute/v1"
  29. )
  30. var (
  31. commit = flag.String("commit", "", "git commit to test")
  32. runID = strings.Replace(time.Now().Format("2006-01-02-15-04-05.000000-0700"), ".", "-", -1)
  33. )
  34. const (
  35. cloudScope = "https://www.googleapis.com/auth/cloud-platform"
  36. benchFinishString = "busybench finished profiling"
  37. )
  38. const startupTemplate = `
  39. #! /bin/bash
  40. (
  41. # Shut down the VM in 5 minutes after this script exits
  42. # to stop accounting the VM for billing and cores quota.
  43. trap "sleep 300 && poweroff" EXIT
  44. retry() {
  45. for i in {1..3}; do
  46. "${@}" && return 0
  47. done
  48. return 1
  49. }
  50. # Fail on any error.
  51. set -eo pipefail
  52. # Display commands being run.
  53. set -x
  54. # Install git
  55. retry apt-get update >/dev/null
  56. retry apt-get -y -q install git >/dev/null
  57. # Install desired Go version
  58. mkdir -p /tmp/bin
  59. retry curl -sL -o /tmp/bin/gimme https://raw.githubusercontent.com/travis-ci/gimme/master/gimme
  60. chmod +x /tmp/bin/gimme
  61. export PATH=$PATH:/tmp/bin
  62. retry eval "$(gimme {{.GoVersion}})"
  63. # Set $GOPATH
  64. export GOPATH="$HOME/go"
  65. export GOCLOUD_HOME=$GOPATH/src/cloud.google.com/go
  66. mkdir -p $GOCLOUD_HOME
  67. # Install agent
  68. retry git clone https://code.googlesource.com/gocloud $GOCLOUD_HOME >/dev/null
  69. cd $GOCLOUD_HOME/profiler/busybench
  70. git reset --hard {{.Commit}}
  71. retry go get >/dev/null
  72. # Run benchmark with agent
  73. go run busybench.go --service="{{.Service}}" --mutex_profiling="{{.MutexProfiling}}"
  74. # Write output to serial port 2 with timestamp.
  75. ) 2>&1 | while read line; do echo "$(date): ${line}"; done >/dev/ttyS1
  76. `
  77. const dockerfileFmt = `FROM golang
  78. RUN git clone https://code.googlesource.com/gocloud /go/src/cloud.google.com/go \
  79. && cd /go/src/cloud.google.com/go/profiler/busybench && git reset --hard %s \
  80. && go get && go install
  81. CMD ["busybench", "--service", "%s"]
  82. `
  83. type goGCETestCase struct {
  84. proftest.InstanceConfig
  85. name string
  86. goVersion string
  87. mutexProfiling bool
  88. wantProfileTypes []string
  89. }
  90. func (tc *goGCETestCase) initializeStartupScript(template *template.Template) error {
  91. var buf bytes.Buffer
  92. err := template.Execute(&buf,
  93. struct {
  94. Service string
  95. GoVersion string
  96. Commit string
  97. MutexProfiling bool
  98. }{
  99. Service: tc.name,
  100. GoVersion: tc.goVersion,
  101. Commit: *commit,
  102. MutexProfiling: tc.mutexProfiling,
  103. })
  104. if err != nil {
  105. return fmt.Errorf("failed to render startup script for %s: %v", tc.name, err)
  106. }
  107. tc.StartupScript = buf.String()
  108. return nil
  109. }
  110. func TestAgentIntegration(t *testing.T) {
  111. projectID := os.Getenv("GCLOUD_TESTS_GOLANG_PROJECT_ID")
  112. if projectID == "" {
  113. t.Fatalf("Getenv(GCLOUD_TESTS_GOLANG_PROJECT_ID) got empty string")
  114. }
  115. zone := os.Getenv("GCLOUD_TESTS_GOLANG_ZONE")
  116. if zone == "" {
  117. t.Fatalf("Getenv(GCLOUD_TESTS_GOLANG_ZONE) got empty string")
  118. }
  119. if *commit == "" {
  120. t.Fatal("commit flag is not set")
  121. }
  122. ctx := context.Background()
  123. client, err := google.DefaultClient(ctx, cloudScope)
  124. if err != nil {
  125. t.Fatalf("failed to get default client: %v", err)
  126. }
  127. computeService, err := compute.New(client)
  128. if err != nil {
  129. t.Fatalf("failed to initialize compute service: %v", err)
  130. }
  131. template, err := template.New("startupScript").Parse(startupTemplate)
  132. if err != nil {
  133. t.Fatalf("failed to parse startup script template: %v", err)
  134. }
  135. tr := proftest.TestRunner{
  136. Client: client,
  137. }
  138. gceTr := proftest.GCETestRunner{
  139. TestRunner: tr,
  140. ComputeService: computeService,
  141. }
  142. testcases := []goGCETestCase{
  143. {
  144. InstanceConfig: proftest.InstanceConfig{
  145. ProjectID: projectID,
  146. Zone: zone,
  147. Name: fmt.Sprintf("profiler-test-go110-%s", runID),
  148. MachineType: "n1-standard-1",
  149. },
  150. name: fmt.Sprintf("profiler-test-go110-%s-gce", runID),
  151. wantProfileTypes: []string{"CPU", "HEAP", "THREADS", "CONTENTION"},
  152. goVersion: "1.10",
  153. mutexProfiling: true,
  154. },
  155. {
  156. InstanceConfig: proftest.InstanceConfig{
  157. ProjectID: projectID,
  158. Zone: zone,
  159. Name: fmt.Sprintf("profiler-test-go19-%s", runID),
  160. MachineType: "n1-standard-1",
  161. },
  162. name: fmt.Sprintf("profiler-test-go19-%s-gce", runID),
  163. wantProfileTypes: []string{"CPU", "HEAP", "THREADS", "CONTENTION"},
  164. goVersion: "1.9",
  165. mutexProfiling: true,
  166. },
  167. {
  168. InstanceConfig: proftest.InstanceConfig{
  169. ProjectID: projectID,
  170. Zone: zone,
  171. Name: fmt.Sprintf("profiler-test-go18-%s", runID),
  172. MachineType: "n1-standard-1",
  173. },
  174. name: fmt.Sprintf("profiler-test-go18-%s-gce", runID),
  175. wantProfileTypes: []string{"CPU", "HEAP", "THREADS", "CONTENTION"},
  176. goVersion: "1.8",
  177. mutexProfiling: true,
  178. },
  179. {
  180. InstanceConfig: proftest.InstanceConfig{
  181. ProjectID: projectID,
  182. Zone: zone,
  183. Name: fmt.Sprintf("profiler-test-go17-%s", runID),
  184. MachineType: "n1-standard-1",
  185. },
  186. name: fmt.Sprintf("profiler-test-go17-%s-gce", runID),
  187. wantProfileTypes: []string{"CPU", "HEAP", "THREADS"},
  188. goVersion: "1.7",
  189. },
  190. {
  191. InstanceConfig: proftest.InstanceConfig{
  192. ProjectID: projectID,
  193. Zone: zone,
  194. Name: fmt.Sprintf("profiler-test-go16-%s", runID),
  195. MachineType: "n1-standard-1",
  196. },
  197. name: fmt.Sprintf("profiler-test-go16-%s-gce", runID),
  198. wantProfileTypes: []string{"CPU", "HEAP", "THREADS"},
  199. goVersion: "1.6",
  200. },
  201. }
  202. for _, tc := range testcases {
  203. tc := tc // capture range variable
  204. t.Run(tc.name, func(t *testing.T) {
  205. t.Parallel()
  206. if err := tc.initializeStartupScript(template); err != nil {
  207. t.Fatalf("failed to initialize startup script")
  208. }
  209. if err := gceTr.StartInstance(ctx, &tc.InstanceConfig); err != nil {
  210. t.Fatal(err)
  211. }
  212. defer func() {
  213. if gceTr.DeleteInstance(ctx, &tc.InstanceConfig); err != nil {
  214. t.Fatal(err)
  215. }
  216. }()
  217. timeoutCtx, cancel := context.WithTimeout(ctx, time.Minute*25)
  218. defer cancel()
  219. if err := gceTr.PollForSerialOutput(timeoutCtx, &tc.InstanceConfig, benchFinishString); err != nil {
  220. t.Fatalf("PollForSerialOutput() got error: %v", err)
  221. }
  222. timeNow := time.Now()
  223. endTime := timeNow.Format(time.RFC3339)
  224. startTime := timeNow.Add(-1 * time.Hour).Format(time.RFC3339)
  225. for _, pType := range tc.wantProfileTypes {
  226. pr, err := tr.QueryProfiles(tc.ProjectID, tc.name, startTime, endTime, pType)
  227. if err != nil {
  228. t.Errorf("QueryProfiles(%s, %s, %s, %s, %s) got error: %v", tc.ProjectID, tc.name, startTime, endTime, pType, err)
  229. continue
  230. }
  231. if err := pr.HasFunction("busywork"); err != nil {
  232. t.Error(err)
  233. }
  234. }
  235. })
  236. }
  237. }