|
|
@@ -1,10 +1,8 @@
|
|
|
package aws
|
|
|
|
|
|
import (
|
|
|
- "fmt"
|
|
|
"os"
|
|
|
"reflect"
|
|
|
- "strings"
|
|
|
"testing"
|
|
|
"time"
|
|
|
|
|
|
@@ -70,7 +68,7 @@ func TestAthenaIntegration_GetCloudCost(t *testing.T) {
|
|
|
}
|
|
|
|
|
|
func Test_athenaRowToCloudCost(t *testing.T) {
|
|
|
- aqi := AthenaQueryIndexes{
|
|
|
+ aqiCur10 := AthenaQueryIndexes{
|
|
|
ColumnIndexes: map[string]int{
|
|
|
"ListCostColumn": 0,
|
|
|
"NetCostColumn": 1,
|
|
|
@@ -97,6 +95,32 @@ func Test_athenaRowToCloudCost(t *testing.T) {
|
|
|
IsK8sColumn: "IsK8sColumn",
|
|
|
}
|
|
|
|
|
|
+ aqiCur20 := AthenaQueryIndexes{
|
|
|
+ ColumnIndexes: map[string]int{
|
|
|
+ "ListCostColumn": 0,
|
|
|
+ "NetCostColumn": 1,
|
|
|
+ "AmortizedNetCostColumn": 2,
|
|
|
+ "AmortizedCostColumn": 3,
|
|
|
+ "IsK8sColumn": 4,
|
|
|
+ AthenaDateTruncColumn: 5,
|
|
|
+ "line_item_resource_id": 6,
|
|
|
+ "bill_payer_account_id": 7,
|
|
|
+ "line_item_usage_account_id": 8,
|
|
|
+ "line_item_product_code": 9,
|
|
|
+ "line_item_usage_type": 10,
|
|
|
+ "product_region_code": 11,
|
|
|
+ "line_item_availability_zone": 12,
|
|
|
+ AthenaResourceTagsCastToJsonColumn: 13,
|
|
|
+ },
|
|
|
+ TagColumns: []string{},
|
|
|
+ AWSTagColumns: []string{},
|
|
|
+ ListCostColumn: "ListCostColumn",
|
|
|
+ NetCostColumn: "NetCostColumn",
|
|
|
+ AmortizedNetCostColumn: "AmortizedNetCostColumn",
|
|
|
+ AmortizedCostColumn: "AmortizedCostColumn",
|
|
|
+ IsK8sColumn: "IsK8sColumn",
|
|
|
+ }
|
|
|
+
|
|
|
tests := []struct {
|
|
|
name string
|
|
|
row []string
|
|
|
@@ -105,51 +129,51 @@ func Test_athenaRowToCloudCost(t *testing.T) {
|
|
|
wantErr bool
|
|
|
}{
|
|
|
{
|
|
|
- name: "incorrect row length",
|
|
|
+ name: "incorrect row length CUR 1.0",
|
|
|
row: []string{"not enough elements"},
|
|
|
- aqi: aqi,
|
|
|
+ aqi: aqiCur10,
|
|
|
want: nil,
|
|
|
wantErr: true,
|
|
|
},
|
|
|
{
|
|
|
- name: "invalid list cost",
|
|
|
+ name: "invalid list cost CUR 1.0",
|
|
|
row: []string{"invalid", "2", "3", "4", "true", "2024-09-01 00:00:00.000", "resourceID", "payerAccountID", "usageAccountID", "productCode", "usageType", "regionCode", "availabilityZone", "userTagTestValue", "awsTagTestValue"},
|
|
|
- aqi: aqi,
|
|
|
+ aqi: aqiCur10,
|
|
|
want: nil,
|
|
|
wantErr: true,
|
|
|
},
|
|
|
{
|
|
|
- name: "invalid net cost",
|
|
|
+ name: "invalid net cost CUR 1.0",
|
|
|
row: []string{"1", "invalid", "3", "4", "true", "2024-09-01 00:00:00.000", "resourceID", "payerAccountID", "usageAccountID", "productCode", "usageType", "regionCode", "availabilityZone", "userTagTestValue", "awsTagTestValue"},
|
|
|
- aqi: aqi,
|
|
|
+ aqi: aqiCur10,
|
|
|
want: nil,
|
|
|
wantErr: true,
|
|
|
},
|
|
|
{
|
|
|
- name: "invalid amortized net cost",
|
|
|
+ name: "invalid amortized net cost CUR 1.0",
|
|
|
row: []string{"1", "2", "invalid", "4", "true", "2024-09-01 00:00:00.000", "resourceID", "payerAccountID", "usageAccountID", "productCode", "usageType", "regionCode", "availabilityZone", "userTagTestValue", "awsTagTestValue"},
|
|
|
- aqi: aqi,
|
|
|
+ aqi: aqiCur10,
|
|
|
want: nil,
|
|
|
wantErr: true,
|
|
|
},
|
|
|
{
|
|
|
- name: "invalid amortized cost",
|
|
|
+ name: "invalid amortized cost CUR 1.0",
|
|
|
row: []string{"1", "2", "3", "invalid", "true", "2024-09-01 00:00:00.000", "resourceID", "payerAccountID", "usageAccountID", "productCode", "usageType", "regionCode", "availabilityZone", "userTagTestValue", "awsTagTestValue"},
|
|
|
- aqi: aqi,
|
|
|
+ aqi: aqiCur10,
|
|
|
want: nil,
|
|
|
wantErr: true,
|
|
|
},
|
|
|
{
|
|
|
- name: "invalid date",
|
|
|
+ name: "invalid date CUR 1.0",
|
|
|
row: []string{"1", "2", "3", "4", "true", "invalid", "resourceID", "payerAccountID", "usageAccountID", "productCode", "usageType", "regionCode", "availabilityZone", "userTagTestValue", "awsTagTestValue"},
|
|
|
- aqi: aqi,
|
|
|
+ aqi: aqiCur10,
|
|
|
want: nil,
|
|
|
wantErr: true,
|
|
|
},
|
|
|
{
|
|
|
- name: "valid kubernetes with labels",
|
|
|
+ name: "valid kubernetes with labels CUR 1.0",
|
|
|
row: []string{"1", "2", "3", "4", "true", "2024-09-01 00:00:00.000", "resourceID", "payerAccountID", "usageAccountID", "productCode", "usageType", "regionCode", "availabilityZone", "userTagTestValue", "awsTagTestValue"},
|
|
|
- aqi: aqi,
|
|
|
+ aqi: aqiCur10,
|
|
|
want: &opencost.CloudCost{
|
|
|
Properties: &opencost.CloudCostProperties{
|
|
|
ProviderID: "resourceID",
|
|
|
@@ -197,7 +221,7 @@ func Test_athenaRowToCloudCost(t *testing.T) {
|
|
|
{
|
|
|
name: "valid non-kubernetes, no labels",
|
|
|
row: []string{"1", "2", "3", "4", "false", "2024-09-01 00:00:00.000", "resourceID", "payerAccountID", "usageAccountID", "productCode", "usageType", "regionCode", "availabilityZone", "", ""},
|
|
|
- aqi: aqi,
|
|
|
+ aqi: aqiCur10,
|
|
|
want: &opencost.CloudCost{
|
|
|
Properties: &opencost.CloudCostProperties{
|
|
|
ProviderID: "resourceID",
|
|
|
@@ -240,9 +264,9 @@ func Test_athenaRowToCloudCost(t *testing.T) {
|
|
|
wantErr: false,
|
|
|
},
|
|
|
{
|
|
|
- name: "valid load balancer product code",
|
|
|
+ name: "valid load balancer product code CUR 1.0",
|
|
|
row: []string{"1", "2", "3", "4", "false", "2024-09-01 00:00:00.000", "resourceID/lbID", "payerAccountID", "usageAccountID", "AWSELB", "usageType", "regionCode", "availabilityZone", "", ""},
|
|
|
- aqi: aqi,
|
|
|
+ aqi: aqiCur10,
|
|
|
want: &opencost.CloudCost{
|
|
|
Properties: &opencost.CloudCostProperties{
|
|
|
ProviderID: "lbID",
|
|
|
@@ -285,9 +309,9 @@ func Test_athenaRowToCloudCost(t *testing.T) {
|
|
|
wantErr: false,
|
|
|
},
|
|
|
{
|
|
|
- name: "valid non-kubernetes, Fargate CPU",
|
|
|
+ name: "valid non-kubernetes, Fargate CPU CUR 1.0",
|
|
|
row: []string{"1", "2", "3", "4", "false", "2024-09-01 00:00:00.000", "123:pod/resource", "payerAccountID", "usageAccountID", "AmazonEKS", "CPU", "regionCode", "availabilityZone", "", ""},
|
|
|
- aqi: aqi,
|
|
|
+ aqi: aqiCur10,
|
|
|
want: &opencost.CloudCost{
|
|
|
Properties: &opencost.CloudCostProperties{
|
|
|
ProviderID: "123:pod/resource/CPU",
|
|
|
@@ -330,9 +354,9 @@ func Test_athenaRowToCloudCost(t *testing.T) {
|
|
|
wantErr: false,
|
|
|
},
|
|
|
{
|
|
|
- name: "valid non-kubernetes, Fargate RAM",
|
|
|
+ name: "valid non-kubernetes, Fargate RAM CUR 1.0",
|
|
|
row: []string{"1", "2", "3", "4", "false", "2024-09-01 00:00:00.000", "123:pod/resource", "payerAccountID", "usageAccountID", "AmazonEKS", "GB", "regionCode", "availabilityZone", "", ""},
|
|
|
- aqi: aqi,
|
|
|
+ aqi: aqiCur10,
|
|
|
want: &opencost.CloudCost{
|
|
|
Properties: &opencost.CloudCostProperties{
|
|
|
ProviderID: "123:pod/resource/RAM",
|
|
|
@@ -374,6 +398,54 @@ func Test_athenaRowToCloudCost(t *testing.T) {
|
|
|
},
|
|
|
wantErr: false,
|
|
|
},
|
|
|
+ {
|
|
|
+ name: "valid kubernetes with labels CUR 2.0",
|
|
|
+ row: []string{"1", "2", "3", "4", "true", "2024-09-01 00:00:00.000", "resourceID", "payerAccountID", "usageAccountID", "productCode", "usageType", "regionCode", "availabilityZone", `{"test": "userTagTestValue", "aws_test": "awsTagTestValue"}`},
|
|
|
+ aqi: aqiCur20,
|
|
|
+ want: &opencost.CloudCost{
|
|
|
+ Properties: &opencost.CloudCostProperties{
|
|
|
+ ProviderID: "resourceID",
|
|
|
+ Provider: "AWS",
|
|
|
+ AccountID: "usageAccountID",
|
|
|
+ AccountName: "usageAccountID",
|
|
|
+ InvoiceEntityID: "payerAccountID",
|
|
|
+ InvoiceEntityName: "payerAccountID",
|
|
|
+ RegionID: "regionCode",
|
|
|
+ AvailabilityZone: "availabilityZone",
|
|
|
+ Service: "productCode",
|
|
|
+ Category: opencost.OtherCategory,
|
|
|
+ Labels: opencost.CloudCostLabels{
|
|
|
+ "test": "userTagTestValue",
|
|
|
+ "aws_test": "awsTagTestValue",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ Window: opencost.NewClosedWindow(
|
|
|
+ time.Date(2024, 9, 1, 0, 0, 0, 0, time.UTC),
|
|
|
+ time.Date(2024, 9, 2, 0, 0, 0, 0, time.UTC),
|
|
|
+ ),
|
|
|
+ ListCost: opencost.CostMetric{
|
|
|
+ Cost: 1,
|
|
|
+ KubernetesPercent: 1,
|
|
|
+ },
|
|
|
+ NetCost: opencost.CostMetric{
|
|
|
+ Cost: 2,
|
|
|
+ KubernetesPercent: 1,
|
|
|
+ },
|
|
|
+ AmortizedNetCost: opencost.CostMetric{
|
|
|
+ Cost: 3,
|
|
|
+ KubernetesPercent: 1,
|
|
|
+ },
|
|
|
+ InvoicedCost: opencost.CostMetric{
|
|
|
+ Cost: 2,
|
|
|
+ KubernetesPercent: 1,
|
|
|
+ },
|
|
|
+ AmortizedCost: opencost.CostMetric{
|
|
|
+ Cost: 4,
|
|
|
+ KubernetesPercent: 1,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ wantErr: false,
|
|
|
+ },
|
|
|
}
|
|
|
for _, tt := range tests {
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
@@ -399,58 +471,13 @@ func stringsToRow(strings []string) types.Row {
|
|
|
return types.Row{Data: data}
|
|
|
}
|
|
|
|
|
|
-// mockAthenaQuerier is a mock that overrides HasBillingPeriodPartitions for testing
|
|
|
-type mockAthenaQuerier struct {
|
|
|
- AthenaQuerier
|
|
|
- hasBillingPeriodPartitions bool
|
|
|
-}
|
|
|
-
|
|
|
-func (m *mockAthenaQuerier) HasBillingPeriodPartitions() (bool, error) {
|
|
|
- return m.hasBillingPeriodPartitions, nil
|
|
|
-}
|
|
|
-
|
|
|
-// mockAthenaIntegration is a mock that uses mockAthenaQuerier
|
|
|
-type mockAthenaIntegration struct {
|
|
|
- *mockAthenaQuerier
|
|
|
-}
|
|
|
-
|
|
|
-func (m *mockAthenaIntegration) GetPartitionWhere(start, end time.Time) string {
|
|
|
- // The partition logic using our mock's HasBillingPeriodPartitions result
|
|
|
- month := time.Date(start.Year(), start.Month(), 1, 0, 0, 0, 0, time.UTC)
|
|
|
- endMonth := time.Date(end.Year(), end.Month(), 1, 0, 0, 0, 0, time.UTC)
|
|
|
- var disjuncts []string
|
|
|
-
|
|
|
- // Using our mock's result for billing period partitions
|
|
|
- useBillingPeriodPartitions := false
|
|
|
- if m.mockAthenaQuerier.AthenaConfiguration.CURVersion != "1.0" {
|
|
|
- useBillingPeriodPartitions = m.mockAthenaQuerier.hasBillingPeriodPartitions
|
|
|
- }
|
|
|
-
|
|
|
- for !month.After(endMonth) {
|
|
|
- if m.mockAthenaQuerier.AthenaConfiguration.CURVersion == "1.0" {
|
|
|
- // CUR 1.0 uses year and month columns for partitioning
|
|
|
- disjuncts = append(disjuncts, fmt.Sprintf("(year = '%d' AND month = '%d')", month.Year(), month.Month()))
|
|
|
- } else if useBillingPeriodPartitions {
|
|
|
- // CUR 2.0 with billing_period partitions
|
|
|
- disjuncts = append(disjuncts, fmt.Sprintf("(billing_period = '%d-%02d')", month.Year(), month.Month()))
|
|
|
- } else {
|
|
|
- // CUR 2.0 fallback - use date_format functions
|
|
|
- disjuncts = append(disjuncts, fmt.Sprintf("(date_format(line_item_usage_start_date, '%%Y') = '%d' AND date_format(line_item_usage_start_date, '%%m') = '%02d')",
|
|
|
- month.Year(), month.Month()))
|
|
|
- }
|
|
|
- month = month.AddDate(0, 1, 0)
|
|
|
- }
|
|
|
- return fmt.Sprintf("(%s)", strings.Join(disjuncts, " OR "))
|
|
|
-}
|
|
|
-
|
|
|
func TestAthenaIntegration_GetPartitionWhere(t *testing.T) {
|
|
|
testCases := map[string]struct {
|
|
|
- integration interface {
|
|
|
- GetPartitionWhere(time.Time, time.Time) string
|
|
|
- }
|
|
|
- start time.Time
|
|
|
- end time.Time
|
|
|
- expected string
|
|
|
+ integration *AthenaIntegration
|
|
|
+ start time.Time
|
|
|
+ end time.Time
|
|
|
+ resourceTagsColumn bool
|
|
|
+ expected string
|
|
|
}{
|
|
|
"CUR 1.0 single month": {
|
|
|
integration: &AthenaIntegration{
|
|
|
@@ -463,35 +490,32 @@ func TestAthenaIntegration_GetPartitionWhere(t *testing.T) {
|
|
|
Workgroup: "workgroup",
|
|
|
Account: "account",
|
|
|
Authorizer: &ServiceAccount{},
|
|
|
- CURVersion: "1.0",
|
|
|
},
|
|
|
},
|
|
|
},
|
|
|
- start: time.Date(2024, 1, 15, 0, 0, 0, 0, time.UTC),
|
|
|
- end: time.Date(2024, 1, 25, 0, 0, 0, 0, time.UTC),
|
|
|
- expected: "((year = '2024' AND month = '1'))",
|
|
|
+ start: time.Date(2024, 1, 15, 0, 0, 0, 0, time.UTC),
|
|
|
+ end: time.Date(2024, 1, 25, 0, 0, 0, 0, time.UTC),
|
|
|
+ resourceTagsColumn: false,
|
|
|
+ expected: "((year = '2024' AND month = '1'))",
|
|
|
},
|
|
|
"CUR 2.0 single month": {
|
|
|
- integration: &mockAthenaIntegration{
|
|
|
- mockAthenaQuerier: &mockAthenaQuerier{
|
|
|
- AthenaQuerier: AthenaQuerier{
|
|
|
- AthenaConfiguration: AthenaConfiguration{
|
|
|
- Bucket: "bucket",
|
|
|
- Region: "region",
|
|
|
- Database: "database",
|
|
|
- Table: "table",
|
|
|
- Workgroup: "workgroup",
|
|
|
- Account: "account",
|
|
|
- Authorizer: &ServiceAccount{},
|
|
|
- CURVersion: "2.0",
|
|
|
- },
|
|
|
+ integration: &AthenaIntegration{
|
|
|
+ AthenaQuerier: AthenaQuerier{
|
|
|
+ AthenaConfiguration: AthenaConfiguration{
|
|
|
+ Bucket: "bucket",
|
|
|
+ Region: "region",
|
|
|
+ Database: "database",
|
|
|
+ Table: "table",
|
|
|
+ Workgroup: "workgroup",
|
|
|
+ Account: "account",
|
|
|
+ Authorizer: &ServiceAccount{},
|
|
|
},
|
|
|
- hasBillingPeriodPartitions: true,
|
|
|
},
|
|
|
},
|
|
|
- start: time.Date(2024, 1, 15, 0, 0, 0, 0, time.UTC),
|
|
|
- end: time.Date(2024, 1, 25, 0, 0, 0, 0, time.UTC),
|
|
|
- expected: "((billing_period = '2024-01'))",
|
|
|
+ start: time.Date(2024, 1, 15, 0, 0, 0, 0, time.UTC),
|
|
|
+ end: time.Date(2024, 1, 25, 0, 0, 0, 0, time.UTC),
|
|
|
+ resourceTagsColumn: true,
|
|
|
+ expected: "((billing_period = '2024-01'))",
|
|
|
},
|
|
|
"CUR 1.0 multiple months": {
|
|
|
integration: &AthenaIntegration{
|
|
|
@@ -504,57 +528,51 @@ func TestAthenaIntegration_GetPartitionWhere(t *testing.T) {
|
|
|
Workgroup: "workgroup",
|
|
|
Account: "account",
|
|
|
Authorizer: &ServiceAccount{},
|
|
|
- CURVersion: "1.0",
|
|
|
},
|
|
|
},
|
|
|
},
|
|
|
- start: time.Date(2024, 1, 15, 0, 0, 0, 0, time.UTC),
|
|
|
- end: time.Date(2024, 3, 10, 0, 0, 0, 0, time.UTC),
|
|
|
- expected: "((year = '2024' AND month = '1') OR (year = '2024' AND month = '2') OR (year = '2024' AND month = '3'))",
|
|
|
+ start: time.Date(2024, 1, 15, 0, 0, 0, 0, time.UTC),
|
|
|
+ end: time.Date(2024, 3, 10, 0, 0, 0, 0, time.UTC),
|
|
|
+ resourceTagsColumn: false,
|
|
|
+ expected: "((year = '2024' AND month = '1') OR (year = '2024' AND month = '2') OR (year = '2024' AND month = '3'))",
|
|
|
},
|
|
|
"CUR 2.0 multiple months": {
|
|
|
- integration: &mockAthenaIntegration{
|
|
|
- mockAthenaQuerier: &mockAthenaQuerier{
|
|
|
- AthenaQuerier: AthenaQuerier{
|
|
|
- AthenaConfiguration: AthenaConfiguration{
|
|
|
- Bucket: "bucket",
|
|
|
- Region: "region",
|
|
|
- Database: "database",
|
|
|
- Table: "table",
|
|
|
- Workgroup: "workgroup",
|
|
|
- Account: "account",
|
|
|
- Authorizer: &ServiceAccount{},
|
|
|
- CURVersion: "2.0",
|
|
|
- },
|
|
|
+ integration: &AthenaIntegration{
|
|
|
+ AthenaQuerier: AthenaQuerier{
|
|
|
+ AthenaConfiguration: AthenaConfiguration{
|
|
|
+ Bucket: "bucket",
|
|
|
+ Region: "region",
|
|
|
+ Database: "database",
|
|
|
+ Table: "table",
|
|
|
+ Workgroup: "workgroup",
|
|
|
+ Account: "account",
|
|
|
+ Authorizer: &ServiceAccount{},
|
|
|
},
|
|
|
- hasBillingPeriodPartitions: true,
|
|
|
},
|
|
|
},
|
|
|
- start: time.Date(2024, 1, 15, 0, 0, 0, 0, time.UTC),
|
|
|
- end: time.Date(2024, 3, 10, 0, 0, 0, 0, time.UTC),
|
|
|
- expected: "((billing_period = '2024-01') OR (billing_period = '2024-02') OR (billing_period = '2024-03'))",
|
|
|
+ start: time.Date(2024, 1, 15, 0, 0, 0, 0, time.UTC),
|
|
|
+ end: time.Date(2024, 3, 10, 0, 0, 0, 0, time.UTC),
|
|
|
+ resourceTagsColumn: true,
|
|
|
+ expected: "((billing_period = '2024-01') OR (billing_period = '2024-02') OR (billing_period = '2024-03'))",
|
|
|
},
|
|
|
"CUR 2.0 across year boundary": {
|
|
|
- integration: &mockAthenaIntegration{
|
|
|
- mockAthenaQuerier: &mockAthenaQuerier{
|
|
|
- AthenaQuerier: AthenaQuerier{
|
|
|
- AthenaConfiguration: AthenaConfiguration{
|
|
|
- Bucket: "bucket",
|
|
|
- Region: "region",
|
|
|
- Database: "database",
|
|
|
- Table: "table",
|
|
|
- Workgroup: "workgroup",
|
|
|
- Account: "account",
|
|
|
- Authorizer: &ServiceAccount{},
|
|
|
- CURVersion: "2.0",
|
|
|
- },
|
|
|
+ integration: &AthenaIntegration{
|
|
|
+ AthenaQuerier: AthenaQuerier{
|
|
|
+ AthenaConfiguration: AthenaConfiguration{
|
|
|
+ Bucket: "bucket",
|
|
|
+ Region: "region",
|
|
|
+ Database: "database",
|
|
|
+ Table: "table",
|
|
|
+ Workgroup: "workgroup",
|
|
|
+ Account: "account",
|
|
|
+ Authorizer: &ServiceAccount{},
|
|
|
},
|
|
|
- hasBillingPeriodPartitions: true,
|
|
|
},
|
|
|
},
|
|
|
- start: time.Date(2023, 12, 15, 0, 0, 0, 0, time.UTC),
|
|
|
- end: time.Date(2024, 2, 10, 0, 0, 0, 0, time.UTC),
|
|
|
- expected: "((billing_period = '2023-12') OR (billing_period = '2024-01') OR (billing_period = '2024-02'))",
|
|
|
+ start: time.Date(2023, 12, 15, 0, 0, 0, 0, time.UTC),
|
|
|
+ end: time.Date(2024, 2, 10, 0, 0, 0, 0, time.UTC),
|
|
|
+ resourceTagsColumn: true,
|
|
|
+ expected: "((billing_period = '2023-12') OR (billing_period = '2024-01') OR (billing_period = '2024-02'))",
|
|
|
},
|
|
|
"CUR 1.0 across year boundary": {
|
|
|
integration: &AthenaIntegration{
|
|
|
@@ -567,63 +585,19 @@ func TestAthenaIntegration_GetPartitionWhere(t *testing.T) {
|
|
|
Workgroup: "workgroup",
|
|
|
Account: "account",
|
|
|
Authorizer: &ServiceAccount{},
|
|
|
- CURVersion: "1.0",
|
|
|
- },
|
|
|
- },
|
|
|
- },
|
|
|
- start: time.Date(2023, 12, 15, 0, 0, 0, 0, time.UTC),
|
|
|
- end: time.Date(2024, 2, 10, 0, 0, 0, 0, time.UTC),
|
|
|
- expected: "((year = '2023' AND month = '12') OR (year = '2024' AND month = '1') OR (year = '2024' AND month = '2'))",
|
|
|
- },
|
|
|
- "Default CUR version (empty string defaults to 2.0)": {
|
|
|
- integration: &mockAthenaIntegration{
|
|
|
- mockAthenaQuerier: &mockAthenaQuerier{
|
|
|
- AthenaQuerier: AthenaQuerier{
|
|
|
- AthenaConfiguration: AthenaConfiguration{
|
|
|
- Bucket: "bucket",
|
|
|
- Region: "region",
|
|
|
- Database: "database",
|
|
|
- Table: "table",
|
|
|
- Workgroup: "workgroup",
|
|
|
- Account: "account",
|
|
|
- Authorizer: &ServiceAccount{},
|
|
|
- CURVersion: "",
|
|
|
- },
|
|
|
- },
|
|
|
- hasBillingPeriodPartitions: true,
|
|
|
- },
|
|
|
- },
|
|
|
- start: time.Date(2024, 1, 15, 0, 0, 0, 0, time.UTC),
|
|
|
- end: time.Date(2024, 1, 25, 0, 0, 0, 0, time.UTC),
|
|
|
- expected: "((billing_period = '2024-01'))",
|
|
|
- },
|
|
|
- "CUR 2.0 fallback when no billing_period partitions": {
|
|
|
- integration: &mockAthenaIntegration{
|
|
|
- mockAthenaQuerier: &mockAthenaQuerier{
|
|
|
- AthenaQuerier: AthenaQuerier{
|
|
|
- AthenaConfiguration: AthenaConfiguration{
|
|
|
- Bucket: "bucket",
|
|
|
- Region: "region",
|
|
|
- Database: "database",
|
|
|
- Table: "table",
|
|
|
- Workgroup: "workgroup",
|
|
|
- Account: "account",
|
|
|
- Authorizer: &ServiceAccount{},
|
|
|
- CURVersion: "2.0",
|
|
|
- },
|
|
|
},
|
|
|
- hasBillingPeriodPartitions: false, // No billing_period partitions
|
|
|
},
|
|
|
},
|
|
|
- start: time.Date(2024, 1, 15, 0, 0, 0, 0, time.UTC),
|
|
|
- end: time.Date(2024, 1, 25, 0, 0, 0, 0, time.UTC),
|
|
|
- expected: "((date_format(line_item_usage_start_date, '%Y') = '2024' AND date_format(line_item_usage_start_date, '%m') = '01'))",
|
|
|
+ start: time.Date(2023, 12, 15, 0, 0, 0, 0, time.UTC),
|
|
|
+ end: time.Date(2024, 2, 10, 0, 0, 0, 0, time.UTC),
|
|
|
+ resourceTagsColumn: false,
|
|
|
+ expected: "((year = '2023' AND month = '12') OR (year = '2024' AND month = '1') OR (year = '2024' AND month = '2'))",
|
|
|
},
|
|
|
}
|
|
|
|
|
|
for name, testCase := range testCases {
|
|
|
t.Run(name, func(t *testing.T) {
|
|
|
- actual := testCase.integration.GetPartitionWhere(testCase.start, testCase.end)
|
|
|
+ actual := testCase.integration.GetPartitionWhere(testCase.start, testCase.end, testCase.resourceTagsColumn)
|
|
|
if actual != testCase.expected {
|
|
|
t.Errorf("GetPartitionWhere() mismatch:\nActual: %s\nExpected: %s", actual, testCase.expected)
|
|
|
}
|