| package quickstart |
|
|
| import ( |
| "bytes" |
| "context" |
| "encoding/json" |
| "fmt" |
| "io" |
| "net/http" |
| "os" |
| "strings" |
| "testing" |
| "time" |
|
|
| cloudevents "github.com/cloudevents/sdk-go/v2/event" |
| "github.com/samber/lo" |
| "github.com/stretchr/testify/assert" |
| "github.com/stretchr/testify/require" |
|
|
| api "github.com/openmeterio/openmeter/api/client/go" |
| apiv3 "github.com/openmeterio/openmeter/api/v3" |
| "github.com/openmeterio/openmeter/openmeter/meter" |
| ) |
|
|
| func initClient(t *testing.T) *api.ClientWithResponses { |
| t.Helper() |
|
|
| address := os.Getenv("OPENMETER_ADDRESS") |
| if address == "" { |
| t.Skip("OPENMETER_ADDRESS not set") |
| } |
|
|
| client, err := api.NewClientWithResponses(address) |
| require.NoError(t, err) |
|
|
| return client |
| } |
|
|
| func openmeterAddress(t *testing.T) string { |
| t.Helper() |
|
|
| address := os.Getenv("OPENMETER_ADDRESS") |
| if address == "" { |
| t.Skip("OPENMETER_ADDRESS not set") |
| } |
|
|
| return strings.TrimRight(address, "/") |
| } |
|
|
| func openmeterV3Address(t *testing.T) string { |
| t.Helper() |
|
|
| return openmeterAddress(t) + "/api/v3" |
| } |
|
|
| func createMeterV3(t *testing.T, address string, body apiv3.CreateMeterRequest) *apiv3.Meter { |
| t.Helper() |
|
|
| payload, err := json.Marshal(body) |
| require.NoError(t, err) |
|
|
| req, err := http.NewRequestWithContext( |
| context.Background(), |
| http.MethodPost, |
| address+"/openmeter/meters", |
| bytes.NewReader(payload), |
| ) |
| require.NoError(t, err) |
| req.Header.Set("Content-Type", "application/json") |
|
|
| resp, err := http.DefaultClient.Do(req) |
| require.NoError(t, err) |
| defer resp.Body.Close() |
|
|
| responseBody, err := io.ReadAll(resp.Body) |
| require.NoError(t, err) |
| require.Equal(t, http.StatusCreated, resp.StatusCode, "Invalid status code [response_body=%s]", string(responseBody)) |
|
|
| var created apiv3.Meter |
| require.NoError(t, json.Unmarshal(responseBody, &created)) |
|
|
| return &created |
| } |
|
|
| func queryMeterV3(t require.TestingT, address string, meterID string, body apiv3.MeterQueryRequest) *apiv3.MeterQueryResult { |
| if helper, ok := any(t).(interface{ Helper() }); ok { |
| helper.Helper() |
| } |
|
|
| payload, err := json.Marshal(body) |
| require.NoError(t, err) |
|
|
| req, err := http.NewRequestWithContext( |
| context.Background(), |
| http.MethodPost, |
| address+"/openmeter/meters/"+meterID+"/query", |
| bytes.NewReader(payload), |
| ) |
| require.NoError(t, err) |
| req.Header.Set("Content-Type", "application/json") |
|
|
| resp, err := http.DefaultClient.Do(req) |
| require.NoError(t, err) |
| defer resp.Body.Close() |
|
|
| responseBody, err := io.ReadAll(resp.Body) |
| require.NoError(t, err) |
| require.Equal(t, http.StatusOK, resp.StatusCode, "Invalid status code [response_body=%s]", string(responseBody)) |
|
|
| var result apiv3.MeterQueryResult |
| require.NoError(t, json.Unmarshal(responseBody, &result)) |
|
|
| return &result |
| } |
|
|
| func TestQuickstart(t *testing.T) { |
| client := initClient(t) |
| v3Address := openmeterV3Address(t) |
| suffix := fmt.Sprintf("%d", time.Now().UnixNano()) |
| v1MeterSlug := "quickstart_v1_" + suffix |
| v3MeterKey := "quickstart_v3_" + suffix |
|
|
| v1MeterName := "Quickstart V1 Meter" |
| v1CreateResp, err := client.CreateMeterWithResponse(context.Background(), api.CreateMeterJSONRequestBody{ |
| Slug: v1MeterSlug, |
| Name: lo.ToPtr(v1MeterName), |
| Aggregation: api.MeterAggregationCount, |
| EventType: "request", |
| GroupBy: &map[string]string{ |
| "method": "$.method", |
| "route": "$.route", |
| }, |
| }) |
| require.NoError(t, err) |
| require.Equal(t, http.StatusOK, v1CreateResp.StatusCode(), "Invalid status code [response_body=%s]", string(v1CreateResp.Body)) |
|
|
| v3Meter := createMeterV3(t, v3Address, apiv3.CreateMeterRequest{ |
| Key: v3MeterKey, |
| Name: "Quickstart V3 Meter", |
| Aggregation: apiv3.MeterAggregationCount, |
| EventType: "request", |
| Dimensions: &map[string]string{ |
| "method": "$.method", |
| "route": "$.route", |
| }, |
| }) |
|
|
| |
| { |
| ev := cloudevents.New() |
| ev.SetID("00001") |
| ev.SetSource("service-0") |
| ev.SetType("request") |
| ev.SetSubject("customer-1") |
| ev.SetTime(time.Date(2023, time.January, 1, 0, 0, 0, 0, time.UTC)) |
| _ = ev.SetData("application/json", map[string]string{ |
| "method": "GET", |
| "route": "/hello", |
| "duration_ms": "40", |
| }) |
|
|
| require.EventuallyWithT(t, func(t *assert.CollectT) { |
| resp, err := client.IngestEventWithResponse(context.Background(), ev) |
| require.NoError(t, err) |
| require.Equal(t, http.StatusNoContent, resp.StatusCode()) |
| }, 30*time.Second, time.Second) |
| } |
|
|
| { |
| ev := cloudevents.New() |
| ev.SetID("00002") |
| ev.SetSource("service-0") |
| ev.SetType("request") |
| ev.SetSubject("customer-1") |
| ev.SetTime(time.Date(2023, time.January, 1, 0, 0, 0, 0, time.UTC)) |
| _ = ev.SetData("application/json", map[string]string{ |
| "method": "GET", |
| "route": "/hello", |
| "duration_ms": "40", |
| }) |
|
|
| require.EventuallyWithT(t, func(t *assert.CollectT) { |
| resp, err := client.IngestEventWithResponse(context.Background(), ev) |
| require.NoError(t, err) |
| require.Equal(t, http.StatusNoContent, resp.StatusCode()) |
| }, 30*time.Second, time.Second) |
| } |
|
|
| { |
| ev := cloudevents.New() |
| ev.SetID("00003") |
| ev.SetSource("service-0") |
| ev.SetType("request") |
| ev.SetSubject("customer-1") |
| ev.SetTime(time.Date(2023, time.January, 2, 0, 0, 0, 0, time.UTC)) |
| _ = ev.SetData("application/json", map[string]string{ |
| "method": "GET", |
| "route": "/hello", |
| "duration_ms": "40", |
| }) |
|
|
| require.EventuallyWithT(t, func(t *assert.CollectT) { |
| resp, err := client.IngestEventWithResponse(context.Background(), ev) |
| require.NoError(t, err) |
| require.Equal(t, http.StatusNoContent, resp.StatusCode()) |
| }, 30*time.Second, time.Second) |
| } |
|
|
| t.Run("v1", func(t *testing.T) { |
| assert.EventuallyWithT(t, func(t *assert.CollectT) { |
| windowSize := meter.WindowSizeHour |
|
|
| resp, err := client.QueryMeterWithResponse(context.Background(), v1MeterSlug, &api.QueryMeterParams{ |
| WindowSize: lo.ToPtr(api.WindowSize(windowSize)), |
| }) |
| require.NoError(t, err) |
| require.Equal(t, http.StatusOK, resp.StatusCode()) |
|
|
| require.Len(t, resp.JSON200.Data, 2) |
| assert.Equal(t, float64(2), resp.JSON200.Data[0].Value) |
| assert.Equal(t, float64(1), resp.JSON200.Data[1].Value) |
| }, 30*time.Second, time.Second) |
| }) |
|
|
| t.Run("v3", func(t *testing.T) { |
| assert.EventuallyWithT(t, func(t *assert.CollectT) { |
| granularity := apiv3.MeterQueryGranularity("PT1H") |
| resp := queryMeterV3(t, v3Address, v3Meter.Id, apiv3.MeterQueryRequest{ |
| Granularity: &granularity, |
| }) |
|
|
| require.Len(t, resp.Data, 2) |
| assert.Equal(t, apiv3.Numeric("2"), resp.Data[0].Value) |
| assert.Equal(t, apiv3.Numeric("1"), resp.Data[1].Value) |
| }, 30*time.Second, time.Second) |
| }) |
| } |
|
|