Skip to content

Commit 09c2e0c

Browse files
committed
godev/internal/upload: create internal upload package
This package provides methods for querying and reading an upload config for use in the local viewer to show the user which data is valid for a particular config and the upload server to validate a report upload request. Change-Id: I4a1a87b8dd05db7c807f233c20d808d29f761b59 Reviewed-on: https://go-review.googlesource.com/c/telemetry/+/503995 Run-TryBot: Jamal Carvalho <[email protected]> Reviewed-by: Hyang-Ah Hana Kim <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent a736992 commit 09c2e0c

File tree

3 files changed

+231
-0
lines changed

3 files changed

+231
-0
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
{
2+
"Version": "v0.0.1-test",
3+
"GOOS": [
4+
"linux",
5+
"darwin"
6+
],
7+
"GOARCH": [
8+
"amd64",
9+
"arm64"
10+
],
11+
"GoVersion": [
12+
"go1.20",
13+
"go1.20.1"
14+
],
15+
"Programs": [
16+
{
17+
"Name": "golang.org/x/tools/gopls",
18+
"Versions": [
19+
"v0.10.1",
20+
"v0.11.0"
21+
],
22+
"Counters": [
23+
{
24+
"Name": "editor:{emacs,vim,vscode,other}",
25+
"Rate": 0.01
26+
}
27+
]
28+
},
29+
{
30+
"Name": "cmd/go",
31+
"Versions": [
32+
"v0.10.1",
33+
"v0.11.0"
34+
],
35+
"Counters": [
36+
{
37+
"Name": "go/buildcache/miss:{0,0.1,0.2,0.5,1,10,100,2,20,5,50}",
38+
"Rate": 0.01
39+
}
40+
]
41+
}
42+
]
43+
}

godev/internal/upload/upload.go

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// Copyright 2023 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// package upload provides methods for loading and querying a
6+
// telemetry upload config file.
7+
package upload
8+
9+
import (
10+
"encoding/json"
11+
"os"
12+
"strings"
13+
14+
"golang.org/x/telemetry"
15+
)
16+
17+
// Config is a wrapper around telemetry.UploadConfig that provides some
18+
// convenience methods for checking the contents of a report.
19+
type Config struct {
20+
*telemetry.UploadConfig
21+
program map[string]bool
22+
goos map[string]bool
23+
goarch map[string]bool
24+
goversion map[string]bool
25+
pgversion map[pgkey]bool
26+
pgcounter map[pgkey]bool
27+
pgstack map[pgkey]bool
28+
}
29+
30+
type pgkey struct {
31+
program, key string
32+
}
33+
34+
func ReadConfig(file string) (*Config, error) {
35+
data, err := os.ReadFile(file)
36+
if err != nil {
37+
return nil, err
38+
}
39+
var cfg telemetry.UploadConfig
40+
if err := json.Unmarshal(data, &cfg); err != nil {
41+
return nil, err
42+
}
43+
return NewConfig(&cfg), nil
44+
}
45+
46+
func NewConfig(cfg *telemetry.UploadConfig) *Config {
47+
ucfg := Config{UploadConfig: cfg}
48+
ucfg.goos = set(ucfg.GOOS)
49+
ucfg.goarch = set(ucfg.GOARCH)
50+
ucfg.goversion = set(ucfg.GoVersion)
51+
ucfg.program = make(map[string]bool, len(ucfg.Programs))
52+
ucfg.pgversion = make(map[pgkey]bool, len(ucfg.Programs))
53+
ucfg.pgcounter = make(map[pgkey]bool, len(ucfg.Programs))
54+
ucfg.pgstack = make(map[pgkey]bool, len(ucfg.Programs))
55+
for _, p := range ucfg.Programs {
56+
ucfg.program[p.Name] = true
57+
for _, v := range p.Versions {
58+
ucfg.pgversion[pgkey{p.Name, v}] = true
59+
}
60+
for _, c := range p.Counters {
61+
for _, e := range expand(c.Name) {
62+
ucfg.pgcounter[pgkey{p.Name, e}] = true
63+
}
64+
}
65+
for _, s := range p.Stacks {
66+
ucfg.pgstack[pgkey{p.Name, s.Name}] = true
67+
}
68+
}
69+
return &ucfg
70+
}
71+
72+
func (r *Config) HasProgram(s string) bool {
73+
return r.program[s]
74+
}
75+
76+
func (r *Config) HasGOOS(s string) bool {
77+
return r.goos[s]
78+
}
79+
80+
func (r *Config) HasGOARCH(s string) bool {
81+
return r.goarch[s]
82+
}
83+
84+
func (r *Config) HasGoVersion(s string) bool {
85+
return r.goversion[s]
86+
}
87+
88+
func (r *Config) HasVersion(program, version string) bool {
89+
return r.pgversion[pgkey{program, version}]
90+
}
91+
92+
func (r *Config) HasCounter(program, counter string) bool {
93+
return r.pgcounter[pgkey{program, counter}]
94+
}
95+
96+
func (r *Config) HasStack(program, stack string) bool {
97+
return r.pgstack[pgkey{program, stack}]
98+
}
99+
100+
func set(slice []string) map[string]bool {
101+
s := make(map[string]bool, len(slice))
102+
for _, v := range slice {
103+
s[v] = true
104+
}
105+
return s
106+
}
107+
108+
// expand takes a counter defined with buckets and expands it into distinct
109+
// strings for each bucket
110+
func expand(counter string) []string {
111+
prefix, rest, hasBuckets := strings.Cut(counter, "{")
112+
var counters []string
113+
if hasBuckets {
114+
buckets := strings.Split(strings.TrimSuffix(rest, "}"), ",")
115+
for _, b := range buckets {
116+
counters = append(counters, prefix+b)
117+
}
118+
} else {
119+
counters = append(counters, prefix)
120+
}
121+
return counters
122+
}

