blob: 1322125106e45fd09d8804ed68de6f1dd70a4722 [file] [log] [blame]
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package upload_test
import (
"strings"
"testing"
"time"
"golang.org/x/telemetry/internal/configtest"
"golang.org/x/telemetry/internal/regtest"
"golang.org/x/telemetry/internal/telemetry"
"golang.org/x/telemetry/internal/testenv"
"golang.org/x/telemetry/internal/upload"
)
// createUploader sets up an upload environment for the provided test, with a
// fake proxy allowing the given counters, and a fake upload server.
//
// The returned Uploader is ready to upload the given directory.
// The second return is a function to fetch all uploaded reports.
//
// For convenience, createUploader also sets the mode in telemetryDir to "on",
// back-dated to a time in the past. Callers that want to run the upload with a
// different mode can reset as necessary.
//
// All associated resources are cleaned up with t.Clean.
func createUploader(t *testing.T, telemetryDir string, counters, stackCounters []string) (*upload.Uploader, func() [][]byte) {
t.Helper()
if err := telemetry.NewDir(telemetryDir).SetModeAsOf("on", time.Now().Add(-365*24*time.Hour)); err != nil {
t.Fatal(err)
}
srv, uploaded := upload.CreateTestUploadServer(t)
uc := upload.CreateTestUploadConfig(t, counters, stackCounters)
env := configtest.LocalProxyEnv(t, uc, "v1.2.3")
uploader, err := upload.NewUploader(upload.RunConfig{
TelemetryDir: telemetryDir,
UploadURL: srv.URL,
LogWriter: testWriter{t},
Env: env,
})
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { uploader.Close() })
return uploader, uploaded
}
// testWriter is an io.Writer wrapping t.Log.
type testWriter struct {
t *testing.T
}
func (w testWriter) Write(p []byte) (n int, err error) {
w.t.Log(strings.TrimSuffix(string(p), "\n")) // trim newlines added by logging
return len(p), nil
}
func TestUploader_MultipleUploads(t *testing.T) {
// This test checks that Uploader.Run produces multiple reports when counters
// span more than a week.
testenv.SkipIfUnsupportedPlatform(t)
// This program is run at two different dates.
prog := regtest.NewIncProgram(t, "prog", "counter1")
// Create two counter files to upload, at least a week apart.
telemetryDir := t.TempDir()
asof1 := time.Now().Add(-15 * 24 * time.Hour)
if out, err := regtest.RunProgAsOf(t, telemetryDir, asof1, prog); err != nil {
t.Fatalf("failed to run program: %s", out)
}
asof2 := time.Now().Add(-8 * 24 * time.Hour)
if out, err := regtest.RunProgAsOf(t, telemetryDir, asof2, prog); err != nil {
t.Fatalf("failed to run program: %s", out)
}
uploader, getUploads := createUploader(t, telemetryDir, []string{"counter1", "counter2"}, nil)
if err := uploader.Run(); err != nil {
t.Fatal(err)
}
uploads := getUploads()
if got, want := len(uploads), 2; got != want {
t.Fatalf("got %d uploads, want %d", got, want)
}
for _, upload := range uploads {
report := string(upload)
if !strings.Contains(report, "counter1") {
t.Errorf("Didn't get an upload for counter1. Report:\n%s", report)
}
}
}
func TestUploader_EmptyUpload(t *testing.T) {
// This test verifies that an empty counter file does not cause uploads of
// another week's reports to fail.
testenv.SkipIfUnsupportedPlatform(t)
// prog1 runs in week 1, and increments no counter.
prog1 := regtest.NewIncProgram(t, "prog1")
// prog2 runs in week 2.
prog2 := regtest.NewIncProgram(t, "prog2", "week2")
telemetryDir := t.TempDir()
// Create two counter files to upload, at least a week apart.
// Week 1 has no counters, which in the past caused the both uploads to fail.
asof1 := time.Now().Add(-15 * 24 * time.Hour)
if out, err := regtest.RunProgAsOf(t, telemetryDir, asof1, prog1); err != nil {
t.Fatalf("failed to run program: %s", out)
}
asof2 := time.Now().Add(-8 * 24 * time.Hour)
if out, err := regtest.RunProgAsOf(t, telemetryDir, asof2, prog2); err != nil {
t.Fatalf("failed to run program: %s", out)
}
uploader, getUploads := createUploader(t, telemetryDir, []string{"week1", "week2"}, nil)
if err := uploader.Run(); err != nil {
t.Fatal(err)
}
// Check that we got one upload, for week 2.
uploads := getUploads()
if got, want := len(uploads), 1; got != want {
t.Fatalf("got %d uploads, want %d", got, want)
}
for _, upload := range uploads {
report := string(upload)
if !strings.Contains(report, "week2") {
t.Errorf("Didn't get an upload for week2. Report:\n%s", report)
}
}
}
func TestUploader_ModeHandling(t *testing.T) {
// This test verifies that the uploader honors the telemetry mode, as well as
// its asof date.
testenv.SkipIfUnsupportedPlatform(t)
prog := regtest.NewIncProgram(t, "prog1", "counter")
tests := []struct {
mode string
wantUploads int
}{
{"off", 0},
{"local", 0},
{"on", 1}, // only the second week is uploadable
}
for _, test := range tests {
t.Run(test.mode, func(t *testing.T) {
telemetryDir := t.TempDir()
// Create two counter files to upload, at least a week apart.
now := time.Now()
asof1 := now.Add(-15 * 24 * time.Hour)
if out, err := regtest.RunProgAsOf(t, telemetryDir, asof1, prog); err != nil {
t.Fatalf("failed to run program: %s", out)
}
asof2 := now.Add(-8 * 24 * time.Hour)
if out, err := regtest.RunProgAsOf(t, telemetryDir, asof2, prog); err != nil {
t.Fatalf("failed to run program: %s", out)
}
uploader, getUploads := createUploader(t, telemetryDir, []string{"counter"}, nil)
// Enable telemetry as of 10 days ago. This should prevent the first week
// from being uploaded, but not the second.
if err := telemetry.NewDir(telemetryDir).SetModeAsOf(test.mode, now.Add(-10*24*time.Hour)); err != nil {
t.Fatal(err)
}
if err := uploader.Run(); err != nil {
t.Fatal(err)
}
uploads := getUploads()
if gotUploads := len(uploads); gotUploads != test.wantUploads {
t.Fatalf("got %d uploads, want %d", gotUploads, test.wantUploads)
}
})
}
}