-
Notifications
You must be signed in to change notification settings - Fork 129
feat(multi-subject): enable and test #3583
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: feat/multi-subject/entitlement-subject
Are you sure you want to change the base?
feat(multi-subject): enable and test #3583
Conversation
📝 WalkthroughWalkthroughThis PR relaxes CustomerUsageAttribution.subjectKeys from exactly one to zero-or-more, updates API spec and production code to handle zero subjects, adds e2e and integration tests for multi-subject flows, and extends test environment wiring to exercise subscription, meter, and billing workflows for multi-subject scenarios. Changes
Sequence Diagram(s)sequenceDiagram
participant Test
participant CustomerSvc as Customer Service
participant SubscriptionSvc as Subscription Service
participant EntitlementSvc as Entitlement Service
participant MeterAgg as Meter/Aggregation
Test->>CustomerSvc: CreateCustomer(payload with 0..N subjectKeys)
alt subjectKeys length > 0
CustomerSvc->>CustomerSvc: Create subject keys (bulk)
else
CustomerSvc-->>Test: Skip subject-key creation
end
Test->>SubscriptionSvc: CreateSubscription(customer, plan)
SubscriptionSvc->>EntitlementSvc: Create entitlements per subject (if applicable)
Test->>MeterAgg: Ingest usage events for subject A, B, ...
MeterAgg->>MeterAgg: Aggregate usage across subjects
Test->>MeterAgg: Query aggregated usage
MeterAgg-->>Test: Aggregated value = sum across subjects
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Areas to focus review on:
Possibly related PRs
Suggested labels
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro ⛔ Files ignored due to path filters (6)
📒 Files selected for processing (10)
🚧 Files skipped from review as they are similar to previous changes (5)
🧰 Additional context used📓 Path-based instructions (3)**/*.go⚙️ CodeRabbit configuration file
Files:
**/*_test.go⚙️ CodeRabbit configuration file
Files:
**/*.tsp⚙️ CodeRabbit configuration file
Files:
🧠 Learnings (1)📚 Learning: 2025-03-07T12:17:43.129ZApplied to files:
🧬 Code graph analysis (2)test/customer/testenv.go (10)
test/customer/subject.go (17)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (1)
test/customer/subject.go (1)
212-213: Tighten the meter assertion
require.Equal(t, met.Key, met.Key, ...)will always pass, so it’s not giving us any confidence that the lookup returned the right record. Maybe compare the fetched key to the slug you requested (integration-meter) or to the key from theCreateMeterresponse instead. Super minor, but it’ll make the test actually verify the lookup.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (6)
api/client/go/client.gen.gois excluded by!api/client/**api/client/javascript/src/client/schemas.tsis excluded by!api/client/**api/client/javascript/src/zod/index.tsis excluded by!api/client/**api/client/python/openmeter/_generated/models/_models.pyis excluded by!**/_generated/**,!api/client/**api/openapi.cloud.yamlis excluded by!**/openapi.cloud.yamlapi/openapi.yamlis excluded by!**/openapi.yaml
📒 Files selected for processing (10)
api/spec/src/customer/customer.tsp(1 hunks)e2e/config.yaml(1 hunks)e2e/multisubject_test.go(1 hunks)e2e/productcatalog_test.go(1 hunks)openmeter/credit/grant.go(1 hunks)openmeter/customer/adapter/customer.go(1 hunks)test/customer/customer.go(1 hunks)test/customer/customer_test.go(1 hunks)test/customer/subject.go(2 hunks)test/customer/testenv.go(8 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go
⚙️ CodeRabbit configuration file
**/*.go: In general when reviewing the Golang code make readability and maintainability a priority, even potentially suggest restructuring the code to improve them.Performance should be a priority in critical code paths. Anything related to event ingestion, message processing, database operations (regardless of database) should be vetted for potential performance bottlenecks.
Files:
openmeter/customer/adapter/customer.gotest/customer/customer_test.goopenmeter/credit/grant.gotest/customer/customer.goe2e/productcatalog_test.gotest/customer/subject.gotest/customer/testenv.goe2e/multisubject_test.go
**/*_test.go
⚙️ CodeRabbit configuration file
**/*_test.go: Make sure the tests are comprehensive and cover the changes. Keep a strong focus on unit tests and in-code integration tests.
When appropriate, recommend e2e tests for critical changes.
Files:
test/customer/customer_test.goe2e/productcatalog_test.goe2e/multisubject_test.go
**/*.tsp
⚙️ CodeRabbit configuration file
**/*.tsp: Review the TypeSpec code for conformity with TypeSpec best practices. When recommending changes also consider the fact that multiple codegeneration toolchains depend on the TypeSpec code, each of which have their idiosyncrasies and bugs.The declared API should be accurate, in parity with the actual implementation, and easy to understand for the user.
Files:
api/spec/src/customer/customer.tsp
🧠 Learnings (1)
📚 Learning: 2025-03-07T12:17:43.129Z
Learnt from: GAlexIHU
Repo: openmeterio/openmeter PR: 2383
File: openmeter/entitlement/metered/lateevents_test.go:37-45
Timestamp: 2025-03-07T12:17:43.129Z
Learning: In the OpenMeter codebase, test files like `openmeter/entitlement/metered/lateevents_test.go` may use variables like `meterSlug` and `namespace` without explicit declarations visible in the same file. This appears to be an accepted pattern in their test structure.
Applied to files:
e2e/config.yamle2e/productcatalog_test.gotest/customer/subject.gotest/customer/testenv.goe2e/multisubject_test.go
🧬 Code graph analysis (4)
openmeter/customer/adapter/customer.go (3)
openmeter/ent/schema/customer.go (5)
CustomerSubjects(72-74)CustomerSubjects(76-80)CustomerSubjects(82-100)CustomerSubjects(102-119)CustomerSubjects(121-138)openmeter/ent/db/ent.go (1)
IsConstraintError(368-374)openmeter/customer/errors.go (1)
NewSubjectKeyConflictError(67-71)
test/customer/customer.go (3)
openmeter/customer/customer.go (3)
CreateCustomerInput(312-315)CustomerMutate(112-122)CustomerUsageAttribution(200-202)api/api.gen.go (1)
CustomerUsageAttribution(2410-2414)api/client/go/client.gen.go (1)
CustomerUsageAttribution(2239-2243)
test/customer/subject.go (14)
test/customer/customer.go (1)
CustomerHandlerTestSuite(54-58)openmeter/meter/service.go (2)
CreateMeterInput(107-117)GetMeterInput(38-41)openmeter/customer/customer.go (5)
Customer(41-53)CreateCustomerInput(312-315)CustomerMutate(112-122)CustomerUsageAttribution(200-202)CustomerID(147-147)openmeter/productcatalog/feature/connector.go (1)
CreateFeatureInputs(19-26)openmeter/productcatalog/plan/service.go (1)
CreatePlanInput(105-110)openmeter/productcatalog/plan.go (1)
PlanMeta(197-223)pkg/datetime/testutils.go (1)
MustParseDuration(38-45)openmeter/productcatalog/entitlement.go (3)
EntitlementTemplate(34-39)NewEntitlementTemplateFrom(230-246)MeteredEntitlementTemplate(253-273)openmeter/productcatalog/subscription/service/plan.go (1)
PlanFromPlan(76-81)pkg/clock/clock.go (2)
Now(14-21)SetTime(23-27)openmeter/subscription/workflow/service.go (2)
CreateSubscriptionWorkflowInput(23-30)ChangeSubscriptionWorkflowInput(32-39)openmeter/subscription/timing.go (2)
Timing(14-17)TimingImmediate(198-198)openmeter/billing/invoiceline.go (4)
NewFlatFeeLine(473-511)NewFlatFeeLineInput(434-458)WithFeatureKey(466-470)CreatePendingInvoiceLinesInput(701-706)openmeter/billing/invoice.go (1)
InvoicePendingLinesInput(920-929)
test/customer/testenv.go (14)
openmeter/meter/service/service.go (2)
Service(13-15)New(17-23)openmeter/meter/adapter/adapter.go (3)
Adapter(46-49)New(33-42)Config(16-19)openmeter/watermill/eventbus/eventbus.go (2)
NewMock(159-172)Publisher(67-79)openmeter/subscription/service/service.go (2)
New(44-63)ServiceConfig(25-42)openmeter/productcatalog/plan/service/service.go (2)
New(19-42)Config(12-17)pkg/ffx/context.go (1)
NewTestContextService(65-70)openmeter/subscription/repo/subscriptionrepo.go (1)
NewSubscriptionRepo(29-33)openmeter/subscription/addon/repo/subscriptionaddon.go (1)
NewSubscriptionAddonRepo(22-26)openmeter/subscription/addon/repo/subscriptionaddonquantity.go (1)
NewSubscriptionAddonQuantityRepo(18-22)openmeter/subscription/workflow/service/service.go (2)
NewWorkflowService(33-37)WorkflowServiceConfig(17-27)openmeter/app/service.go (1)
AppService(13-35)openmeter/app/sandbox/mock.go (1)
NewMockableFactory(232-264)openmeter/billing/profile.go (8)
CreateProfileInput(329-339)AlignmentKindSubscription(28-28)PaymentConfig(120-122)CollectionMethod(134-134)CollectionMethodChargeAutomatically(138-138)SupplierContact(150-155)CreateProfileAppsInput(365-365)Profile(224-229)pkg/models/model.go (2)
Address(220-228)CountryCode(231-231)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: Artifacts / Container image
- GitHub Check: Lint
- GitHub Check: Migration Checks
- GitHub Check: Code Generators
- GitHub Check: Test
- GitHub Check: Build
| ffService := ffx.NewTestContextService(ffx.AccessConfig{ | ||
| subscription.MultiSubscriptionEnabledFF: false, | ||
| }) | ||
|
|
||
| subRepo := subscriptionrepo.NewSubscriptionRepo(dbDeps.DBClient) | ||
| subPhaseRepo := subscriptionrepo.NewSubscriptionPhaseRepo(dbDeps.DBClient) | ||
| subItemRepo := subscriptionrepo.NewSubscriptionItemRepo(dbDeps.DBClient) | ||
|
|
||
| entitlementAdapter := subscriptionentitlement.NewSubscriptionEntitlementAdapter( | ||
| entitlementRegistry.Entitlement, | ||
| subItemRepo, | ||
| subPhaseRepo, | ||
| ) | ||
|
|
||
| svc, err := subscriptionservice.New(subscriptionservice.ServiceConfig{ | ||
| SubscriptionRepo: subRepo, | ||
| SubscriptionPhaseRepo: subPhaseRepo, | ||
| SubscriptionItemRepo: subItemRepo, | ||
| CustomerService: customerService, | ||
| EntitlementAdapter: entitlementAdapter, | ||
| FeatureService: entitlementRegistry.Feature, | ||
| TransactionManager: subItemRepo, | ||
| Publisher: publisher, | ||
| Lockr: locker, | ||
| FeatureFlags: ffService, | ||
| }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Flip the multi-subscription flag on.
Right now we're wiring up the subscription service with MultiSubscriptionEnabledFF set to false, but the new multi-subject flows still check this feature flag before accepting multiple subject keys. Leaving it disabled means the env we just expanded will reject the very scenarios these tests are trying to exercise (you'll see validation failures instead of the new behavior). Let's flip it to true so the test harness actually runs with multi-subject enabled.
- ffService := ffx.NewTestContextService(ffx.AccessConfig{
- subscription.MultiSubscriptionEnabledFF: false,
- })
+ ffService := ffx.NewTestContextService(ffx.AccessConfig{
+ subscription.MultiSubscriptionEnabledFF: true,
+ })📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ffService := ffx.NewTestContextService(ffx.AccessConfig{ | |
| subscription.MultiSubscriptionEnabledFF: false, | |
| }) | |
| subRepo := subscriptionrepo.NewSubscriptionRepo(dbDeps.DBClient) | |
| subPhaseRepo := subscriptionrepo.NewSubscriptionPhaseRepo(dbDeps.DBClient) | |
| subItemRepo := subscriptionrepo.NewSubscriptionItemRepo(dbDeps.DBClient) | |
| entitlementAdapter := subscriptionentitlement.NewSubscriptionEntitlementAdapter( | |
| entitlementRegistry.Entitlement, | |
| subItemRepo, | |
| subPhaseRepo, | |
| ) | |
| svc, err := subscriptionservice.New(subscriptionservice.ServiceConfig{ | |
| SubscriptionRepo: subRepo, | |
| SubscriptionPhaseRepo: subPhaseRepo, | |
| SubscriptionItemRepo: subItemRepo, | |
| CustomerService: customerService, | |
| EntitlementAdapter: entitlementAdapter, | |
| FeatureService: entitlementRegistry.Feature, | |
| TransactionManager: subItemRepo, | |
| Publisher: publisher, | |
| Lockr: locker, | |
| FeatureFlags: ffService, | |
| }) | |
| ffService := ffx.NewTestContextService(ffx.AccessConfig{ | |
| subscription.MultiSubscriptionEnabledFF: true, | |
| }) | |
| subRepo := subscriptionrepo.NewSubscriptionRepo(dbDeps.DBClient) | |
| subPhaseRepo := subscriptionrepo.NewSubscriptionPhaseRepo(dbDeps.DBClient) | |
| subItemRepo := subscriptionrepo.NewSubscriptionItemRepo(dbDeps.DBClient) | |
| entitlementAdapter := subscriptionentitlement.NewSubscriptionEntitlementAdapter( | |
| entitlementRegistry.Entitlement, | |
| subItemRepo, | |
| subPhaseRepo, | |
| ) | |
| svc, err := subscriptionservice.New(subscriptionservice.ServiceConfig{ | |
| SubscriptionRepo: subRepo, | |
| SubscriptionPhaseRepo: subPhaseRepo, | |
| SubscriptionItemRepo: subItemRepo, | |
| CustomerService: customerService, | |
| EntitlementAdapter: entitlementAdapter, | |
| FeatureService: entitlementRegistry.Feature, | |
| TransactionManager: subItemRepo, | |
| Publisher: publisher, | |
| Lockr: locker, | |
| FeatureFlags: ffService, | |
| }) |
🤖 Prompt for AI Agents
In test/customer/testenv.go around lines 279 to 304, the test environment
initializes ffService with MultiSubscriptionEnabledFF set to false which
prevents the new multi-subject flows from running; change the flag to true
(ffx.AccessConfig{ subscription.MultiSubscriptionEnabledFF: true }) so the
subscription service is wired with the multi-subscription feature enabled and
the tests exercise the intended multi-subject behavior.
d728430 to
33e1c2c
Compare
^ Conflicts: ^ api/api.gen.go ^ api/client/go/client.gen.go
e918bf3 to
508ba59
Compare
Overview
Enables multi-subject in validation layer & API typings + adds TestSuite around functionality change
The tests use a subscription based approach, basically we validate that:
Summary by CodeRabbit
New Features
Tests