godev/internal/upload/upload_test.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Copyright 2023 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package upload
6+
7+
import (
8+
_ "embed"
9+
"testing"
10+
)
11+
12+
func TestUploadConfig(t *testing.T) {
13+
got, err := ReadConfig("testdata/config.json")
14+
if err != nil {
15+
t.Fatal(err)
16+
}
17+
wantGOOS := []string{"linux", "darwin"}
18+
wantGOARCH := []string{"amd64", "arm64"}
19+
wantGoVersion := []string{"go1.20", "go1.20.1"}
20+
wantPrograms := []string{"golang.org/x/tools/gopls", "cmd/go"}
21+
wantVersions := [][2]string{
22+
{"golang.org/x/tools/gopls", "v0.10.1"},
23+
{"golang.org/x/tools/gopls", "v0.11.0"},
24+
}
25+
wantCounters := [][2]string{
26+
{"golang.org/x/tools/gopls", "editor:emacs"},
27+
{"golang.org/x/tools/gopls", "editor:vim"},
28+
{"golang.org/x/tools/gopls", "editor:vscode"},
29+
{"golang.org/x/tools/gopls", "editor:other"},
30+
{"cmd/go", "go/buildcache/miss:0"},
31+
{"cmd/go", "go/buildcache/miss:1"},
32+
{"cmd/go", "go/buildcache/miss:10"},
33+
{"cmd/go", "go/buildcache/miss:100"},
34+
}
35+
36+
for _, w := range wantGOOS {
37+
if !got.HasGOOS(w) {
38+
t.Errorf("got.HasGOOS(%s) = false: want true", w)
39+
}
40+
}
41+
for _, w := range wantGOARCH {
42+
if !got.HasGOARCH(w) {
43+
t.Errorf("got.HasGOARCH(%s) = false: want true", w)
44+
}
45+
}
46+
for _, w := range wantGoVersion {
47+
if !got.HasGoVersion(w) {
48+
t.Errorf("got.HasGoVersion(%s) = false: want true", w)
49+
}
50+
}
51+
for _, w := range wantPrograms {
52+
if !got.HasProgram(w) {
53+
t.Errorf("got.HasProgram(%s) = false: want true", w)
54+
}
55+
}
56+
for _, w := range wantVersions {
57+
if !got.HasVersion(w[0], w[1]) {
58+
t.Errorf("got.HasVersion(%s, %s) = false: want true", w[0], w)
59+
}
60+
}
61+
for _, w := range wantCounters {
62+
if !got.HasCounter(w[0], w[1]) {
63+
t.Errorf("got.HasCounter(%s, %s) = false: want true", w[0], w[1])
64+
}
65+
}
66+
}

0 commit comments

Comments
 (0)