Skip to content
This repository was archived by the owner on Sep 15, 2021. It is now read-only.

Commit 5211787

Browse files
committed
integration: added a helper to run tests, upload to GCS and email
Updates #10 A helper to get us closer to integration tests that are triggered say on every push to a repository. The helper when run will run the tests by `make test` and if there is any failure, it'll upload all the output to GCS, grab a link and then compose an email that'll be sent to everyone that needs to be notified. It uses postmark for emailing ```shell $ go run run+notify.go -gcp-project census-demos \ -postmark-account-token "dbfb2fd0-9c33-42cf-85ee-6d234ebca614" \ -postmark-server-token "85d8e1b7-52a1-41fb-8ac9-4eb5d450996e" ``` ```shell 2018/03/28 00:25:13 Failed to run `make test` error: exit status 2 output: protoc -I src/main/proto/ src/main/proto/defs.proto --go_out=plugins=grpc:src/main/proto # To use a different OpenCensus and gRPC version, use # -PopencensusVersion= and -PgrpcVersion=. ./gradlew installDist FAILURE: Build failed with an exception. * What went wrong: Could not determine java version from '9.0.4'. * Try: Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. make: *** [gradlew_install] Error 1 exit status 1 ```
1 parent 3e9f9cd commit 5211787

File tree

1 file changed

+153
-0
lines changed

1 file changed

+153
-0
lines changed

integration/run+notify.go

+153
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
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+
15+
package main
16+
17+
import (
18+
"bytes"
19+
"context"
20+
"crypto/md5"
21+
"flag"
22+
"fmt"
23+
"io"
24+
"log"
25+
"os/exec"
26+
"strings"
27+
"text/template"
28+
"time"
29+
30+
"github.com/keighl/postmark"
31+
"github.com/orijtech/infra"
32+
)
33+
34+
var infraClient *infra.Client
35+
var emailClient *postmark.Client
36+
var emails []string
37+
var project, bucket string
38+
var appEmail string
39+
var postmarkAccountToken, postmarkServerToken, emailStr string
40+
41+
func init() {
42+
flag.StringVar(&project, "gcp-project", "opencensus-integration-tests", "the GCP project that'll be used to save information about builds")
43+
flag.StringVar(&bucket, "gcs-bucket", "opencensus-integration-tests", "the GCS bucket that failure results will be saved to")
44+
flag.StringVar(&emailStr, "notify-emails", "[email protected]", "the emails of folks to notify on failures e.g. [email protected],[email protected]")
45+
flag.StringVar(&appEmail, "app-email", "[email protected]", "the postmark email account to use to send notifications")
46+
flag.StringVar(&postmarkAccountToken, "postmark-account-token", "", "the postmark account token")
47+
flag.StringVar(&postmarkServerToken, "postmark-server-token", "", "the postmark server token")
48+
flag.Parse()
49+
50+
var err error
51+
infraClient, err = infra.NewDefaultClient()
52+
if err != nil {
53+
log.Fatalf("Creating GCP infraClient %v", err)
54+
}
55+
emailClient = postmark.NewClient(postmarkServerToken, postmarkAccountToken)
56+
emails = strings.Split(emailStr, ",")
57+
}
58+
59+
type grouping struct {
60+
cmd string
61+
steps [][]string
62+
}
63+
64+
var preliminaryCommands = []*grouping{
65+
{
66+
cmd: "go",
67+
steps: [][]string{
68+
// {"get", "-u", "go.opencensus.io/..."},
69+
},
70+
},
71+
}
72+
73+
func runCommand(maxTimeSeconds int64, sCmd string, args ...string) ([]byte, error) {
74+
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(maxTimeSeconds)*time.Second)
75+
defer cancel()
76+
77+
cmd := exec.CommandContext(ctx, sCmd, args...)
78+
return cmd.CombinedOutput()
79+
}
80+
81+
func main() {
82+
// 1. Run the preliminary installations
83+
for _, pCmd := range preliminaryCommands {
84+
for _, args := range pCmd.steps {
85+
output, err := runCommand(100, pCmd.cmd, args...)
86+
if err != nil {
87+
// Upload the results to GCS then mail everyone the link to the test failures.
88+
intro := fmt.Sprintf("While running `%s %s` encountered", pCmd.cmd, strings.Join(args, " "))
89+
if e := uploadToGCSThenMailWithLink(intro, output, err, emails...); e != nil {
90+
msg := "While trying to notify concerened parties, got error %v\n\nOriginal error: %v\nOutput: %s\n"
91+
log.Fatalf(msg, e, err, output)
92+
}
93+
log.Fatalf("Encountered error %v so proceeding to notify concerned parties by email", err)
94+
}
95+
}
96+
}
97+
98+
// 2. Run `make test`
99+
output, err := runCommand(600, "make", "test")
100+
if err != nil {
101+
// Mail these results to the team
102+
intro := "While running `make test` encountered"
103+
if e := uploadToGCSThenMailWithLink(intro, output, err, emails...); e != nil {
104+
msg := "While trying to notify concerened parties after `make test`, got error %v\n\nOriginal error: %v\nOutput: %s\n"
105+
log.Fatalf(msg, e, err, output)
106+
}
107+
log.Fatalf("Failed to run `make test` error: %v\noutput: %s", err, output)
108+
}
109+
}
110+
111+
func uploadToGCSThenMailWithLink(intro string, output []byte, err error, emails ...string) error {
112+
// 1. Ensure that the bucket exists firstly on GCS
113+
bh := &infra.BucketCheck{Project: project, Bucket: bucket}
114+
if _, err := infraClient.EnsureBucketExists(bh); err != nil {
115+
return err
116+
}
117+
118+
uploadBody := fmt.Sprintf("%s\nError %v\n\nOutput: %s", intro, err, output)
119+
120+
now := time.Now().Round(time.Second)
121+
mHash := md5.New()
122+
fmt.Fprintf(mHash, "%s", now)
123+
// 2. Upload the content to the GCS bucket
124+
params := &infra.UploadParams{
125+
Public: true,
126+
Reader: func() io.Reader { return strings.NewReader(uploadBody) },
127+
Bucket: bucket,
128+
Name: fmt.Sprintf("test-failures/%d/%d/%d/%x.txt", now.Year(), now.Month(), now.Day(), mHash.Sum(nil)),
129+
}
130+
obj, err := infraClient.UploadWithParams(params)
131+
if err != nil {
132+
return err
133+
}
134+
theURL := infra.ObjectURL(obj)
135+
136+
htmlBuf := new(bytes.Buffer)
137+
info := map[string]string{"URL": theURL, "Time": fmt.Sprintf("%s", now.UTC())}
138+
if err := emailTemplate.Execute(htmlBuf, info); err != nil {
139+
return err
140+
}
141+
email := postmark.Email{
142+
From: appEmail,
143+
To: strings.Join(emails, ","),
144+
Subject: "OpenCensus integration test failures",
145+
HtmlBody: htmlBuf.String(),
146+
}
147+
_, err = emailClient.SendEmail(email)
148+
return err
149+
}
150+
151+
var emailTemplate = template.Must(template.New("notification").Parse(`
152+
Test failures for OpenCensus integration tests at {{.Time}}.<br />Please visit the URL {{.URL}}
153+
`))

0 commit comments

Comments
 (0)