Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into cole/persistent-volumes
Browse files Browse the repository at this point in the history
  • Loading branch information
colesnodgrass committed Jun 5, 2024
2 parents e606d73 + 13137d4 commit c2c6bc2
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 40 deletions.
6 changes: 3 additions & 3 deletions internal/telemetry/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ func Get(opts ...GetOption) Client {
analyticsCfg, err := loadConfigFromFile(configPath)
if errors.Is(err, os.ErrNotExist) {
// file not found, create a new one
analyticsCfg = Config{UserUUID: NewUUID()}
analyticsCfg = Config{AnalyticsID: NewUUID()}
if err := writeConfigToFile(configPath, analyticsCfg); err != nil {
return analyticsCfg, fmt.Errorf("could not write file to %s: %w", configPath, err)
}
Expand All @@ -113,8 +113,8 @@ func Get(opts ...GetOption) Client {
}

// if a file exists but doesn't have a uuid, create a new uuid
if analyticsCfg.UserUUID.IsZero() {
analyticsCfg.UserUUID = NewUUID()
if analyticsCfg.AnalyticsID.IsZero() {
analyticsCfg.AnalyticsID = NewUUID()
if err := writeConfigToFile(configPath, analyticsCfg); err != nil {
return analyticsCfg, fmt.Errorf("could not write file to %s: %w", configPath, err)
}
Expand Down
16 changes: 8 additions & 8 deletions internal/telemetry/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ func TestGet(t *testing.T) {
t.Error("expected config file to contain 'Airbyte'")
}

if !strings.Contains(string(data), "anonymous_user_uuid") {
t.Error("expected config file to contain 'anonymous_user_uuid'")
if !strings.Contains(string(data), fieldAnalyticsID) {
t.Error(fmt.Sprintf("expected config file to contain '%s'", fieldAnalyticsID))
}

if strings.Contains(string(data), "anonymous_user_id") {
t.Error("config file should not contain 'anonymous_user_id'")
if strings.Contains(string(data), fieldUserID) {
t.Error(fmt.Sprintf("config file should not contain '%s'", fieldUserID))
}
}

Expand Down Expand Up @@ -64,12 +64,12 @@ func TestGet_WithExistingULID(t *testing.T) {
t.Error("expected config file to contain 'Airbyte'")
}

if !strings.Contains(string(data), "anonymous_user_uuid") {
t.Error("expected config file to contain 'anonymous_user_uuid'")
if !strings.Contains(string(data), fieldAnalyticsID) {
t.Error(fmt.Sprintf("expected config file to contain '%s'", fieldAnalyticsID))
}

if !strings.Contains(string(data), "anonymous_user_id") {
t.Error("expected config file to contain 'anonymous_user_id'")
if !strings.Contains(string(data), fieldUserID) {
t.Error(fmt.Sprintf("config file should not contain '%s'", fieldUserID))
}
}

Expand Down
31 changes: 28 additions & 3 deletions internal/telemetry/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ const (
Anonymous usage reporting is currently enabled. For more information, please see https://docs.airbyte.com/telemetry`
)

// fields
const (
fieldAnalyticsID = "analytics_id"
fieldUserID = "anonymous_user_id"
)

var ConfigFile = filepath.Join(".airbyte", "analytics.yml")

// UUID is a wrapper around uuid.UUID so that we can implement the yaml interfaces.
Expand Down Expand Up @@ -104,8 +110,9 @@ func (u ULID) IsZero() bool {

// Config represents the analytics.yaml file.
type Config struct {
UserID ULID `yaml:"anonymous_user_id,omitempty"`
UserUUID UUID `yaml:"anonymous_user_uuid,omitempty"`
UserID ULID `yaml:"anonymous_user_id,omitempty"`
AnalyticsID UUID `yaml:"analytics_id,omitempty"`
Other map[string]interface{} `yaml:",inline"`
}

// permissions sets the file and directory permission level for the telemetry files that may be created.
Expand All @@ -126,9 +133,27 @@ func loadConfigFromFile(path string) (Config, error) {

var c Config

if err := yaml.Unmarshal(analytics, &c); err != nil {
if err := yaml.Unmarshal(analytics, &c.Other); err != nil {
return Config{}, fmt.Errorf("could not unmarshal yaml: %w", err)
}
if v, ok := c.Other[fieldUserID]; ok {
if parsed, err := ulid.Parse(v.(string)); err != nil {
return Config{}, fmt.Errorf("could not parse ulid (%s): %w", v, err)
} else {
c.UserID = ULID(parsed)
}
}

if v, ok := c.Other[fieldAnalyticsID]; ok {
if parsed, err := uuid.Parse(v.(string)); err != nil {
return Config{}, fmt.Errorf("could not parse uuid (%s): %w", v, err)
} else {
c.AnalyticsID = UUID(parsed)
}
}

delete(c.Other, fieldUserID)
delete(c.Other, fieldAnalyticsID)

return c, nil
}
Expand Down
132 changes: 117 additions & 15 deletions internal/telemetry/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ anonymous_user_id: ` + ulidID.String()); err != nil {
t.Fatal("could not write to temp file", err)
}

cnf, err := loadConfigFromFile(f.Name())
cfg, err := loadConfigFromFile(f.Name())
if d := cmp.Diff(nil, err); d != "" {
t.Error("failed to load file", d)
}

if d := cmp.Diff(ulidID.String(), cnf.UserID.String()); d != "" {
if d := cmp.Diff(ulidID.String(), cfg.UserID.String()); d != "" {
t.Error("id is incorrect", d)
}
})
Expand Down Expand Up @@ -94,21 +94,63 @@ func TestLoadConfigWithUUID(t *testing.T) {
}
defer f.Close()

if _, err := f.WriteString(`# comments
anonymous_user_uuid: ` + uuidID.String()); err != nil {
cfgData := fmt.Sprintf(`# comments
%s: %s`, fieldAnalyticsID, uuidID.String())

if _, err := f.WriteString(cfgData); err != nil {
t.Fatal("could not write to temp file", err)
}

cnf, err := loadConfigFromFile(f.Name())
cfg, err := loadConfigFromFile(f.Name())
if d := cmp.Diff(nil, err); d != "" {
t.Error("failed to load file", d)
}

if d := cmp.Diff(uuidID.String(), cnf.UserUUID.String()); d != "" {
if d := cmp.Diff(uuidID.String(), cfg.AnalyticsID.String()); d != "" {
t.Error("id is incorrect", d)
}
})

t.Run("happy path with extra fields", func(t *testing.T) {
f, err := os.CreateTemp(t.TempDir(), "analytics-")
if err != nil {
t.Fatal("could not create temp file", err)
}
defer f.Close()

cfgData := fmt.Sprintf(`# comments
%s: %s
extra_field: extra_value
another_field: false
total: 300`,
fieldAnalyticsID, uuidID.String())

if _, err := f.WriteString(cfgData); err != nil {
t.Fatal("could not write to temp file", err)
}

cfg, err := loadConfigFromFile(f.Name())
if d := cmp.Diff(nil, err); d != "" {
t.Error("failed to load file", d)
}

if d := cmp.Diff(uuidID.String(), cfg.AnalyticsID.String()); d != "" {
t.Error("id is incorrect", d)
}

if d := cmp.Diff("extra_value", cfg.Other["extra_field"]); d != "" {
t.Error("extra_field is incorrect", d)
}

if d := cmp.Diff(false, cfg.Other["another_field"]); d != "" {
t.Error("another_field is incorrect", d)
}

if d := cmp.Diff(300, cfg.Other["total"]); d != "" {
t.Error("total is incorrect", d)
}
})

t.Run("no file returns err", func(t *testing.T) {
_, err := loadConfigFromFile(filepath.Join(t.TempDir(), "dne.yml"))
if err == nil {
Expand Down Expand Up @@ -171,8 +213,8 @@ func TestWriteConfig(t *testing.T) {
t.Error("failed to read file", err)
}

exp := fmt.Sprintf(`%sanonymous_user_id: %s
`, header, ulidID.String())
exp := fmt.Sprintf(`%s%s: %s
`, header, fieldUserID, ulidID.String())

if d := cmp.Diff(exp, string(contents)); d != "" {
t.Error("contents do not match", d)
Expand All @@ -182,7 +224,34 @@ func TestWriteConfig(t *testing.T) {
t.Run("uuid", func(t *testing.T) {
path := filepath.Join(t.TempDir(), "nested", "deeply", ConfigFile)

cfg := Config{UserUUID: UUID(uuidID)}
cfg := Config{AnalyticsID: UUID(uuidID)}

if err := writeConfigToFile(path, cfg); err != nil {
t.Error("failed to create file", err)
}

contents, err := os.ReadFile(path)
if err != nil {
t.Error("failed to read file", err)
}

exp := fmt.Sprintf(`%s%s: %s
`, header, fieldAnalyticsID, uuidID.String())

if d := cmp.Diff(exp, string(contents)); d != "" {
t.Error("contents do not match", d)
}
})

t.Run("uuid and other", func(t *testing.T) {
path := filepath.Join(t.TempDir(), "nested", "deeply", ConfigFile)

cfg := Config{
AnalyticsID: UUID(uuidID),
Other: map[string]interface{}{
"another_field": "another_value",
},
}

if err := writeConfigToFile(path, cfg); err != nil {
t.Error("failed to create file", err)
Expand All @@ -193,8 +262,9 @@ func TestWriteConfig(t *testing.T) {
t.Error("failed to read file", err)
}

exp := fmt.Sprintf(`%sanonymous_user_uuid: %s
`, header, uuidID.String())
exp := fmt.Sprintf(`%s%s: %s
another_field: another_value
`, header, fieldAnalyticsID, uuidID.String())

if d := cmp.Diff(exp, string(contents)); d != "" {
t.Error("contents do not match", d)
Expand All @@ -205,8 +275,38 @@ func TestWriteConfig(t *testing.T) {
path := filepath.Join(t.TempDir(), "nested", "deeply", ConfigFile)

cfg := Config{
UserID: ULID(ulidID),
UserUUID: UUID(uuidID),
UserID: ULID(ulidID),
AnalyticsID: UUID(uuidID),
}

if err := writeConfigToFile(path, cfg); err != nil {
t.Error("failed to create file", err)
}

contents, err := os.ReadFile(path)
if err != nil {
t.Error("failed to read file", err)
}

exp := fmt.Sprintf(`%s%s: %s
%s: %s
`, header, fieldUserID, ulidID.String(), fieldAnalyticsID, uuidID.String())

if d := cmp.Diff(exp, string(contents)); d != "" {
t.Error("contents do not match", d)
}
})

t.Run("ulid, uuid, and other", func(t *testing.T) {
path := filepath.Join(t.TempDir(), ConfigFile)

cfg := Config{
UserID: ULID(ulidID),
AnalyticsID: UUID(uuidID),
Other: map[string]interface{}{
"field": "value is here",
"count": 100,
},
}

if err := writeConfigToFile(path, cfg); err != nil {
Expand All @@ -219,8 +319,10 @@ func TestWriteConfig(t *testing.T) {
}

exp := fmt.Sprintf(`%sanonymous_user_id: %s
anonymous_user_uuid: %s
`, header, ulidID.String(), uuidID.String())
%s: %s
count: 100
field: value is here
`, header, ulidID.String(), fieldAnalyticsID, uuidID.String())

if d := cmp.Diff(exp, string(contents)); d != "" {
t.Error("contents do not match", d)
Expand Down
4 changes: 2 additions & 2 deletions internal/telemetry/segment.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ func (s *SegmentClient) Attr(key, val string) {
}

func (s *SegmentClient) User() uuid.UUID {
return s.cfg.UserUUID.toUUID()
return s.cfg.AnalyticsID.toUUID()
}

const (
Expand Down Expand Up @@ -109,7 +109,7 @@ func (s *SegmentClient) send(ctx context.Context, es EventState, et EventType, e
}

body := body{
ID: s.cfg.UserUUID.String(),
ID: s.cfg.AnalyticsID.String(),
Event: string(et),
Properties: properties,
Timestamp: time.Now().UTC().Format(time.RFC3339),
Expand Down
Loading

0 comments on commit c2c6bc2

Please sign in to comment.