diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2cc5af06..658f3b52 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,15 +17,10 @@ env: jobs: build: runs-on: ubuntu-latest - strategy: - matrix: - go-version: [ '1.18', '1.19', '1.20', '1.21.x' ] steps: - uses: actions/checkout@v4 - name: Setup Go uses: actions/setup-go@v4 - with: - go-version: ${{ matrix.go-version }} - name: Install dependencies run: | go get . diff --git a/go.sum b/go.sum new file mode 100644 index 00000000..7c6a0d4a --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/apimatic/go-core-runtime v0.0.13 h1:KBrOoUbgdIYbjH+TrQNXkbK7QGBovdX43wr7q5Ta6yE= +github.com/apimatic/go-core-runtime v0.0.13/go.mod h1:kyqGg2v3OTV7o2fXHgbHLZPMinqZvIqw1JwdEd64OzM= diff --git a/test/api_test.go b/test/api_test.go index ccb615ec..21000c9e 100644 --- a/test/api_test.go +++ b/test/api_test.go @@ -1,16 +1,11 @@ package test import ( - "context" - "fmt" - "net/http" "testing" - "time" "github.com/caarlos0/env/v10" "github.com/jaswdr/faker" advancedbilling "github.com/maxio-com/ab-golang-sdk" - "github.com/maxio-com/ab-golang-sdk/models" "github.com/stretchr/testify/suite" ) @@ -21,7 +16,7 @@ type Config struct { Subdomain string `env:"TEST_SUBDOMAIN,required"` } -type APITestSuite struct { +type APISuite struct { suite.Suite fkr faker.Faker @@ -29,7 +24,11 @@ type APITestSuite struct { unauthorizedClient advancedbilling.ClientInterface } -func (s *APITestSuite) SetupTest() { +func TestAPITestSuite(t *testing.T) { + suite.Run(t, new(APISuite)) +} + +func (s *APISuite) SetupTest() { s.fkr = faker.New() cfg := Config{} @@ -52,156 +51,3 @@ func (s *APITestSuite) SetupTest() { s.client = advancedbilling.NewClient(config) s.unauthorizedClient = advancedbilling.NewClient(configUnauthorized) } - -func TestAPITestSuite(t *testing.T) { - suite.Run(t, new(APITestSuite)) -} - -func (s *APITestSuite) createCustomer(ctx context.Context) models.Customer { - person := s.fkr.Person() - - resp, err := s.client.CustomersController().CreateCustomer(ctx, &models.CreateCustomerRequest{ - Customer: models.CreateCustomer{ - FirstName: person.FirstName(), - LastName: person.LastName(), - Email: person.Contact().Email, - Organization: strPtr(s.fkr.Company().Name()), - Reference: strPtr(fmt.Sprintf("%d", s.fkr.RandomNumber(10))), - Address: strPtr(person.Faker.Address().StreetAddress()), - City: strPtr(person.Faker.Address().City()), - State: strPtr(person.Faker.Address().State()), - Zip: strPtr(person.Faker.Address().PostCode()), - Country: strPtr(person.Faker.Address().Country()), - Phone: strPtr(person.Faker.Address().Country()), - }, - }) - - s.NoErrorf(err, "create customer err") - s.Equalf(http.StatusCreated, resp.Response.StatusCode, "create customer status code") - - return resp.Data.Customer -} - -func (s *APITestSuite) createProductFamily(ctx context.Context) models.ProductFamily { - resp, err := s.client.ProductFamiliesController().CreateProductFamily(ctx, &models.CreateProductFamilyRequest{ - ProductFamily: models.CreateProductFamily{ - Name: strPtr(s.fkr.Company().Name()), - }, - }) - - s.NoErrorf(err, "create product family err") - s.Equalf(http.StatusCreated, resp.Response.StatusCode, "create product family status code") - - return *resp.Data.ProductFamily -} - -func (s *APITestSuite) createProduct(ctx context.Context, productFamilyID int) models.Product { - resp, err := s.client.ProductsController().CreateProduct(ctx, productFamilyID, &models.CreateOrUpdateProductRequest{ - Product: models.CreateOrUpdateProduct{ - Name: "Test", - Description: "Testable product", - PriceInCents: 50, - Interval: 1, - IntervalUnit: models.IntervalUnit_MONTH, - }, - }) - - s.NoErrorf(err, "create product err") - s.Equalf(http.StatusCreated, resp.Response.StatusCode, "create product status code") - - return resp.Data.Product -} - -func (s *APITestSuite) createCoupon(ctx context.Context, productFamilyID int) models.Coupon { - coupon := &models.Coupon{ - Name: strPtr("100\\% off first month of usage"), - Code: strPtr("100OFF"), - Description: strPtr("100\\% off one-time"), - Percentage: models.NewOptional[string](strPtr("100")), - AllowNegativeBalance: boolPtr(false), - Recurring: boolPtr(false), - EndDate: models.NewOptional[string](strPtr(newDate())), - ProductFamilyId: &productFamilyID, - Stackable: boolPtr(false), - ExcludeMidPeriodAllocations: boolPtr(true), - ApplyOnCancelAtEndOfPeriod: boolPtr(true), - } - - resp, err := s.client.CouponsController().CreateCoupon(ctx, productFamilyID, &models.CreateOrUpdateCoupon{ - Coupon: interfacePtr(coupon), - }) - - s.NoErrorf(err, "create coupon err") - s.Equalf(http.StatusCreated, resp.Response.StatusCode, "create coupon err") - - return *resp.Data.Coupon -} - -type MeteredComponent struct { - Name string `json:"name"` - UnitName string `json:"unit_name"` - Taxable bool `json:"taxable"` - PricingScheme string `json:"pricing_scheme"` - Prices []Price `json:"prices"` -} - -type Price struct { - StartingQuantity int `json:"starting_quantity"` - UnitPrice int `json:"unit_price"` -} - -func (s *APITestSuite) createMeteredComponent(ctx context.Context, productFamilyID int) models.Component { - component := struct { - MeteredComponent MeteredComponent `json:"metered_component"` - }{ - MeteredComponent: MeteredComponent{ - Name: "test 2", - UnitName: "test message", - Taxable: false, - PricingScheme: "stairstep", - Prices: []Price{{ - StartingQuantity: 1, - UnitPrice: 1, - }, - }, - }, - } - - resp, err := s.client.ComponentsController().CreateComponent( - ctx, - productFamilyID, - models.ComponentKindPath_METEREDCOMPONENTS, - interfacePtr(component), - ) - - s.NoErrorf(err, "create component err") - s.Equalf(http.StatusCreated, resp.Response.StatusCode, "create component err") - - return resp.Data.Component -} - -func strPtr(v string) *string { - return &v -} - -func boolPtr(v bool) *bool { - return &v -} - -func intPtr(v int) *int { - return &v -} - -func interfacePtr(v interface{}) *interface{} { - return &v -} - -func toPtr[T any](v T) *T { - return &v -} - -func newDate() string { - t := time.Now().Add(time.Hour) - - return fmt.Sprintf("%d-%d-%d", t.Year(), t.Month(), t.Day()) -} diff --git a/test/helpers_test.go b/test/helpers_test.go new file mode 100644 index 00000000..f3cbee24 --- /dev/null +++ b/test/helpers_test.go @@ -0,0 +1,163 @@ +package test + +import ( + "context" + "fmt" + "net/http" + "time" + + "github.com/maxio-com/ab-golang-sdk/models" +) + +func (s *APISuite) createCustomer(ctx context.Context) models.Customer { + person := s.fkr.Person() + + resp, err := s.client.CustomersController().CreateCustomer(ctx, &models.CreateCustomerRequest{ + Customer: models.CreateCustomer{ + FirstName: person.FirstName(), + LastName: person.LastName(), + Email: person.Contact().Email, + Organization: strPtr(s.fkr.Company().Name()), + Reference: strPtr(fmt.Sprintf("%d", s.fkr.RandomNumber(10))), + Address: strPtr(person.Faker.Address().StreetAddress()), + City: strPtr(person.Faker.Address().City()), + State: strPtr(person.Faker.Address().State()), + Zip: strPtr(person.Faker.Address().PostCode()), + Country: strPtr(person.Faker.Address().Country()), + Phone: strPtr(person.Faker.Address().Country()), + }, + }) + + s.NoErrorf(err, "create customer err") + s.Equalf(http.StatusCreated, resp.Response.StatusCode, "create customer status code") + + return resp.Data.Customer +} + +func (s *APISuite) createProductFamily(ctx context.Context) models.ProductFamily { + resp, err := s.client.ProductFamiliesController().CreateProductFamily(ctx, &models.CreateProductFamilyRequest{ + ProductFamily: models.CreateProductFamily{ + Name: strPtr(s.fkr.Company().Name()), + }, + }) + + s.NoErrorf(err, "create product family err") + s.Equalf(http.StatusCreated, resp.Response.StatusCode, "create product family status code") + + return *resp.Data.ProductFamily +} + +func (s *APISuite) createProduct(ctx context.Context, productFamilyID int) models.Product { + resp, err := s.client.ProductsController().CreateProduct(ctx, productFamilyID, &models.CreateOrUpdateProductRequest{ + Product: models.CreateOrUpdateProduct{ + Name: s.fkr.RandomStringWithLength(30), + Description: "Testable product", + PriceInCents: 50, + Interval: 1, + IntervalUnit: models.IntervalUnit_MONTH, + }, + }) + + s.NoErrorf(err, "create product err") + s.Equalf(http.StatusCreated, resp.Response.StatusCode, "create product status code") + + return resp.Data.Product +} + +func (s *APISuite) createCoupon(ctx context.Context, productFamilyID int) models.Coupon { + coupon := &models.Coupon{ + Name: strPtr("100\\% off first month of usage"), + Code: strPtr("100OFF" + s.fkr.RandomStringWithLength(30)), + Description: strPtr("100\\% off one-time"), + Percentage: models.NewOptional[string](strPtr("50")), + AllowNegativeBalance: boolPtr(false), + Recurring: boolPtr(false), + EndDate: models.NewOptional[string](strPtr(newDate())), + ProductFamilyId: &productFamilyID, + Stackable: boolPtr(false), + ExcludeMidPeriodAllocations: boolPtr(true), + ApplyOnCancelAtEndOfPeriod: boolPtr(true), + } + + resp, err := s.client.CouponsController().CreateCoupon(ctx, productFamilyID, &models.CreateOrUpdateCoupon{ + Coupon: interfacePtr(coupon), + }) + + s.NoErrorf(err, "create coupon err") + s.Equalf(http.StatusCreated, resp.Response.StatusCode, "create coupon err") + + return *resp.Data.Coupon +} + +type MeteredComponent struct { + Name string `json:"name"` + UnitName string `json:"unit_name"` + Taxable bool `json:"taxable"` + PricingScheme string `json:"pricing_scheme"` + Prices []Price `json:"prices"` +} + +type Price struct { + StartingQuantity int `json:"starting_quantity"` + UnitPrice int `json:"unit_price"` +} + +func (s *APISuite) createMeteredComponent(ctx context.Context, productFamilyID int) models.Component { + component := struct { + MeteredComponent MeteredComponent `json:"metered_component"` + }{ + MeteredComponent: MeteredComponent{ + Name: "test 2", + UnitName: "test message", + Taxable: false, + PricingScheme: "stairstep", + Prices: []Price{{ + StartingQuantity: 1, + UnitPrice: 1, + }, + }, + }, + } + + resp, err := s.client.ComponentsController().CreateComponent( + ctx, + productFamilyID, + models.ComponentKindPath_METEREDCOMPONENTS, + interfacePtr(component), + ) + + s.NoErrorf(err, "create component err") + s.Equalf(http.StatusCreated, resp.Response.StatusCode, "create component err") + + return resp.Data.Component +} + +func strPtr(v string) *string { + return &v +} + +func boolPtr(v bool) *bool { + return &v +} + +func intPtr(v int) *int { + return &v +} + +func interfacePtr(v interface{}) *interface{} { + return &v +} + +func toPtr[T any](v T) *T { + return &v +} + +func newDate() string { + t := time.Now().Add(time.Hour) + + return fmt.Sprintf("%d-%d-%d", t.Year(), t.Month(), t.Day()) +} + +func timePtr(v time.Time) *time.Time { + return &v +} diff --git a/test/site_test.go b/test/site_test.go index 9994cd86..d7cd0b4c 100644 --- a/test/site_test.go +++ b/test/site_test.go @@ -9,7 +9,7 @@ import ( "github.com/maxio-com/ab-golang-sdk/models" ) -func (s *APITestSuite) TestReadSite() { +func (s *APISuite) TestReadSite() { cases := []struct { name string client advancedbilling.ClientInterface diff --git a/test/subscription_test.go b/test/subscription_test.go index 3e1cca14..c589879f 100644 --- a/test/subscription_test.go +++ b/test/subscription_test.go @@ -2,16 +2,15 @@ package test import ( "context" - "encoding/json" - "io/ioutil" "net/http" "testing" "time" + advancedbilling "github.com/maxio-com/ab-golang-sdk" "github.com/maxio-com/ab-golang-sdk/models" ) -func (s *APITestSuite) TestSubscriptionCreate() { +func (s *APISuite) TestSubscriptionCreate() { ctx := context.Background() customer := s.createCustomer(ctx) @@ -22,11 +21,13 @@ func (s *APITestSuite) TestSubscriptionCreate() { cases := []struct { name string + client advancedbilling.ClientInterface subscription models.CreateSubscription assert func(*testing.T, models.ApiResponse[models.SubscriptionResponse], models.CreateSubscription, error) }{ { - name: "valid", + name: "valid", + client: s.client, subscription: s.newSubscription( customer, product, @@ -94,25 +95,43 @@ func (s *APITestSuite) TestSubscriptionCreate() { s.Equal(*coupon.Code, readSubResp.Data.Subscription.CouponCodes[0]) }, }, - // { - // name: "invalid coupon code", - // subscription: s.newSubscription( - // customer, - // product, - // "", - // []models.CreateSubscriptionComponent{}, - // ), - // assert: func(t *testing.T, ar models.ApiResponse[models.SubscriptionResponse], subscription models.CreateSubscription, err error) { - // s.Equal(http.StatusUnprocessableEntity, ar.Response.StatusCode) - // }, - // }, + { + name: "invalid coupon code", + client: s.client, + subscription: s.newSubscription( + customer, + product, + "invalid coupon code", + []models.CreateSubscriptionComponent{}, + ), + assert: func(t *testing.T, ar models.ApiResponse[models.SubscriptionResponse], subscription models.CreateSubscription, err error) { + s.Equal(http.StatusUnprocessableEntity, ar.Response.StatusCode) + }, + }, + { + name: "unauthorized", + client: s.unauthorizedClient, + subscription: s.newSubscription( + customer, + product, + *coupon.Code, + []models.CreateSubscriptionComponent{ + { + ComponentId: interfacePtr(*component.Id), + Enabled: boolPtr(true), + UnitBalance: intPtr(1), + }, + }, + ), + assert: func(t *testing.T, ar models.ApiResponse[models.SubscriptionResponse], cs models.CreateSubscription, err error) { + s.Equal(http.StatusUnauthorized, ar.Response.StatusCode) + }, + }, } for _, c := range cases { s.T().Run(c.name, func(t *testing.T) { - content, _ := json.Marshal(c.subscription) - ioutil.WriteFile("subscription.json", content, 0644) - resp, err := s.client.SubscriptionsController().CreateSubscription( + resp, err := c.client.SubscriptionsController().CreateSubscription( ctx, &models.CreateSubscriptionRequest{ Subscription: c.subscription, @@ -124,7 +143,7 @@ func (s *APITestSuite) TestSubscriptionCreate() { } } -func (s *APITestSuite) newSubscription( +func (s *APISuite) newSubscription( customer models.Customer, product models.Product, couponCode string, @@ -135,7 +154,7 @@ func (s *APITestSuite) newSubscription( PaymentCollectionMethod: toPtr[models.PaymentCollectionMethod](models.PaymentCollectionMethod_AUTOMATIC), CustomerId: customer.Id, Currency: strPtr("USD"), - InitialBillingAt: strPtr(newDate()), + InitialBillingAt: strPtr("2029-08-29T12:00:00-04:00"), CouponCode: &couponCode, Components: components, PaymentProfileAttributes: &models.PaymentProfileAttributes{