Compare commits

...

1 Commits

Author SHA1 Message Date
Zach Kipp 136d0843e4 test: improve test coverage for boundary usage tracking 2026-01-29 16:40:15 -07:00
4 changed files with 357 additions and 21 deletions
+33 -5
View File
@@ -19,6 +19,9 @@ import (
"github.com/coder/coder/v2/agent/boundarylogproxy/codec"
agentproto "github.com/coder/coder/v2/agent/proto"
"github.com/coder/coder/v2/coderd/agentapi"
"github.com/coder/coder/v2/coderd/boundaryusage"
"github.com/coder/coder/v2/coderd/database/dbauthz"
"github.com/coder/coder/v2/coderd/database/dbtestutil"
"github.com/coder/coder/v2/testutil"
)
@@ -64,27 +67,37 @@ func sendBoundaryLogsRequest(t *testing.T, conn net.Conn, req *agentproto.Report
// TestBoundaryLogs_EndToEnd is an end-to-end test that sends a protobuf
// message over the agent's unix socket (as boundary would) and verifies
// it is ultimately logged by coderd with the correct structured fields.
// it is ultimately logged by coderd with the correct structured fields
// and that usage statistics are tracked properly.
func TestBoundaryLogs_EndToEnd(t *testing.T) {
t.Parallel()
db, _ := dbtestutil.NewDB(t)
socketPath := filepath.Join(testutil.TempDirUnixSocket(t), "boundary.sock")
srv := boundarylogproxy.NewServer(testutil.Logger(t), socketPath)
err := srv.Start()
require.NoError(t, err)
t.Cleanup(func() { require.NoError(t, srv.Close()) })
const maxStalenessMs = 60000
sink := &logSink{}
logger := slog.Make(sink)
workspaceID := uuid.New()
ownerID := uuid.New()
templateID := uuid.New()
templateVersionID := uuid.New()
replicaID := uuid.New()
tracker := boundaryusage.NewTracker()
reporter := &agentapi.BoundaryLogsAPI{
Log: logger,
WorkspaceID: workspaceID,
TemplateID: templateID,
TemplateVersionID: templateVersionID,
Log: logger,
WorkspaceID: workspaceID,
OwnerID: ownerID,
TemplateID: templateID,
TemplateVersionID: templateVersionID,
BoundaryUsageTracker: tracker,
}
ctx, cancel := context.WithCancel(context.Background())
@@ -169,4 +182,19 @@ func TestBoundaryLogs_EndToEnd(t *testing.T) {
cancel()
<-forwarderDone
// Verify usage tracking: flush tracker to database and check counts.
// Use a fresh context since the forwarder context has been canceled.
dbCtx := testutil.Context(t, testutil.WaitShort)
err = tracker.FlushToDB(dbCtx, db, replicaID)
require.NoError(t, err)
boundaryCtx := dbauthz.AsBoundaryUsageTracker(dbCtx)
summary, err := db.GetBoundaryUsageSummary(boundaryCtx, maxStalenessMs)
require.NoError(t, err)
require.Equal(t, int64(1), summary.UniqueWorkspaces)
require.Equal(t, int64(1), summary.UniqueUsers)
require.Equal(t, int64(1), summary.AllowedRequests)
require.Equal(t, int64(1), summary.DeniedRequests)
}
+233
View File
@@ -0,0 +1,233 @@
package agentapi_test
import (
"testing"
"github.com/google/uuid"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/types/known/timestamppb"
"cdr.dev/slog/v3"
"cdr.dev/slog/v3/sloggers/slogtest"
agentproto "github.com/coder/coder/v2/agent/proto"
"github.com/coder/coder/v2/coderd/agentapi"
"github.com/coder/coder/v2/coderd/boundaryusage"
"github.com/coder/coder/v2/coderd/database/dbauthz"
"github.com/coder/coder/v2/coderd/database/dbtestutil"
"github.com/coder/coder/v2/testutil"
)
const testMaxStalenessMs = 60000
func TestBoundaryLogsAPI_ReportBoundaryLogs_MultipleBatches(t *testing.T) {
t.Parallel()
db, _ := dbtestutil.NewDB(t)
ctx := testutil.Context(t, testutil.WaitShort)
tracker := boundaryusage.NewTracker()
workspaceID := uuid.New()
ownerID := uuid.New()
replicaID := uuid.New()
api := &agentapi.BoundaryLogsAPI{
Log: slogtest.Make(t, nil).Leveled(slog.LevelDebug),
WorkspaceID: workspaceID,
OwnerID: ownerID,
TemplateID: uuid.New(),
TemplateVersionID: uuid.New(),
BoundaryUsageTracker: tracker,
}
// First batch: 3 allowed, 1 denied.
req1 := &agentproto.ReportBoundaryLogsRequest{
Logs: []*agentproto.BoundaryLog{
{Allowed: true, Time: timestamppb.Now(), Resource: &agentproto.BoundaryLog_HttpRequest_{HttpRequest: &agentproto.BoundaryLog_HttpRequest{Method: "GET", Url: "https://a.com"}}},
{Allowed: true, Time: timestamppb.Now(), Resource: &agentproto.BoundaryLog_HttpRequest_{HttpRequest: &agentproto.BoundaryLog_HttpRequest{Method: "GET", Url: "https://b.com"}}},
{Allowed: true, Time: timestamppb.Now(), Resource: &agentproto.BoundaryLog_HttpRequest_{HttpRequest: &agentproto.BoundaryLog_HttpRequest{Method: "GET", Url: "https://c.com"}}},
{Allowed: false, Time: timestamppb.Now(), Resource: &agentproto.BoundaryLog_HttpRequest_{HttpRequest: &agentproto.BoundaryLog_HttpRequest{Method: "GET", Url: "https://blocked.com"}}},
},
}
_, err := api.ReportBoundaryLogs(ctx, req1)
require.NoError(t, err)
// Second batch: 1 allowed, 2 denied.
req2 := &agentproto.ReportBoundaryLogsRequest{
Logs: []*agentproto.BoundaryLog{
{Allowed: true, Time: timestamppb.Now(), Resource: &agentproto.BoundaryLog_HttpRequest_{HttpRequest: &agentproto.BoundaryLog_HttpRequest{Method: "GET", Url: "https://a.com"}}},
{Allowed: false, Time: timestamppb.Now(), Resource: &agentproto.BoundaryLog_HttpRequest_{HttpRequest: &agentproto.BoundaryLog_HttpRequest{Method: "GET", Url: "https://blocked1.com"}}},
{Allowed: false, Time: timestamppb.Now(), Resource: &agentproto.BoundaryLog_HttpRequest_{HttpRequest: &agentproto.BoundaryLog_HttpRequest{Method: "GET", Url: "https://blocked2.com"}}},
},
}
_, err = api.ReportBoundaryLogs(ctx, req2)
require.NoError(t, err)
err = tracker.FlushToDB(ctx, db, replicaID)
require.NoError(t, err)
boundaryCtx := dbauthz.AsBoundaryUsageTracker(ctx)
summary, err := db.GetBoundaryUsageSummary(boundaryCtx, testMaxStalenessMs)
require.NoError(t, err)
require.Equal(t, int64(1), summary.UniqueWorkspaces)
require.Equal(t, int64(1), summary.UniqueUsers)
require.Equal(t, int64(3+1), summary.AllowedRequests)
require.Equal(t, int64(1+2), summary.DeniedRequests)
}
func TestBoundaryLogsAPI_ReportBoundaryLogs_EmptyRequest(t *testing.T) {
t.Parallel()
db, _ := dbtestutil.NewDB(t)
ctx := testutil.Context(t, testutil.WaitShort)
tracker := boundaryusage.NewTracker()
replicaID := uuid.New()
api := &agentapi.BoundaryLogsAPI{
Log: slogtest.Make(t, nil).Leveled(slog.LevelDebug),
WorkspaceID: uuid.New(),
OwnerID: uuid.New(),
TemplateID: uuid.New(),
TemplateVersionID: uuid.New(),
BoundaryUsageTracker: tracker,
}
// Send an empty request with no logs, then flush and verify no usage was
// tracked.
req := &agentproto.ReportBoundaryLogsRequest{
Logs: []*agentproto.BoundaryLog{},
}
_, err := api.ReportBoundaryLogs(ctx, req)
require.NoError(t, err)
err = tracker.FlushToDB(ctx, db, replicaID)
require.NoError(t, err)
boundaryCtx := dbauthz.AsBoundaryUsageTracker(ctx)
summary, err := db.GetBoundaryUsageSummary(boundaryCtx, testMaxStalenessMs)
require.NoError(t, err)
require.Equal(t, int64(0), summary.UniqueWorkspaces)
require.Equal(t, int64(0), summary.UniqueUsers)
require.Equal(t, int64(0), summary.AllowedRequests)
require.Equal(t, int64(0), summary.DeniedRequests)
}
func TestBoundaryLogsAPI_ReportBoundaryLogs_InvalidLogs(t *testing.T) {
t.Parallel()
db, _ := dbtestutil.NewDB(t)
ctx := testutil.Context(t, testutil.WaitShort)
tracker := boundaryusage.NewTracker()
replicaID := uuid.New()
api := &agentapi.BoundaryLogsAPI{
Log: slogtest.Make(t, nil).Leveled(slog.LevelDebug),
WorkspaceID: uuid.New(),
OwnerID: uuid.New(),
TemplateID: uuid.New(),
TemplateVersionID: uuid.New(),
BoundaryUsageTracker: tracker,
}
req := &agentproto.ReportBoundaryLogsRequest{
Logs: []*agentproto.BoundaryLog{
{
Allowed: true,
Time: timestamppb.Now(),
Resource: &agentproto.BoundaryLog_HttpRequest_{
HttpRequest: nil, // Invalid: nil HTTP request
},
},
{
Allowed: true,
Time: timestamppb.Now(),
Resource: &agentproto.BoundaryLog_HttpRequest_{
HttpRequest: &agentproto.BoundaryLog_HttpRequest{
Method: "GET",
Url: "https://valid.com",
},
},
},
},
}
_, err := api.ReportBoundaryLogs(ctx, req)
require.NoError(t, err)
// Flush and verify only the valid log was tracked.
err = tracker.FlushToDB(ctx, db, replicaID)
require.NoError(t, err)
boundaryCtx := dbauthz.AsBoundaryUsageTracker(ctx)
summary, err := db.GetBoundaryUsageSummary(boundaryCtx, testMaxStalenessMs)
require.NoError(t, err)
require.Equal(t, int64(1), summary.UniqueWorkspaces)
require.Equal(t, int64(1), summary.UniqueUsers)
require.Equal(t, int64(1), summary.AllowedRequests)
require.Equal(t, int64(0), summary.DeniedRequests)
}
func TestBoundaryLogsAPI_ReportBoundaryLogs_MultipleWorkspaces(t *testing.T) {
t.Parallel()
db, _ := dbtestutil.NewDB(t)
ctx := testutil.Context(t, testutil.WaitShort)
tracker := boundaryusage.NewTracker()
replicaID := uuid.New()
// Simulate multiple workspaces reporting through different API instances.
workspace1, workspace2 := uuid.New(), uuid.New()
owner1, owner2 := uuid.New(), uuid.New()
api1 := &agentapi.BoundaryLogsAPI{
Log: slogtest.Make(t, nil).Leveled(slog.LevelDebug),
WorkspaceID: workspace1,
OwnerID: owner1,
TemplateID: uuid.New(),
TemplateVersionID: uuid.New(),
BoundaryUsageTracker: tracker,
}
api2 := &agentapi.BoundaryLogsAPI{
Log: slogtest.Make(t, nil).Leveled(slog.LevelDebug),
WorkspaceID: workspace2,
OwnerID: owner2,
TemplateID: uuid.New(),
TemplateVersionID: uuid.New(),
BoundaryUsageTracker: tracker,
}
req := &agentproto.ReportBoundaryLogsRequest{
Logs: []*agentproto.BoundaryLog{
{Allowed: true, Time: timestamppb.Now(), Resource: &agentproto.BoundaryLog_HttpRequest_{HttpRequest: &agentproto.BoundaryLog_HttpRequest{Method: "GET", Url: "https://example.com"}}},
{Allowed: false, Time: timestamppb.Now(), Resource: &agentproto.BoundaryLog_HttpRequest_{HttpRequest: &agentproto.BoundaryLog_HttpRequest{Method: "GET", Url: "https://blocked.com"}}},
},
}
_, err := api1.ReportBoundaryLogs(ctx, req)
require.NoError(t, err)
_, err = api2.ReportBoundaryLogs(ctx, req)
require.NoError(t, err)
// Flush and verify both workspaces are tracked.
err = tracker.FlushToDB(ctx, db, replicaID)
require.NoError(t, err)
boundaryCtx := dbauthz.AsBoundaryUsageTracker(ctx)
summary, err := db.GetBoundaryUsageSummary(boundaryCtx, testMaxStalenessMs)
require.NoError(t, err)
require.Equal(t, int64(2), summary.UniqueWorkspaces)
require.Equal(t, int64(2), summary.UniqueUsers)
require.Equal(t, int64(1+1), summary.AllowedRequests)
require.Equal(t, int64(1+1), summary.DeniedRequests)
}
+20 -16
View File
@@ -16,6 +16,10 @@ import (
"github.com/coder/coder/v2/testutil"
)
// testMaxStalenessMs is the maximum staleness in milliseconds for boundary
// usage stats queries in tests.
const testMaxStalenessMs = 60000
func TestMain(m *testing.M) {
goleak.VerifyTestMain(m, testutil.GoleakOptions...)
}
@@ -45,7 +49,7 @@ func TestTracker_Track_Single(t *testing.T) {
// Verify the data was written correctly.
boundaryCtx := dbauthz.AsBoundaryUsageTracker(ctx)
summary, err := db.GetBoundaryUsageSummary(boundaryCtx, 60000)
summary, err := db.GetBoundaryUsageSummary(boundaryCtx, testMaxStalenessMs)
require.NoError(t, err)
require.Equal(t, int64(1), summary.UniqueWorkspaces)
require.Equal(t, int64(1), summary.UniqueUsers)
@@ -73,7 +77,7 @@ func TestTracker_Track_DuplicateWorkspaceUser(t *testing.T) {
require.NoError(t, err)
boundaryCtx := dbauthz.AsBoundaryUsageTracker(ctx)
summary, err := db.GetBoundaryUsageSummary(boundaryCtx, 60000)
summary, err := db.GetBoundaryUsageSummary(boundaryCtx, testMaxStalenessMs)
require.NoError(t, err)
require.Equal(t, int64(1), summary.UniqueWorkspaces, "should be 1 unique workspace")
require.Equal(t, int64(1), summary.UniqueUsers, "should be 1 unique user")
@@ -102,7 +106,7 @@ func TestTracker_Track_MultipleWorkspacesUsers(t *testing.T) {
require.NoError(t, err)
boundaryCtx := dbauthz.AsBoundaryUsageTracker(ctx)
summary, err := db.GetBoundaryUsageSummary(boundaryCtx, 60000)
summary, err := db.GetBoundaryUsageSummary(boundaryCtx, testMaxStalenessMs)
require.NoError(t, err)
require.Equal(t, int64(3), summary.UniqueWorkspaces)
require.Equal(t, int64(2), summary.UniqueUsers)
@@ -140,7 +144,7 @@ func TestTracker_Track_Concurrent(t *testing.T) {
require.NoError(t, err)
boundaryCtx := dbauthz.AsBoundaryUsageTracker(ctx)
summary, err := db.GetBoundaryUsageSummary(boundaryCtx, 60000)
summary, err := db.GetBoundaryUsageSummary(boundaryCtx, testMaxStalenessMs)
require.NoError(t, err)
require.Equal(t, int64(numGoroutines), summary.UniqueWorkspaces)
require.Equal(t, int64(numGoroutines), summary.UniqueUsers)
@@ -180,7 +184,7 @@ func TestTracker_FlushToDB_Accumulates(t *testing.T) {
require.NoError(t, err)
boundaryCtx := dbauthz.AsBoundaryUsageTracker(ctx)
summary, err := db.GetBoundaryUsageSummary(boundaryCtx, 60000)
summary, err := db.GetBoundaryUsageSummary(boundaryCtx, testMaxStalenessMs)
require.NoError(t, err)
require.Equal(t, int64(1), summary.UniqueWorkspaces)
require.Equal(t, int64(1), summary.UniqueUsers)
@@ -220,7 +224,7 @@ func TestTracker_FlushToDB_NewPeriod(t *testing.T) {
require.NoError(t, err)
// The summary should only contain the new data after reset.
summary, err := db.GetBoundaryUsageSummary(boundaryCtx, 60000)
summary, err := db.GetBoundaryUsageSummary(boundaryCtx, testMaxStalenessMs)
require.NoError(t, err)
require.Equal(t, int64(1), summary.UniqueWorkspaces, "should only count new workspace")
require.Equal(t, int64(1), summary.UniqueUsers, "should only count new user")
@@ -242,7 +246,7 @@ func TestTracker_FlushToDB_NoActivity(t *testing.T) {
// Verify nothing was written to DB.
boundaryCtx := dbauthz.AsBoundaryUsageTracker(ctx)
summary, err := db.GetBoundaryUsageSummary(boundaryCtx, 60000)
summary, err := db.GetBoundaryUsageSummary(boundaryCtx, testMaxStalenessMs)
require.NoError(t, err)
require.Equal(t, int64(0), summary.UniqueWorkspaces)
require.Equal(t, int64(0), summary.AllowedRequests)
@@ -297,7 +301,7 @@ func TestUpsertBoundaryUsageStats_Update(t *testing.T) {
require.False(t, newPeriod, "should return false for update")
// Verify the update took effect.
summary, err := db.GetBoundaryUsageSummary(ctx, 60000)
summary, err := db.GetBoundaryUsageSummary(ctx, testMaxStalenessMs)
require.NoError(t, err)
require.Equal(t, int64(8), summary.UniqueWorkspaces)
require.Equal(t, int64(5), summary.UniqueUsers)
@@ -343,7 +347,7 @@ func TestGetBoundaryUsageSummary_MultipleReplicas(t *testing.T) {
})
require.NoError(t, err)
summary, err := db.GetBoundaryUsageSummary(ctx, 60000)
summary, err := db.GetBoundaryUsageSummary(ctx, testMaxStalenessMs)
require.NoError(t, err)
// Verify aggregation (SUM of all replicas).
@@ -359,7 +363,7 @@ func TestGetBoundaryUsageSummary_Empty(t *testing.T) {
db, _ := dbtestutil.NewDB(t)
ctx := dbauthz.AsBoundaryUsageTracker(context.Background())
summary, err := db.GetBoundaryUsageSummary(ctx, 60000)
summary, err := db.GetBoundaryUsageSummary(ctx, testMaxStalenessMs)
require.NoError(t, err)
// COALESCE should return 0 for all columns.
@@ -388,7 +392,7 @@ func TestResetBoundaryUsageStats(t *testing.T) {
}
// Verify data exists.
summary, err := db.GetBoundaryUsageSummary(ctx, 60000)
summary, err := db.GetBoundaryUsageSummary(ctx, testMaxStalenessMs)
require.NoError(t, err)
require.Greater(t, summary.AllowedRequests, int64(0))
@@ -397,7 +401,7 @@ func TestResetBoundaryUsageStats(t *testing.T) {
require.NoError(t, err)
// Verify all data is gone.
summary, err = db.GetBoundaryUsageSummary(ctx, 60000)
summary, err = db.GetBoundaryUsageSummary(ctx, testMaxStalenessMs)
require.NoError(t, err)
require.Equal(t, int64(0), summary.UniqueWorkspaces)
require.Equal(t, int64(0), summary.AllowedRequests)
@@ -436,7 +440,7 @@ func TestDeleteBoundaryUsageStatsByReplicaID(t *testing.T) {
require.NoError(t, err)
// Verify only replica2's stats remain.
summary, err := db.GetBoundaryUsageSummary(ctx, 60000)
summary, err := db.GetBoundaryUsageSummary(ctx, testMaxStalenessMs)
require.NoError(t, err)
require.Equal(t, int64(20), summary.UniqueWorkspaces)
require.Equal(t, int64(200), summary.AllowedRequests)
@@ -474,7 +478,7 @@ func TestTracker_TelemetryCycle(t *testing.T) {
require.NoError(t, tracker3.FlushToDB(ctx, db, replica3))
// Telemetry aggregates.
summary, err := db.GetBoundaryUsageSummary(boundaryCtx, 60000)
summary, err := db.GetBoundaryUsageSummary(boundaryCtx, testMaxStalenessMs)
require.NoError(t, err)
// Verify aggregation.
@@ -491,7 +495,7 @@ func TestTracker_TelemetryCycle(t *testing.T) {
require.NoError(t, tracker1.FlushToDB(ctx, db, replica1))
// Verify trackers reset their in-memory state.
summary, err = db.GetBoundaryUsageSummary(boundaryCtx, 60000)
summary, err = db.GetBoundaryUsageSummary(boundaryCtx, testMaxStalenessMs)
require.NoError(t, err)
require.Equal(t, int64(1), summary.UniqueWorkspaces)
require.Equal(t, int64(1), summary.AllowedRequests)
@@ -535,7 +539,7 @@ func TestTracker_ConcurrentFlushAndTrack(t *testing.T) {
// Verify stats are non-negative.
boundaryCtx := dbauthz.AsBoundaryUsageTracker(ctx)
summary, err := db.GetBoundaryUsageSummary(boundaryCtx, 60000)
summary, err := db.GetBoundaryUsageSummary(boundaryCtx, testMaxStalenessMs)
require.NoError(t, err)
require.GreaterOrEqual(t, summary.AllowedRequests, int64(0))
require.GreaterOrEqual(t, summary.DeniedRequests, int64(0))
+71
View File
@@ -17,8 +17,12 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/goleak"
"google.golang.org/protobuf/types/known/timestamppb"
"cdr.dev/slog/v3/sloggers/slogtest"
agentproto "github.com/coder/coder/v2/agent/proto"
"github.com/coder/coder/v2/buildinfo"
"github.com/coder/coder/v2/coderd/agentapi"
"github.com/coder/coder/v2/coderd/boundaryusage"
"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/database/dbauthz"
@@ -969,4 +973,71 @@ func TestTelemetry_BoundaryUsageSummary(t *testing.T) {
// claimed the lock for this period.
require.Nil(t, snapshot2.BoundaryUsageSummary)
})
t.Run("WithBoundaryLogsAPI", func(t *testing.T) {
t.Parallel()
db, _ := dbtestutil.NewDB(t)
ctx := testutil.Context(t, testutil.WaitMedium)
// Create a tracker and BoundaryLogsAPI to simulate the full production
// path: Agent -> ReportBoundaryLogs -> Tracker -> DB -> Telemetry.
tracker := boundaryusage.NewTracker()
replicaID := uuid.New()
workspace1, workspace2 := uuid.New(), uuid.New()
owner1, owner2 := uuid.New(), uuid.New()
api1 := &agentapi.BoundaryLogsAPI{
Log: slogtest.Make(t, nil),
WorkspaceID: workspace1,
OwnerID: owner1,
TemplateID: uuid.New(),
TemplateVersionID: uuid.New(),
BoundaryUsageTracker: tracker,
}
api2 := &agentapi.BoundaryLogsAPI{
Log: slogtest.Make(t, nil),
WorkspaceID: workspace2,
OwnerID: owner2,
TemplateID: uuid.New(),
TemplateVersionID: uuid.New(),
BoundaryUsageTracker: tracker,
}
// Simulate boundary logs from workspace 1: 1 allowed, 2 denied.
req1 := &agentproto.ReportBoundaryLogsRequest{
Logs: []*agentproto.BoundaryLog{
{Allowed: true, Time: timestamppb.Now(), Resource: &agentproto.BoundaryLog_HttpRequest_{HttpRequest: &agentproto.BoundaryLog_HttpRequest{Method: "GET", Url: "https://a.com"}}},
{Allowed: false, Time: timestamppb.Now(), Resource: &agentproto.BoundaryLog_HttpRequest_{HttpRequest: &agentproto.BoundaryLog_HttpRequest{Method: "GET", Url: "https://blocked1.com"}}},
{Allowed: false, Time: timestamppb.Now(), Resource: &agentproto.BoundaryLog_HttpRequest_{HttpRequest: &agentproto.BoundaryLog_HttpRequest{Method: "GET", Url: "https://blocked2.com"}}},
},
}
_, err := api1.ReportBoundaryLogs(ctx, req1)
require.NoError(t, err)
// Simulate boundary logs from workspace 2: 3 allowed, 1 denied.
req2 := &agentproto.ReportBoundaryLogsRequest{
Logs: []*agentproto.BoundaryLog{
{Allowed: true, Time: timestamppb.Now(), Resource: &agentproto.BoundaryLog_HttpRequest_{HttpRequest: &agentproto.BoundaryLog_HttpRequest{Method: "GET", Url: "https://f.com"}}},
{Allowed: true, Time: timestamppb.Now(), Resource: &agentproto.BoundaryLog_HttpRequest_{HttpRequest: &agentproto.BoundaryLog_HttpRequest{Method: "GET", Url: "https://g.com"}}},
{Allowed: true, Time: timestamppb.Now(), Resource: &agentproto.BoundaryLog_HttpRequest_{HttpRequest: &agentproto.BoundaryLog_HttpRequest{Method: "GET", Url: "https://h.com"}}},
{Allowed: false, Time: timestamppb.Now(), Resource: &agentproto.BoundaryLog_HttpRequest_{HttpRequest: &agentproto.BoundaryLog_HttpRequest{Method: "GET", Url: "https://blocked3.com"}}},
},
}
_, err = api2.ReportBoundaryLogs(ctx, req2)
require.NoError(t, err)
err = tracker.FlushToDB(ctx, db, replicaID)
require.NoError(t, err)
_, snapshot := collectSnapshot(ctx, t, db, nil)
require.NotNil(t, snapshot.BoundaryUsageSummary)
require.Equal(t, int64(2), snapshot.BoundaryUsageSummary.UniqueWorkspaces)
require.Equal(t, int64(2), snapshot.BoundaryUsageSummary.UniqueUsers)
require.Equal(t, int64(1+3), snapshot.BoundaryUsageSummary.AllowedRequests)
require.Equal(t, int64(2+1), snapshot.BoundaryUsageSummary.DeniedRequests)
})
}