Skip to content

Commit

Permalink
Add unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
sajit committed Oct 4, 2024
1 parent 8a43e97 commit e173566
Show file tree
Hide file tree
Showing 2 changed files with 172 additions and 29 deletions.
15 changes: 7 additions & 8 deletions mongodb-atlas/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ func (a *AtlasCostSource) getAtlasCostsForWindow(win *opencost.Window) (*pb.Cust
}

// get the costs
costs, err := getCosts(a.atlasClient, a.orgID, token)
costs, err := GetCosts(a.atlasClient, a.orgID, token)
if err != nil {
log.Errorf("error getting costs: %v", err)
return nil, err
Expand All @@ -154,7 +154,7 @@ func (a *AtlasCostSource) getAtlasCostsForWindow(win *opencost.Window) (*pb.Cust
return &resp, nil
}

func getCosts(client HTTPClient, org string, token string) ([]*pb.CustomCost, error) {
func GetCosts(client HTTPClient, org string, token string) ([]*pb.CustomCost, error) {
request, _ := http.NewRequest("GET", fmt.Sprintf(costExplorerQueryFmt, org, token), nil)

request.Header.Set("Accept", "application/vnd.atlas.2023-01-01+json")
Expand All @@ -163,14 +163,18 @@ func getCosts(client HTTPClient, org string, token string) ([]*pb.CustomCost, er
response, error := client.Do(request)
statusCode := response.StatusCode
//102 status code means processing - so repeat call 5 times to see if we get a response
for count := 1; count < 5 && statusCode == 102; count++ {
for count := 1; count < 5 && statusCode == http.StatusProcessing; count++ {
// Sleep for 5 seconds before the next request
time.Sleep(5 * time.Second)
response, _ := client.Do(request)
statusCode = response.StatusCode

}

if statusCode == http.StatusProcessing {
msg := "timeout waiting for response"
return nil, fmt.Errorf(msg)
}
if error != nil {
msg := fmt.Sprintf("getCostExplorerUsage: error from server: %v", error)
log.Errorf(msg)
Expand All @@ -187,11 +191,6 @@ func getCosts(client HTTPClient, org string, token string) ([]*pb.CustomCost, er
log.Errorf(msg)
return nil, fmt.Errorf(msg)
}
//sample
//report_data='{"usageDetails":[{"invoiceId":"66d7254246a21a41036ff315","organizationId":"66d7254246a21a41036ff2e9","organizationName":"Kubecost","service":"Data Transfer","usageAmount":1.33,"usageDate":"2024-09-01"},
//{"invoiceId":"66d7254246a21a41036ff315","organizationId":"66d7254246a21a41036ff2e9","organizationName":"Kubecost","service":"Clusters","usageAmount":51.19,"usageDate":"2024-09-01"}]}’

//fake it for now
var costs []*pb.CustomCost
// Iterate over the UsageDetails in CostResponse
for _, invoice := range costResponse.UsageDetails {
Expand Down
186 changes: 165 additions & 21 deletions mongodb-atlas/cmd/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"io"
"net/http"
"testing"
"time"
Expand All @@ -23,10 +23,6 @@ func (m *MockHTTPClient) Do(req *http.Request) (*http.Response, error) {
return m.DoFunc(req)
}

func TestSanity(t *testing.T) {
assert.True(t, true)
}

func TestCreateCostExplorerQueryToken(t *testing.T) {
// Mock data
org := "testOrg"
Expand Down Expand Up @@ -55,7 +51,7 @@ func TestCreateCostExplorerQueryToken(t *testing.T) {
// Return a mock response with status 200 and mock JSON body
return &http.Response{
StatusCode: http.StatusOK,
Body: ioutil.NopCloser(bytes.NewBuffer(mockResponseJson)),
Body: io.NopCloser(bytes.NewBuffer(mockResponseJson)),
}, nil
},
}
Expand Down Expand Up @@ -119,19 +115,11 @@ func TestErrorFromServer(t *testing.T) {
// Create a mock HTTPClient that returns a successful response
mockClient := &MockHTTPClient{
DoFunc: func(req *http.Request) (*http.Response, error) {
// Verify that the request method and URL are correct
if req.Method != http.MethodPost {
t.Errorf("expected POST request, got %s", req.Method)
}
expectedURL := fmt.Sprintf(costExplorerFmt, orgId)
if req.URL.String() != expectedURL {
t.Errorf("expected URL %s, got %s", expectedURL, req.URL.String())
}

// Return a mock response with status 200 and mock JSON body
return &http.Response{
StatusCode: http.StatusInternalServerError,
Body: ioutil.NopCloser(bytes.NewBufferString("fake")),
Body: io.NopCloser(bytes.NewBufferString("fake")),
}, nil
},
}
Expand All @@ -147,28 +135,184 @@ func TestCallToCreateCostExplorerQueryBadMessage(t *testing.T) {
layout := "2006-01-02"
endTime, _ := time.Parse(layout, "2024-07-01")
startTime, _ := time.Parse(layout, "2023-12-01")
mockClient := &MockHTTPClient{
DoFunc: func(req *http.Request) (*http.Response, error) {

// Return a mock response with status 200 and mock JSON body
return &http.Response{
StatusCode: http.StatusOK,
Body: io.NopCloser(bytes.NewBufferString("This ain't json")),
}, nil
},
}

_, error := CreateCostExplorerQueryToken("myOrg", startTime, endTime, mockClient)
assert.NotEmpty(t, error)

}

// tests for getCosts
func TestGetCostsMultipleInvoices(t *testing.T) {
costResponse := atlasplugin.CostResponse{
UsageDetails: []atlasplugin.Invoice{
{
InvoiceId: "INV001",
OrganizationId: "ORG123",
OrganizationName: "Acme Corp",
Service: "Compute",
UsageAmount: 120.50,
UsageDate: "2024-10-01",
},
{
InvoiceId: "INV002",
OrganizationId: "ORG124",
OrganizationName: "Beta Corp",
Service: "Storage",
UsageAmount: 75.75,
UsageDate: "2024-10-02",
},
{
InvoiceId: "INV003",
OrganizationId: "ORG125",
OrganizationName: "Gamma Inc",
Service: "Networking",
UsageAmount: 50.00,
UsageDate: "2024-10-03",
},
},
}

mockResponseJson, _ := json.Marshal(costResponse)

mockClient := &MockHTTPClient{
DoFunc: func(req *http.Request) (*http.Response, error) {
// Verify that the request method and URL are correct
if req.Method != http.MethodPost {
t.Errorf("expected POST request, got %s", req.Method)
if req.Method != http.MethodGet {
t.Errorf("expected GET request, got %s", req.Method)
}
expectedURL := fmt.Sprintf(costExplorerFmt, "myOrg")
expectedURL := fmt.Sprintf(costExplorerQueryFmt, "myOrg", "t1")
if req.URL.String() != expectedURL {
t.Errorf("expected URL %s, got %s", expectedURL, req.URL.String())
}

// Return a mock response with status 200 and mock JSON body
return &http.Response{
StatusCode: http.StatusOK,
Body: ioutil.NopCloser(bytes.NewBufferString("This ain't json")),
Body: io.NopCloser(bytes.NewBuffer(mockResponseJson)),
}, nil
},
}
costs, err := GetCosts(mockClient, "myOrg", "t1")
assert.Nil(t, err)
assert.Equal(t, 3, len(costs))

_, error := CreateCostExplorerQueryToken("myOrg", startTime, endTime, mockClient)
for i, invoice := range costResponse.UsageDetails {
assert.Equal(t, invoice.InvoiceId, costs[i].Id)
assert.Equal(t, invoice.OrganizationName, costs[i].AccountName)
assert.Equal(t, invoice.Service, costs[i].ChargeCategory)
assert.Equal(t, invoice.UsageAmount, costs[i].BilledCost)
}
}

func TestGetCostErrorFromServer(t *testing.T) {

mockClient := &MockHTTPClient{
DoFunc: func(req *http.Request) (*http.Response, error) {

// Return a mock response with status 200 and mock JSON body
return &http.Response{
StatusCode: http.StatusInternalServerError,
Body: io.NopCloser(bytes.NewBufferString("")),
}, nil
},
}
costs, err := GetCosts(mockClient, "myOrg", "t1")

assert.NotEmpty(t, err)
assert.Nil(t, costs)

}

func TestGetCostsBadMessage(t *testing.T) {

mockClient := &MockHTTPClient{
DoFunc: func(req *http.Request) (*http.Response, error) {

// Return a mock response with status 200 and mock JSON body
return &http.Response{
StatusCode: http.StatusInternalServerError,
Body: io.NopCloser(bytes.NewBufferString("No Jason No")),
}, nil
},
}

_, error := GetCosts(mockClient, "myOrg", "t1")
assert.NotEmpty(t, error)

}

//tests for getCosts
func TestRepeatCallTill200(t *testing.T) {

var count = 0
costResponse := atlasplugin.CostResponse{
UsageDetails: []atlasplugin.Invoice{

{
InvoiceId: "INV003",
OrganizationId: "ORG125",
OrganizationName: "Gamma Inc",
Service: "Networking",
UsageAmount: 50.00,
UsageDate: "2024-10-03",
},
},
}

mockResponseJson, _ := json.Marshal(costResponse)

mockClient := &MockHTTPClient{
DoFunc: func(req *http.Request) (*http.Response, error) {
count++

if count < 5 {
// Return a mock response with status 200 and mock JSON body
return &http.Response{
StatusCode: http.StatusProcessing,
Body: io.NopCloser(bytes.NewBuffer(mockResponseJson)),
}, nil

} else {
// Return a mock response with status 200 and mock JSON body
return &http.Response{
StatusCode: http.StatusOK,
Body: io.NopCloser(bytes.NewBuffer(mockResponseJson)),
}, nil

}

},
}

costs, err := GetCosts(mockClient, "myOrg", "t1")
assert.Nil(t, err)
assert.Equal(t, 1, len(costs))
}

func TestStuckInProcessing(t *testing.T) {

mockClient := &MockHTTPClient{
DoFunc: func(req *http.Request) (*http.Response, error) {

// Return a mock response with status 200 and mock JSON body
return &http.Response{
StatusCode: http.StatusProcessing,
Body: io.NopCloser(bytes.NewBufferString("")),
}, nil

},
}

costs, err := GetCosts(mockClient, "myOrg", "t1")
assert.NotNil(t, err)
assert.Nil(t, costs)
}

0 comments on commit e173566

Please sign in to comment.