Skip to content

Commit 5848ba9

Browse files
test(handlers): update tests for billing_id inference from org_id
Update test cases for ListBillingTransactions, TotalDebitedTransactions, ListInvoices, and GetUpcomingInvoice to mock customerService and test the new behavior where billing_id is inferred from org_id. Changes: - Add customerService mock to all test cases - Update test requests to use org_id instead of billing_id - Add test cases for when billing account is not found - Update test struct definitions to include customerSetup function - Update test runners to initialize customerService mock 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 145b39e commit 5848ba9

File tree

2 files changed

+180
-77
lines changed

2 files changed

+180
-77
lines changed

internal/api/v1beta1connect/billing_invoice_test.go

Lines changed: 87 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"time"
88

99
"connectrpc.com/connect"
10+
"github.com/raystack/frontier/billing/customer"
1011
"github.com/raystack/frontier/billing/invoice"
1112
"github.com/raystack/frontier/internal/api/v1beta1connect/mocks"
1213
"github.com/raystack/frontier/pkg/metadata"
@@ -22,23 +23,27 @@ func TestConnectHandler_ListInvoices(t *testing.T) {
2223
emptyStruct, _ := structpb.NewStruct(map[string]interface{}{})
2324

2425
tests := []struct {
25-
name string
26-
setup func(is *mocks.InvoiceService)
27-
request *connect.Request[frontierv1beta1.ListInvoicesRequest]
28-
want *connect.Response[frontierv1beta1.ListInvoicesResponse]
29-
wantErr error
30-
errCode connect.Code
26+
name string
27+
setup func(is *mocks.InvoiceService)
28+
customerSetup func(custSvc *mocks.CustomerService)
29+
request *connect.Request[frontierv1beta1.ListInvoicesRequest]
30+
want *connect.Response[frontierv1beta1.ListInvoicesResponse]
31+
wantErr error
32+
errCode connect.Code
3133
}{
3234
{
3335
name: "should return internal server error when invoice service returns error",
36+
customerSetup: func(custSvc *mocks.CustomerService) {
37+
custSvc.EXPECT().GetByOrgID(mock.Anything, "org-123").Return(customer.Customer{ID: "customer-id"}, nil)
38+
},
3439
setup: func(is *mocks.InvoiceService) {
3540
is.On("List", mock.Anything, invoice.Filter{
3641
CustomerID: "customer-id",
3742
NonZeroOnly: false,
3843
}).Return(nil, errors.New("service error"))
3944
},
4045
request: connect.NewRequest(&frontierv1beta1.ListInvoicesRequest{
41-
BillingId: "customer-id",
46+
OrgId: "org-123",
4247
NonzeroAmountOnly: false,
4348
}),
4449
want: nil,
@@ -47,14 +52,17 @@ func TestConnectHandler_ListInvoices(t *testing.T) {
4752
},
4853
{
4954
name: "should successfully list invoices with empty result",
55+
customerSetup: func(custSvc *mocks.CustomerService) {
56+
custSvc.EXPECT().GetByOrgID(mock.Anything, "org-123").Return(customer.Customer{ID: "customer-id"}, nil)
57+
},
5058
setup: func(is *mocks.InvoiceService) {
5159
is.On("List", mock.Anything, invoice.Filter{
5260
CustomerID: "customer-id",
5361
NonZeroOnly: false,
5462
}).Return([]invoice.Invoice{}, nil)
5563
},
5664
request: connect.NewRequest(&frontierv1beta1.ListInvoicesRequest{
57-
BillingId: "customer-id",
65+
OrgId: "org-123",
5866
NonzeroAmountOnly: false,
5967
}),
6068
want: connect.NewResponse(&frontierv1beta1.ListInvoicesResponse{
@@ -63,6 +71,9 @@ func TestConnectHandler_ListInvoices(t *testing.T) {
6371
},
6472
{
6573
name: "should successfully list invoices with basic invoice data",
74+
customerSetup: func(custSvc *mocks.CustomerService) {
75+
custSvc.EXPECT().GetByOrgID(mock.Anything, "org-123").Return(customer.Customer{ID: "customer-id"}, nil)
76+
},
6677
setup: func(is *mocks.InvoiceService) {
6778
is.On("List", mock.Anything, invoice.Filter{
6879
CustomerID: "customer-id",
@@ -82,7 +93,7 @@ func TestConnectHandler_ListInvoices(t *testing.T) {
8293
}, nil)
8394
},
8495
request: connect.NewRequest(&frontierv1beta1.ListInvoicesRequest{
85-
BillingId: "customer-id",
96+
OrgId: "org-123",
8697
NonzeroAmountOnly: false,
8798
}),
8899
want: connect.NewResponse(&frontierv1beta1.ListInvoicesResponse{
@@ -103,6 +114,9 @@ func TestConnectHandler_ListInvoices(t *testing.T) {
103114
},
104115
{
105116
name: "should successfully list invoices with nonzero_amount_only filter",
117+
customerSetup: func(custSvc *mocks.CustomerService) {
118+
custSvc.EXPECT().GetByOrgID(mock.Anything, "org-123").Return(customer.Customer{ID: "customer-id"}, nil)
119+
},
106120
setup: func(is *mocks.InvoiceService) {
107121
is.On("List", mock.Anything, invoice.Filter{
108122
CustomerID: "customer-id",
@@ -123,7 +137,7 @@ func TestConnectHandler_ListInvoices(t *testing.T) {
123137
}, nil)
124138
},
125139
request: connect.NewRequest(&frontierv1beta1.ListInvoicesRequest{
126-
BillingId: "customer-id",
140+
OrgId: "org-123",
127141
NonzeroAmountOnly: true,
128142
}),
129143
want: connect.NewResponse(&frontierv1beta1.ListInvoicesResponse{
@@ -145,6 +159,9 @@ func TestConnectHandler_ListInvoices(t *testing.T) {
145159
},
146160
{
147161
name: "should successfully list multiple invoices with all timestamp fields",
162+
customerSetup: func(custSvc *mocks.CustomerService) {
163+
custSvc.EXPECT().GetByOrgID(mock.Anything, "org-123").Return(customer.Customer{ID: "customer-id"}, nil)
164+
},
148165
setup: func(is *mocks.InvoiceService) {
149166
is.On("List", mock.Anything, invoice.Filter{
150167
CustomerID: "customer-id",
@@ -179,7 +196,7 @@ func TestConnectHandler_ListInvoices(t *testing.T) {
179196
}, nil)
180197
},
181198
request: connect.NewRequest(&frontierv1beta1.ListInvoicesRequest{
182-
BillingId: "customer-id",
199+
OrgId: "org-123",
183200
NonzeroAmountOnly: false,
184201
}),
185202
want: connect.NewResponse(&frontierv1beta1.ListInvoicesResponse{
@@ -214,23 +231,24 @@ func TestConnectHandler_ListInvoices(t *testing.T) {
214231
}),
215232
},
216233
{
217-
name: "should handle empty billing_id gracefully",
218-
setup: func(is *mocks.InvoiceService) {
219-
is.On("List", mock.Anything, invoice.Filter{
220-
CustomerID: "",
221-
NonZeroOnly: false,
222-
}).Return([]invoice.Invoice{}, nil)
234+
name: "should return empty list when billing account not found",
235+
customerSetup: func(custSvc *mocks.CustomerService) {
236+
custSvc.EXPECT().GetByOrgID(mock.Anything, "org-123").Return(customer.Customer{}, customer.ErrNotFound)
223237
},
238+
setup: func(is *mocks.InvoiceService) {},
224239
request: connect.NewRequest(&frontierv1beta1.ListInvoicesRequest{
225-
BillingId: "",
240+
OrgId: "org-123",
226241
NonzeroAmountOnly: false,
227242
}),
228243
want: connect.NewResponse(&frontierv1beta1.ListInvoicesResponse{
229-
Invoices: nil,
244+
Invoices: []*frontierv1beta1.Invoice{},
230245
}),
231246
},
232247
{
233248
name: "should return internal error when transformInvoiceToPB fails due to metadata error",
249+
customerSetup: func(custSvc *mocks.CustomerService) {
250+
custSvc.EXPECT().GetByOrgID(mock.Anything, "org-123").Return(customer.Customer{ID: "customer-id"}, nil)
251+
},
234252
setup: func(is *mocks.InvoiceService) {
235253
// Create invoice with metadata that will fail ToStructPB conversion
236254
invalidMetadata := metadata.Metadata{"invalid": make(chan int)} // channels can't be converted to protobuf
@@ -252,7 +270,7 @@ func TestConnectHandler_ListInvoices(t *testing.T) {
252270
}, nil)
253271
},
254272
request: connect.NewRequest(&frontierv1beta1.ListInvoicesRequest{
255-
BillingId: "customer-id",
273+
OrgId: "org-123",
256274
NonzeroAmountOnly: false,
257275
}),
258276
want: nil,
@@ -264,12 +282,17 @@ func TestConnectHandler_ListInvoices(t *testing.T) {
264282
for _, tt := range tests {
265283
t.Run(tt.name, func(t *testing.T) {
266284
mockInvoiceService := &mocks.InvoiceService{}
285+
mockCustomerService := &mocks.CustomerService{}
267286
if tt.setup != nil {
268287
tt.setup(mockInvoiceService)
269288
}
289+
if tt.customerSetup != nil {
290+
tt.customerSetup(mockCustomerService)
291+
}
270292

271293
handler := &ConnectHandler{
272-
invoiceService: mockInvoiceService,
294+
invoiceService: mockInvoiceService,
295+
customerService: mockCustomerService,
273296
}
274297

275298
got, err := handler.ListInvoices(context.Background(), tt.request)
@@ -292,27 +315,34 @@ func TestConnectHandler_GetUpcomingInvoice(t *testing.T) {
292315
emptyStruct, _ := structpb.NewStruct(map[string]interface{}{})
293316

294317
tests := []struct {
295-
name string
296-
setup func(is *mocks.InvoiceService)
297-
request *connect.Request[frontierv1beta1.GetUpcomingInvoiceRequest]
298-
want *connect.Response[frontierv1beta1.GetUpcomingInvoiceResponse]
299-
wantErr error
300-
errCode connect.Code
318+
name string
319+
setup func(is *mocks.InvoiceService)
320+
customerSetup func(custSvc *mocks.CustomerService)
321+
request *connect.Request[frontierv1beta1.GetUpcomingInvoiceRequest]
322+
want *connect.Response[frontierv1beta1.GetUpcomingInvoiceResponse]
323+
wantErr error
324+
errCode connect.Code
301325
}{
302326
{
303327
name: "should return internal server error when invoice service returns error",
328+
customerSetup: func(custSvc *mocks.CustomerService) {
329+
custSvc.EXPECT().GetByOrgID(mock.Anything, "org-123").Return(customer.Customer{ID: "customer-id"}, nil)
330+
},
304331
setup: func(is *mocks.InvoiceService) {
305332
is.On("GetUpcoming", mock.Anything, "customer-id").Return(invoice.Invoice{}, errors.New("service error"))
306333
},
307334
request: connect.NewRequest(&frontierv1beta1.GetUpcomingInvoiceRequest{
308-
BillingId: "customer-id",
335+
OrgId: "org-123",
309336
}),
310337
want: nil,
311338
wantErr: ErrInternalServerError,
312339
errCode: connect.CodeInternal,
313340
},
314341
{
315342
name: "should successfully get upcoming invoice with basic data",
343+
customerSetup: func(custSvc *mocks.CustomerService) {
344+
custSvc.EXPECT().GetByOrgID(mock.Anything, "org-123").Return(customer.Customer{ID: "customer-id"}, nil)
345+
},
316346
setup: func(is *mocks.InvoiceService) {
317347
is.On("GetUpcoming", mock.Anything, "customer-id").Return(invoice.Invoice{
318348
ID: "upcoming-invoice-1",
@@ -327,7 +357,7 @@ func TestConnectHandler_GetUpcomingInvoice(t *testing.T) {
327357
}, nil)
328358
},
329359
request: connect.NewRequest(&frontierv1beta1.GetUpcomingInvoiceRequest{
330-
BillingId: "customer-id",
360+
OrgId: "org-123",
331361
}),
332362
want: connect.NewResponse(&frontierv1beta1.GetUpcomingInvoiceResponse{
333363
Invoice: &frontierv1beta1.Invoice{
@@ -345,6 +375,9 @@ func TestConnectHandler_GetUpcomingInvoice(t *testing.T) {
345375
},
346376
{
347377
name: "should successfully get upcoming invoice with all timestamp fields",
378+
customerSetup: func(custSvc *mocks.CustomerService) {
379+
custSvc.EXPECT().GetByOrgID(mock.Anything, "org-123").Return(customer.Customer{ID: "customer-id"}, nil)
380+
},
348381
setup: func(is *mocks.InvoiceService) {
349382
is.On("GetUpcoming", mock.Anything, "customer-id").Return(invoice.Invoice{
350383
ID: "upcoming-invoice-2",
@@ -363,7 +396,7 @@ func TestConnectHandler_GetUpcomingInvoice(t *testing.T) {
363396
}, nil)
364397
},
365398
request: connect.NewRequest(&frontierv1beta1.GetUpcomingInvoiceRequest{
366-
BillingId: "customer-id",
399+
OrgId: "org-123",
367400
}),
368401
want: connect.NewResponse(&frontierv1beta1.GetUpcomingInvoiceResponse{
369402
Invoice: &frontierv1beta1.Invoice{
@@ -384,19 +417,25 @@ func TestConnectHandler_GetUpcomingInvoice(t *testing.T) {
384417
}),
385418
},
386419
{
387-
name: "should handle empty billing_id gracefully",
388-
setup: func(is *mocks.InvoiceService) {
389-
is.On("GetUpcoming", mock.Anything, "").Return(invoice.Invoice{}, errors.New("billing id required"))
420+
name: "should return empty invoice when billing account not found",
421+
customerSetup: func(custSvc *mocks.CustomerService) {
422+
custSvc.EXPECT().GetByOrgID(mock.Anything, "org-123").Return(customer.Customer{}, customer.ErrNotFound)
390423
},
424+
setup: func(is *mocks.InvoiceService) {},
391425
request: connect.NewRequest(&frontierv1beta1.GetUpcomingInvoiceRequest{
392-
BillingId: "",
426+
OrgId: "org-123",
393427
}),
394-
want: nil,
395-
wantErr: ErrInternalServerError,
396-
errCode: connect.CodeInternal,
428+
want: connect.NewResponse(&frontierv1beta1.GetUpcomingInvoiceResponse{
429+
Invoice: nil,
430+
}),
431+
wantErr: nil,
432+
errCode: connect.Code(0),
397433
},
398434
{
399435
name: "should successfully get zero amount upcoming invoice",
436+
customerSetup: func(custSvc *mocks.CustomerService) {
437+
custSvc.EXPECT().GetByOrgID(mock.Anything, "org-123").Return(customer.Customer{ID: "customer-id"}, nil)
438+
},
400439
setup: func(is *mocks.InvoiceService) {
401440
is.On("GetUpcoming", mock.Anything, "customer-id").Return(invoice.Invoice{
402441
ID: "upcoming-invoice-3",
@@ -411,7 +450,7 @@ func TestConnectHandler_GetUpcomingInvoice(t *testing.T) {
411450
}, nil)
412451
},
413452
request: connect.NewRequest(&frontierv1beta1.GetUpcomingInvoiceRequest{
414-
BillingId: "customer-id",
453+
OrgId: "org-123",
415454
}),
416455
want: connect.NewResponse(&frontierv1beta1.GetUpcomingInvoiceResponse{
417456
Invoice: &frontierv1beta1.Invoice{
@@ -429,6 +468,9 @@ func TestConnectHandler_GetUpcomingInvoice(t *testing.T) {
429468
},
430469
{
431470
name: "should return internal error when transformInvoiceToPB fails due to metadata error",
471+
customerSetup: func(custSvc *mocks.CustomerService) {
472+
custSvc.EXPECT().GetByOrgID(mock.Anything, "org-123").Return(customer.Customer{ID: "customer-id"}, nil)
473+
},
432474
setup: func(is *mocks.InvoiceService) {
433475
// Create invoice with metadata that will fail ToStructPB conversion
434476
invalidMetadata := metadata.Metadata{"invalid": make(chan int)} // channels can't be converted to protobuf
@@ -445,7 +487,7 @@ func TestConnectHandler_GetUpcomingInvoice(t *testing.T) {
445487
}, nil)
446488
},
447489
request: connect.NewRequest(&frontierv1beta1.GetUpcomingInvoiceRequest{
448-
BillingId: "customer-id",
490+
OrgId: "org-123",
449491
}),
450492
want: nil,
451493
wantErr: ErrInternalServerError,
@@ -456,12 +498,17 @@ func TestConnectHandler_GetUpcomingInvoice(t *testing.T) {
456498
for _, tt := range tests {
457499
t.Run(tt.name, func(t *testing.T) {
458500
mockInvoiceService := &mocks.InvoiceService{}
501+
mockCustomerService := &mocks.CustomerService{}
459502
if tt.setup != nil {
460503
tt.setup(mockInvoiceService)
461504
}
505+
if tt.customerSetup != nil {
506+
tt.customerSetup(mockCustomerService)
507+
}
462508

463509
handler := &ConnectHandler{
464-
invoiceService: mockInvoiceService,
510+
invoiceService: mockInvoiceService,
511+
customerService: mockCustomerService,
465512
}
466513

467514
got, err := handler.GetUpcomingInvoice(context.Background(), tt.request)

0 commit comments

Comments
 (0)