Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

chore: add unknown usage event type error#19436

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 36 additions & 13 deletionscoderd/usage/usagetypes/events.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,6 +13,7 @@ package usagetypes
import (
"bytes"
"encoding/json"
"fmt"
"strings"

"golang.org/x/xerrors"
Expand All@@ -22,6 +23,10 @@ import (
// type `usage_event_type`.
type UsageEventType string

// All event types.
//
// When adding a new event type, ensure you add it to the Valid method and the
// ParseEventWithType function.
const (
UsageEventTypeDCManagedAgentsV1 UsageEventType = "dc_managed_agents_v1"
)
Expand All@@ -43,38 +48,56 @@ func (e UsageEventType) IsHeartbeat() bool {
return e.Valid() && strings.HasPrefix(string(e), "hb_")
}

// ParseEvent parses the raw event data into thespecified Go type. It fails if
// there is any unknown fields or extra dataafter theevent. The returned event
// is validated.
func ParseEvent[T Event](data json.RawMessage) (T, error) {
// ParseEvent parses the raw event data into theprovided event. It fails if
// there is any unknown fields or extra dataat theend of the JSON. The
//returned eventis validated.
func ParseEvent(data json.RawMessage, out Event) error {
dec := json.NewDecoder(bytes.NewReader(data))
dec.DisallowUnknownFields()

var event T
err := dec.Decode(&event)
err := dec.Decode(out)
if err != nil {
returnevent,xerrors.Errorf("unmarshal %T event: %w",event, err)
return xerrors.Errorf("unmarshal %T event: %w",out, err)
}
if dec.More() {
returnevent,xerrors.Errorf("extra data after %T event",event)
return xerrors.Errorf("extra data after %T event",out)
}
err =event.Valid()
err =out.Valid()
if err != nil {
returnevent,xerrors.Errorf("invalid %T event: %w",event, err)
return xerrors.Errorf("invalid %T event: %w",out, err)
}

return event, nil
return nil
}

// UnknownEventTypeError is returned by ParseEventWithType when an unknown event
// type is encountered.
type UnknownEventTypeError struct {
EventType string
}

var _ error = UnknownEventTypeError{}

// Error implements error.
func (e UnknownEventTypeError) Error() string {
return fmt.Sprintf("unknown usage event type: %q", e.EventType)
}

// ParseEventWithType parses the raw event data into the specified Go type. It
// fails if there is any unknown fields or extra data after the event. The
// returned event is validated.
//
// If the event type is unknown, UnknownEventTypeError is returned.
func ParseEventWithType(eventType UsageEventType, data json.RawMessage) (Event, error) {
switch eventType {
case UsageEventTypeDCManagedAgentsV1:
return ParseEvent[DCManagedAgentsV1](data)
var event DCManagedAgentsV1
if err := ParseEvent(data, &event); err != nil {
return nil, err
}
return event, nil
default:
return nil,xerrors.Errorf("unknown event type: %s",eventType)
return nil,UnknownEventTypeError{EventType: string(eventType)}
}
}

Expand Down
27 changes: 17 additions & 10 deletionscoderd/usage/usagetypes/events_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,29 +13,34 @@ func TestParseEvent(t *testing.T) {

t.Run("ExtraFields", func(t *testing.T) {
t.Parallel()
_, err := usagetypes.ParseEvent[usagetypes.DCManagedAgentsV1]([]byte(`{"count": 1, "extra": "field"}`))
require.ErrorContains(t, err, "unmarshal usagetypes.DCManagedAgentsV1 event")
var event usagetypes.DCManagedAgentsV1
err := usagetypes.ParseEvent([]byte(`{"count": 1, "extra": "field"}`), &event)
require.ErrorContains(t, err, "unmarshal *usagetypes.DCManagedAgentsV1 event")
})

t.Run("ExtraData", func(t *testing.T) {
t.Parallel()
_, err := usagetypes.ParseEvent[usagetypes.DCManagedAgentsV1]([]byte(`{"count": 1}{"count": 2}`))
require.ErrorContains(t, err, "extra data after usagetypes.DCManagedAgentsV1 event")
var event usagetypes.DCManagedAgentsV1
err := usagetypes.ParseEvent([]byte(`{"count": 1}{"count": 2}`), &event)
require.ErrorContains(t, err, "extra data after *usagetypes.DCManagedAgentsV1 event")
})

t.Run("DCManagedAgentsV1", func(t *testing.T) {
t.Parallel()

event, err := usagetypes.ParseEvent[usagetypes.DCManagedAgentsV1]([]byte(`{"count": 1}`))
var event usagetypes.DCManagedAgentsV1
err := usagetypes.ParseEvent([]byte(`{"count": 1}`), &event)
require.NoError(t, err)
require.Equal(t, usagetypes.DCManagedAgentsV1{Count: 1}, event)
require.Equal(t, map[string]any{"count": uint64(1)}, event.Fields())

_, err = usagetypes.ParseEvent[usagetypes.DCManagedAgentsV1]([]byte(`{"count": "invalid"}`))
require.ErrorContains(t, err, "unmarshal usagetypes.DCManagedAgentsV1 event")
event = usagetypes.DCManagedAgentsV1{}
err = usagetypes.ParseEvent([]byte(`{"count": "invalid"}`), &event)
require.ErrorContains(t, err, "unmarshal *usagetypes.DCManagedAgentsV1 event")

_, err = usagetypes.ParseEvent[usagetypes.DCManagedAgentsV1]([]byte(`{}`))
require.ErrorContains(t, err, "invalid usagetypes.DCManagedAgentsV1 event: count must be greater than 0")
event = usagetypes.DCManagedAgentsV1{}
err = usagetypes.ParseEvent([]byte(`{}`), &event)
require.ErrorContains(t, err, "invalid *usagetypes.DCManagedAgentsV1 event: count must be greater than 0")
})
}

Expand All@@ -45,7 +50,9 @@ func TestParseEventWithType(t *testing.T) {
t.Run("UnknownEvent", func(t *testing.T) {
t.Parallel()
_, err := usagetypes.ParseEventWithType(usagetypes.UsageEventType("fake"), []byte(`{}`))
require.ErrorContains(t, err, "unknown event type: fake")
var unknownEventTypeError usagetypes.UnknownEventTypeError
require.ErrorAs(t, err, &unknownEventTypeError)
require.Equal(t, "fake", unknownEventTypeError.EventType)
})

t.Run("DCManagedAgentsV1", func(t *testing.T) {
Expand Down
2 changes: 2 additions & 0 deletionsenterprise/coderd/usage/publisher.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,6 +14,7 @@ import (
"golang.org/x/xerrors"

"cdr.dev/slog"
"github.com/coder/coder/v2/buildinfo"
"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/database/dbauthz"
"github.com/coder/coder/v2/coderd/database/dbtime"
Expand DownExpand Up@@ -396,6 +397,7 @@ func (p *tallymanPublisher) sendPublishRequest(ctx context.Context, deploymentID
iferr!=nil {
return usagetypes.TallymanV1IngestResponse{},err
}
r.Header.Set("User-Agent","coderd/"+buildinfo.Version())
r.Header.Set(usagetypes.TallymanCoderLicenseKeyHeader,licenseJwt)
r.Header.Set(usagetypes.TallymanCoderDeploymentIDHeader,deploymentID.String())

Expand Down
Loading

[8]ページ先頭

©2009-2025 Movatter.jp