Skip to content

Commit e3300cb

Browse files
author
sajit
committed
unit tests
Signed-off-by: Sajit Kunnumkal <[email protected]>
1 parent 7ec888a commit e3300cb

File tree

5 files changed

+191
-12
lines changed

5 files changed

+191
-12
lines changed

pkg/plugins/snowflake/cmd/main/main

29.5 MB
Binary file not shown.

pkg/plugins/snowflake/cmd/main/main.go

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ func GetInvoices(snowflakeClient SnowflakeClient) ([]snowflakeplugin.LineItem, e
9090
rows, err := snowflakeClient.ExecuteQuery(query)
9191
if err != nil {
9292

93-
log.Fatalf("Query execution failed:", err)
93+
log.Fatalf("Query execution failed: %v", err)
9494
return nil, err
9595
}
9696
defer rows.Close()
@@ -103,7 +103,7 @@ func GetInvoices(snowflakeClient SnowflakeClient) ([]snowflakeplugin.LineItem, e
103103
var date string
104104

105105
if err := rows.Scan(&date, &warehouse, &credits); err != nil {
106-
log.Fatalf("", err)
106+
log.Fatalf("%v", err)
107107
}
108108

109109
lineItem := snowflakeplugin.LineItem{
@@ -115,8 +115,10 @@ func GetInvoices(snowflakeClient SnowflakeClient) ([]snowflakeplugin.LineItem, e
115115
lineItems = append(lineItems, lineItem)
116116
}
117117

118-
if err = rows.Err(); err != nil {
119-
log.Fatalf("", err)
118+
sqlError := rows.Err()
119+
if sqlError != nil {
120+
log.Fatalf("%v", sqlError)
121+
return nil, sqlError
120122
}
121123

122124
return lineItems, nil
@@ -145,7 +147,7 @@ func main() {
145147
client, err := NewSnowflakeClient(snowflakeConfig)
146148

147149
if err != nil {
148-
log.Fatalf("Failed to create Snowflake client:", err)
150+
log.Fatalf("Failed to create Snowflake client: %v", err)
149151
}
150152
snowflakeCostSource := SnowflakeCostSource{
151153
snowflakeClient: client,
@@ -215,13 +217,14 @@ func (s *SnowflakeCostSource) GetCustomCosts(req *pb.CustomCostRequest) []*pb.Cu
215217
func filterLineItemsByWindow(win *opencost.Window, lineItems []snowflakeplugin.LineItem) []*pb.CustomCost {
216218
var filteredItems []*pb.CustomCost
217219
for _, li := range lineItems {
218-
if li.Date == win.Start().Format("2006-01-02 15:04:05") {
219-
cost := &pb.CustomCost{
220-
UsageQuantity: li.CreditUsed,
221-
ResourceName: li.WarehouseName,
222-
}
223-
filteredItems = append(filteredItems, cost)
220+
log.Debugf("Window Start: %s ", win.Start().Format("2006-01-02 15:04:05"))
221+
222+
cost := &pb.CustomCost{
223+
UsageQuantity: li.CreditUsed,
224+
ResourceName: li.WarehouseName,
224225
}
226+
filteredItems = append(filteredItems, cost)
227+
225228
}
226229
return filteredItems
227230
}
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
package main
2+
3+
import (
4+
"errors"
5+
"testing"
6+
"time"
7+
8+
snowflakeplugin "github.com/opencost/opencost-plugins/pkg/plugins/snowflake/plugin"
9+
"github.com/opencost/opencost/core/pkg/model/pb"
10+
"github.com/opencost/opencost/core/pkg/opencost"
11+
"github.com/stretchr/testify/assert"
12+
"google.golang.org/protobuf/types/known/timestamppb"
13+
14+
"github.com/DATA-DOG/go-sqlmock" // For mocking SQL database
15+
)
16+
17+
// TestGetInvoices function
18+
func TestGetInvoices(t *testing.T) {
19+
// Create a mocked database connection
20+
db, mock, err := sqlmock.New()
21+
if err != nil {
22+
t.Fatalf("Error initializing sqlmock: %v", err)
23+
}
24+
defer db.Close()
25+
26+
// Convert MockRows to *sql.Rows
27+
28+
expectedQuery := `(?s)SELECT start_time, warehouse_name, credits_used_compute FROM snowflake\.account_usage\.warehouse_metering_history WHERE start_time >= DATEADD\(day, -m, CURRENT_TIMESTAMP\(\)\) AND warehouse_id > 0 -- Skip pseudo-VWs such as "CLOUD_SERVICES_ONLY" ORDER BY 1 DESC, 2;`
29+
30+
rows := sqlmock.NewRows([]string{"Date", "WarehouseName", "Credits"}).
31+
AddRow("2025-01-23", "ANALYTICS_VW", 123.45).
32+
AddRow("2025-01-22", "LOADING_VW", 75)
33+
34+
// Expect the query and provide the mock response
35+
mock.ExpectQuery(expectedQuery).WillReturnRows(rows)
36+
37+
// Create the SnowflakeClient with the mocked db
38+
mockClient := &snowflakeClient{db: db}
39+
40+
// Test the function
41+
invoices, err := GetInvoices(mockClient)
42+
43+
// Assertions
44+
assert.NoError(t, err)
45+
assert.Len(t, invoices, 2)
46+
47+
expectedInvoices := []snowflakeplugin.LineItem{
48+
{WarehouseName: "ANALYTICS_VW", CreditUsed: 123.45, Date: "2025-01-23"},
49+
{WarehouseName: "LOADING_VW", CreditUsed: 75, Date: "2025-01-22"},
50+
}
51+
assert.Equal(t, expectedInvoices, invoices)
52+
53+
}
54+
55+
func TestExecuteQueryWithRowError(t *testing.T) {
56+
// Create a mocked database connection
57+
db, mock, err := sqlmock.New()
58+
if err != nil {
59+
t.Fatalf("Error initializing sqlmock: %v", err)
60+
}
61+
defer db.Close()
62+
63+
// Define the query
64+
query := "SELECT start_time, warehouse_name, credits_used_compute FROM warehouse_metering_history"
65+
66+
// Create mock rows with an error injected
67+
rows := sqlmock.NewRows([]string{"start_time", "warehouse_name", "credits_used_compute"}).
68+
AddRow("2025-01-28T16:00:00Z", "WH1", 123.45).
69+
AddRow("2025-01-28T15:00:00Z", "WH2", 678.90).
70+
RowError(1, errors.New("simulated row error")) // Inject error at row index 1
71+
72+
// Expect the query and provide the mock response
73+
mock.ExpectQuery(query).WillReturnRows(rows)
74+
75+
// Create the SnowflakeClient with the mocked db
76+
client := &snowflakeClient{db: db}
77+
78+
// Call ExecuteQuery
79+
result, err := client.ExecuteQuery(query)
80+
if err != nil {
81+
t.Fatalf("ExecuteQuery failed: %v", err)
82+
}
83+
defer result.Close()
84+
85+
// Validate the results
86+
var (
87+
startTime string
88+
warehouseName string
89+
credits float64
90+
)
91+
92+
for result.Next() {
93+
if err := result.Scan(&startTime, &warehouseName, &credits); err != nil {
94+
t.Fatalf("Error scanning row: %v", err)
95+
}
96+
}
97+
98+
// Check for row errors
99+
if err := result.Err(); err == nil {
100+
t.Errorf("Expected an error from result.Err(), but got nil")
101+
} else if err.Error() != "simulated row error" {
102+
t.Errorf("Unexpected error message from result.Err(): %v", err)
103+
}
104+
105+
// Verify that all expectations were met
106+
if err := mock.ExpectationsWereMet(); err != nil {
107+
t.Errorf("SQL expectations were not met: %v", err)
108+
}
109+
}
110+
111+
func TestGetCustomCosts(t *testing.T) {
112+
assert.Equal(t, 0, 0)
113+
}
114+
115+
func TestFilterLineItemsByWindow(t *testing.T) {
116+
assert.Equal(t, 0, 0)
117+
}
118+
119+
func TestGetSnowflakeCostsForWindow(t *testing.T) {
120+
121+
// Create a mocked database connection
122+
db, _, err := sqlmock.New()
123+
if err != nil {
124+
t.Fatalf("Error initializing sqlmock: %v", err)
125+
}
126+
defer db.Close()
127+
128+
// Create the SnowflakeClient with the mocked db
129+
mockClient := &snowflakeClient{db: db}
130+
// Create SnowflakeCostSource
131+
snowflakeCostSource := SnowflakeCostSource{
132+
snowflakeClient: mockClient,
133+
}
134+
135+
// Define the window
136+
startTime := time.Date(2025, 1, 20, 0, 0, 0, 0, time.UTC)
137+
endTime := time.Date(2025, 1, 25, 0, 0, 0, 0, time.UTC)
138+
window := opencost.NewWindow(&startTime, &endTime)
139+
140+
// Fetch line items
141+
lineItems := []snowflakeplugin.LineItem{
142+
{WarehouseName: "ANALYTICS_VW", CreditUsed: 123.45, Date: "2025-01-23"},
143+
{WarehouseName: "LOADING_VW", CreditUsed: 75, Date: "2025-01-22"},
144+
}
145+
146+
// Call GetSnowflakeCostsForWindow
147+
result := snowflakeCostSource.GetSnowflakeCostsForWindow(&window, lineItems)
148+
149+
// Assertions
150+
assert.NotNil(t, result)
151+
assert.Equal(t, "data_storage", result.CostSource)
152+
assert.Equal(t, "snowflake", result.Domain)
153+
assert.Equal(t, "v1", result.Version)
154+
assert.Equal(t, "USD", result.Currency)
155+
assert.Equal(t, timestamppb.New(startTime), result.Start)
156+
assert.Equal(t, timestamppb.New(endTime), result.End)
157+
assert.Empty(t, result.Errors)
158+
assert.Len(t, result.Costs, 2)
159+
160+
expectedCosts := []*pb.CustomCost{
161+
{UsageQuantity: 123.45, ResourceName: "ANALYTICS_VW"},
162+
{UsageQuantity: 75, ResourceName: "LOADING_VW"},
163+
}
164+
assert.Equal(t, expectedCosts, result.Costs)
165+
166+
}

pkg/plugins/snowflake/go.mod

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@ require (
88
github.com/hashicorp/go-plugin v1.6.1
99
github.com/opencost/opencost-plugins/common v0.0.0-00010101000000-000000000000
1010
github.com/opencost/opencost/core v0.0.0-20250117200701-47c4b6817505
11+
github.com/stretchr/testify v1.9.0
1112
google.golang.org/protobuf v1.33.0
1213

1314
)
1415

1516
require (
17+
github.com/DATA-DOG/go-sqlmock v1.5.2 // indirect
18+
github.com/davecgh/go-spew v1.1.1 // indirect
1619
github.com/fatih/color v1.16.0 // indirect
1720
github.com/fsnotify/fsnotify v1.6.0 // indirect
1821
github.com/go-logr/logr v1.2.4 // indirect
@@ -37,13 +40,14 @@ require (
3740
github.com/oklog/run v1.1.0 // indirect
3841
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
3942
github.com/pelletier/go-toml v1.9.3 // indirect
43+
github.com/pmezard/go-difflib v1.0.0 // indirect
4044
github.com/rs/zerolog v1.26.1 // indirect
4145
github.com/spf13/afero v1.6.0 // indirect
4246
github.com/spf13/cast v1.3.1 // indirect
4347
github.com/spf13/jwalterweatherman v1.1.0 // indirect
4448
github.com/spf13/pflag v1.0.5 // indirect
4549
github.com/spf13/viper v1.8.1 // indirect
46-
github.com/stretchr/testify v1.9.0 // indirect
50+
github.com/stretchr/objx v0.5.2 // indirect
4751
github.com/subosito/gotenv v1.2.0 // indirect
4852
golang.org/x/exp v0.0.0-20221031165847-c99f073a8326 // indirect
4953
golang.org/x/net v0.23.0 // indirect
@@ -55,6 +59,7 @@ require (
5559
gopkg.in/inf.v0 v0.9.1 // indirect
5660
gopkg.in/ini.v1 v1.67.0 // indirect
5761
gopkg.in/yaml.v2 v2.4.0 // indirect
62+
gopkg.in/yaml.v3 v3.0.1 // indirect
5863
k8s.io/api v0.25.3 // indirect
5964
k8s.io/apimachinery v0.25.3 // indirect
6065
k8s.io/klog/v2 v2.80.0 // indirect

pkg/plugins/snowflake/go.sum

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
3939
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
4040
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
4141
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
42+
github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
43+
github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
4244
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
4345
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
4446
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
@@ -199,6 +201,7 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X
199201
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
200202
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
201203
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
204+
github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE=
202205
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
203206
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
204207
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
@@ -281,6 +284,8 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
281284
github.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44=
282285
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
283286
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
287+
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
288+
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
284289
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
285290
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
286291
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=

0 commit comments

Comments
 (0)