diff --git a/internal/billing/repository_test.go b/internal/billing/repository_test.go index 3a8b00976e..8276136ac6 100644 --- a/internal/billing/repository_test.go +++ b/internal/billing/repository_test.go @@ -74,8 +74,16 @@ func TestRepository_MonthlyActiveUsers(t *testing.T) { TestGenerateActiveUsers(t, conn) today := time.Now().UTC() - threeMonthsAgo := time.Date(today.AddDate(0, -3, 0).Year(), today.AddDate(0, -3, 0).Month(), 1, 0, 0, 0, 0, time.UTC) - oneMonthAgo := time.Date(today.AddDate(0, -1, 0).Year(), today.AddDate(0, -1, 0).Month(), 1, 0, 0, 0, 0, time.UTC) + // Some time calculations are impacted when using the current day vs. the + // start of the month. For example, if... + // today -> May 30th + // today.AddDate(0, -3, 0).Month() -> March + // February was expected here, but we get March. This seems to be a + // rounding thing since February 30th is not a valid date. Instead, the + // start of the month is used to ensure the correct months are calculated. + monthStart := time.Date(today.Year(), today.Month(), 1, 0, 0, 0, 0, time.UTC) + threeMonthsAgo := time.Date(monthStart.AddDate(0, -3, 0).Year(), monthStart.AddDate(0, -3, 0).Month(), 1, 0, 0, 0, 0, time.UTC) + oneMonthAgo := time.Date(monthStart.AddDate(0, -1, 0).Year(), monthStart.AddDate(0, -1, 0).Month(), 1, 0, 0, 0, 0, time.UTC) midMonth := time.Date(today.Year(), today.Month(), 15, 0, 0, 0, 0, time.UTC) t.Run("valid-no-options", func(t *testing.T) { @@ -125,14 +133,14 @@ func TestRepository_MonthlyActiveUsers(t *testing.T) { activeUsers, err := repo.MonthlyActiveUsers(ctx, WithStartTime(&threeMonthsAgo), WithEndTime(&oneMonthAgo)) assert.NoError(t, err) require.Len(t, activeUsers, 2) - expectedStartTime := time.Date(today.AddDate(0, -2, 0).Year(), today.AddDate(0, -2, 0).Month(), 1, 0, 0, 0, 0, time.UTC) - expectedEndTime := time.Date(today.AddDate(0, -1, 0).Year(), today.AddDate(0, -1, 0).Month(), 1, 0, 0, 0, 0, time.UTC) + expectedStartTime := time.Date(monthStart.AddDate(0, -2, 0).Year(), monthStart.AddDate(0, -2, 0).Month(), 1, 0, 0, 0, 0, time.UTC) + expectedEndTime := time.Date(monthStart.AddDate(0, -1, 0).Year(), monthStart.AddDate(0, -1, 0).Month(), 1, 0, 0, 0, 0, time.UTC) require.Equal(t, uint32(6), activeUsers[0].ActiveUsersCount) assert.Equal(t, expectedStartTime, activeUsers[0].StartTime) assert.Equal(t, expectedEndTime, activeUsers[0].EndTime) - expectedStartTime = time.Date(today.AddDate(0, -3, 0).Year(), today.AddDate(0, -3, 0).Month(), 1, 0, 0, 0, 0, time.UTC) - expectedEndTime = time.Date(today.AddDate(0, -2, 0).Year(), today.AddDate(0, -2, 0).Month(), 1, 0, 0, 0, 0, time.UTC) + expectedStartTime = time.Date(monthStart.AddDate(0, -3, 0).Year(), monthStart.AddDate(0, -3, 0).Month(), 1, 0, 0, 0, 0, time.UTC) + expectedEndTime = time.Date(monthStart.AddDate(0, -2, 0).Year(), monthStart.AddDate(0, -2, 0).Month(), 1, 0, 0, 0, 0, time.UTC) require.Equal(t, uint32(6), activeUsers[1].ActiveUsersCount) assert.Equal(t, expectedStartTime, activeUsers[1].StartTime) assert.Equal(t, expectedEndTime, activeUsers[1].EndTime) diff --git a/internal/daemon/controller/handlers/billing/billing_service_test.go b/internal/daemon/controller/handlers/billing/billing_service_test.go index 07ec26b743..beeb2c5ce1 100644 --- a/internal/daemon/controller/handlers/billing/billing_service_test.go +++ b/internal/daemon/controller/handlers/billing/billing_service_test.go @@ -41,8 +41,16 @@ func Test_MonthlyActiveUsers(t *testing.T) { } today := time.Now().UTC() - threeMonthsAgo := time.Date(today.AddDate(0, -3, 0).Year(), today.AddDate(0, -3, 0).Month(), 1, 0, 0, 0, 0, time.UTC).Format("2006-01") - oneMonthAgo := time.Date(today.AddDate(0, -1, 0).Year(), today.AddDate(0, -1, 0).Month(), 1, 0, 0, 0, 0, time.UTC).Format("2006-01") + // Some time calculations are impacted when using the current day vs. the + // start of the month. For example, if... + // today -> May 30th + // today.AddDate(0, -3, 0).Month() -> March + // February was expected here, but we get March. This seems to be a + // rounding thing since February 30th is not a valid date. Instead, the + // start of the month is used to ensure the correct months are calculated. + monthStart := time.Date(today.Year(), today.Month(), 1, 0, 0, 0, 0, time.UTC) + threeMonthsAgo := time.Date(monthStart.AddDate(0, -3, 0).Year(), monthStart.AddDate(0, -3, 0).Month(), 1, 0, 0, 0, 0, time.UTC).Format("2006-01") + oneMonthAgo := time.Date(monthStart.AddDate(0, -1, 0).Year(), monthStart.AddDate(0, -1, 0).Month(), 1, 0, 0, 0, 0, time.UTC).Format("2006-01") badFormat := time.Date(today.Year(), today.Month(), 15, 0, 0, 0, 0, time.UTC).String() cases := []struct { diff --git a/internal/db/sqltest/tests/hcp/billing/monthly_active_users_all_timezone.sql b/internal/db/sqltest/tests/hcp/billing/monthly_active_users_all_timezone.sql index c6828a98aa..d5f46bd7b2 100644 --- a/internal/db/sqltest/tests/hcp/billing/monthly_active_users_all_timezone.sql +++ b/internal/db/sqltest/tests/hcp/billing/monthly_active_users_all_timezone.sql @@ -2,7 +2,18 @@ -- SPDX-License-Identifier: BUSL-1.1 begin; - select plan(11); + select plan(27); + + create function test_is_not_same_month(start_time timestamptz, end_time timestamptz) returns boolean + as $$ + begin + if date_trunc('month', start_time) != date_trunc('month', end_time) then + return true; + end if; + return false; + end; + $$ language plpgsql; + select lives_ok('truncate wh_auth_token_accumulating_fact, wh_user_dimension, wh_session_accumulating_fact, @@ -82,98 +93,123 @@ begin; select is(count(*), 6::bigint, 'wh_user_dimension is not empty') from wh_user_dimension; -- calling the view directly yields results at NZ month boundaries. - select results_eq( - 'select * from hcp_billing_monthly_active_users_all', - $$ - values (date_trunc('month', now(), 'nz'), date_trunc('hour', now(), 'nz'), 0::bigint), - (date_trunc('month', now() - interval '1 month', 'nz'), date_trunc('month', now(), 'nz'), 6::bigint), - (date_trunc('month', now() - interval '2 month', 'nz'), date_trunc('month', now() - interval '1 month', 'nz'), 6::bigint), - (date_trunc('month', now() - interval '3 month', 'nz'), date_trunc('month', now() - interval '2 month', 'nz'), 6::bigint), - (date_trunc('month', now() - interval '4 month', 'nz'), date_trunc('month', now() - interval '3 month', 'nz'), 6::bigint), - (date_trunc('month', now() - interval '5 month', 'nz'), date_trunc('month', now() - interval '4 month', 'nz'), 6::bigint), - (date_trunc('month', now() - interval '6 month', 'nz'), date_trunc('month', now() - interval '5 month', 'nz'), 6::bigint), - (date_trunc('month', now() - interval '7 month', 'nz'), date_trunc('month', now() - interval '6 month', 'nz'), 6::bigint), - (date_trunc('month', now() - interval '8 month', 'nz'), date_trunc('month', now() - interval '7 month', 'nz'), 6::bigint), - (date_trunc('month', now() - interval '9 month', 'nz'), date_trunc('month', now() - interval '8 month', 'nz'), 6::bigint), - (date_trunc('month', now() - interval '10 month', 'nz'), date_trunc('month', now() - interval '9 month', 'nz'), 6::bigint), - (date_trunc('month', now() - interval '11 month', 'nz'), date_trunc('month', now() - interval '10 month', 'nz'), 6::bigint), - (date_trunc('month', now() - interval '12 month', 'nz'), date_trunc('month', now() - interval '11 month', 'nz'), 6::bigint) - $$); + select case when test_is_not_same_month('yesterday'::timestamptz, now()) + then skip('certain tests don''t work on the first day of the month', 3) + else results_eq( + 'select * from hcp_billing_monthly_active_users_all', + $$ + values (date_trunc('month', now(), 'nz'), date_trunc('hour', now(), 'nz'), 0::bigint), + (date_trunc('month', now() - interval '1 month', 'nz'), date_trunc('month', now(), 'nz'), 6::bigint), + (date_trunc('month', now() - interval '2 month', 'nz'), date_trunc('month', now() - interval '1 month', 'nz'), 6::bigint), + (date_trunc('month', now() - interval '3 month', 'nz'), date_trunc('month', now() - interval '2 month', 'nz'), 6::bigint), + (date_trunc('month', now() - interval '4 month', 'nz'), date_trunc('month', now() - interval '3 month', 'nz'), 6::bigint), + (date_trunc('month', now() - interval '5 month', 'nz'), date_trunc('month', now() - interval '4 month', 'nz'), 6::bigint), + (date_trunc('month', now() - interval '6 month', 'nz'), date_trunc('month', now() - interval '5 month', 'nz'), 6::bigint), + (date_trunc('month', now() - interval '7 month', 'nz'), date_trunc('month', now() - interval '6 month', 'nz'), 6::bigint), + (date_trunc('month', now() - interval '8 month', 'nz'), date_trunc('month', now() - interval '7 month', 'nz'), 6::bigint), + (date_trunc('month', now() - interval '9 month', 'nz'), date_trunc('month', now() - interval '8 month', 'nz'), 6::bigint), + (date_trunc('month', now() - interval '10 month', 'nz'), date_trunc('month', now() - interval '9 month', 'nz'), 6::bigint), + (date_trunc('month', now() - interval '11 month', 'nz'), date_trunc('month', now() - interval '10 month', 'nz'), 6::bigint), + (date_trunc('month', now() - interval '12 month', 'nz'), date_trunc('month', now() - interval '11 month', 'nz'), 6::bigint) + $$) + end; + -- calling the function yields results at UTC month boundaries. - select results_eq( - 'select count(*) from hcp_billing_monthly_active_users_all()', - $$ - values (14::bigint); - $$); - select results_eq( - 'select * from hcp_billing_monthly_active_users_all()', - $$ - values (date_trunc('month', now(), 'utc'), date_trunc('hour', now(), 'utc'), 0::bigint), - (date_trunc('month', now() - interval '1 month', 'utc'), date_trunc('month', now(), 'utc'), 0::bigint), - (date_trunc('month', now() - interval '2 month', 'utc'), date_trunc('month', now() - interval '1 month', 'utc'), 6::bigint), - (date_trunc('month', now() - interval '3 month', 'utc'), date_trunc('month', now() - interval '2 month', 'utc'), 6::bigint), - (date_trunc('month', now() - interval '4 month', 'utc'), date_trunc('month', now() - interval '3 month', 'utc'), 6::bigint), - (date_trunc('month', now() - interval '5 month', 'utc'), date_trunc('month', now() - interval '4 month', 'utc'), 6::bigint), - (date_trunc('month', now() - interval '6 month', 'utc'), date_trunc('month', now() - interval '5 month', 'utc'), 6::bigint), - (date_trunc('month', now() - interval '7 month', 'utc'), date_trunc('month', now() - interval '6 month', 'utc'), 6::bigint), - (date_trunc('month', now() - interval '8 month', 'utc'), date_trunc('month', now() - interval '7 month', 'utc'), 6::bigint), - (date_trunc('month', now() - interval '9 month', 'utc'), date_trunc('month', now() - interval '8 month', 'utc'), 6::bigint), - (date_trunc('month', now() - interval '10 month', 'utc'), date_trunc('month', now() - interval '9 month', 'utc'), 6::bigint), - (date_trunc('month', now() - interval '11 month', 'utc'), date_trunc('month', now() - interval '10 month', 'utc'), 6::bigint), - (date_trunc('month', now() - interval '12 month', 'utc'), date_trunc('month', now() - interval '11 month', 'utc'), 6::bigint), - (date_trunc('month', now() - interval '13 month', 'utc'), date_trunc('month', now() - interval '12 month', 'utc'), 6::bigint) - $$); - select results_ne( + select case when test_is_not_same_month('yesterday'::timestamptz, now()) + then skip('certain tests don''t work on the first day of the month', 3) + else results_eq( + 'select count(*) from hcp_billing_monthly_active_users_all()', + $$ + values (14::bigint); + $$) + end; + select case when test_is_not_same_month('yesterday'::timestamptz, now()) + then skip('certain tests don''t work on the first day of the month', 3) + else results_eq( + 'select * from hcp_billing_monthly_active_users_all()', + $$ + values (date_trunc('month', now(), 'utc'), date_trunc('hour', now(), 'utc'), 0::bigint), + (date_trunc('month', now() - interval '1 month', 'utc'), date_trunc('month', now(), 'utc'), 0::bigint), + (date_trunc('month', now() - interval '2 month', 'utc'), date_trunc('month', now() - interval '1 month', 'utc'), 6::bigint), + (date_trunc('month', now() - interval '3 month', 'utc'), date_trunc('month', now() - interval '2 month', 'utc'), 6::bigint), + (date_trunc('month', now() - interval '4 month', 'utc'), date_trunc('month', now() - interval '3 month', 'utc'), 6::bigint), + (date_trunc('month', now() - interval '5 month', 'utc'), date_trunc('month', now() - interval '4 month', 'utc'), 6::bigint), + (date_trunc('month', now() - interval '6 month', 'utc'), date_trunc('month', now() - interval '5 month', 'utc'), 6::bigint), + (date_trunc('month', now() - interval '7 month', 'utc'), date_trunc('month', now() - interval '6 month', 'utc'), 6::bigint), + (date_trunc('month', now() - interval '8 month', 'utc'), date_trunc('month', now() - interval '7 month', 'utc'), 6::bigint), + (date_trunc('month', now() - interval '9 month', 'utc'), date_trunc('month', now() - interval '8 month', 'utc'), 6::bigint), + (date_trunc('month', now() - interval '10 month', 'utc'), date_trunc('month', now() - interval '9 month', 'utc'), 6::bigint), + (date_trunc('month', now() - interval '11 month', 'utc'), date_trunc('month', now() - interval '10 month', 'utc'), 6::bigint), + (date_trunc('month', now() - interval '12 month', 'utc'), date_trunc('month', now() - interval '11 month', 'utc'), 6::bigint), + (date_trunc('month', now() - interval '13 month', 'utc'), date_trunc('month', now() - interval '12 month', 'utc'), 6::bigint) + $$) + end; + select case when test_is_not_same_month('yesterday'::timestamptz, now()) + then skip('certain tests don''t work on the first day of the month', 3) + else results_ne( 'select * from hcp_billing_monthly_active_users_all()', - 'select * from hcp_billing_monthly_active_users_all'); + 'select * from hcp_billing_monthly_active_users_all') + end; -- can provide a start time (inclusive) to limit the results. - select results_eq( - $$ - select * from hcp_billing_monthly_active_users_all(date_trunc('month', now() - interval '5 month', 'utc')); - $$, - $$ - values (date_trunc('month', now(), 'utc'), date_trunc('hour', now(), 'utc'), 0::bigint), - (date_trunc('month', now() - interval '1 month', 'utc'), date_trunc('month', now(), 'utc'), 0::bigint), - (date_trunc('month', now() - interval '2 month', 'utc'), date_trunc('month', now() - interval '1 month', 'utc'), 6::bigint), - (date_trunc('month', now() - interval '3 month', 'utc'), date_trunc('month', now() - interval '2 month', 'utc'), 6::bigint), - (date_trunc('month', now() - interval '4 month', 'utc'), date_trunc('month', now() - interval '3 month', 'utc'), 6::bigint), - (date_trunc('month', now() - interval '5 month', 'utc'), date_trunc('month', now() - interval '4 month', 'utc'), 6::bigint) - $$); - -- can provide a start time (inclusive) and end time (exclusive) to limit results. - select results_eq( - $$ - select * from hcp_billing_monthly_active_users_all(date_trunc('month', now() - interval '5 month', 'utc'), - date_trunc('month', now() - interval '3 month', 'utc')); - $$, - $$ - values (date_trunc('month', now() - interval '4 month', 'utc'), date_trunc('month', now() - interval '3 month', 'utc'), 6::bigint), - (date_trunc('month', now() - interval '5 month', 'utc'), date_trunc('month', now() - interval '4 month', 'utc'), 6::bigint) - $$); + select case when test_is_not_same_month('yesterday'::timestamptz, now()) + then skip('certain tests don''t work on the first day of the month', 3) + else results_eq( + $$ + select * from hcp_billing_monthly_active_users_all(date_trunc('month', now() - interval '5 month', 'utc')); + $$, + $$ + values (date_trunc('month', now(), 'utc'), date_trunc('hour', now(), 'utc'), 0::bigint), + (date_trunc('month', now() - interval '1 month', 'utc'), date_trunc('month', now(), 'utc'), 0::bigint), + (date_trunc('month', now() - interval '2 month', 'utc'), date_trunc('month', now() - interval '1 month', 'utc'), 6::bigint), + (date_trunc('month', now() - interval '3 month', 'utc'), date_trunc('month', now() - interval '2 month', 'utc'), 6::bigint), + (date_trunc('month', now() - interval '4 month', 'utc'), date_trunc('month', now() - interval '3 month', 'utc'), 6::bigint), + (date_trunc('month', now() - interval '5 month', 'utc'), date_trunc('month', now() - interval '4 month', 'utc'), 6::bigint) + $$) + end; + -- can provide a start time (inclusive) and end time (exclusive) to limit results. + select case when test_is_not_same_month('yesterday'::timestamptz, now()) + then skip('certain tests don''t work on the first day of the month', 3) + else results_eq( + $$ + select * from hcp_billing_monthly_active_users_all(date_trunc('month', now() - interval '5 month', 'utc'), + date_trunc('month', now() - interval '3 month', 'utc')); + $$, + $$ + values (date_trunc('month', now() - interval '4 month', 'utc'), date_trunc('month', now() - interval '3 month', 'utc'), 6::bigint), + (date_trunc('month', now() - interval '5 month', 'utc'), date_trunc('month', now() - interval '4 month', 'utc'), 6::bigint) + $$) + end; -- can provide an end time (exclusive) to limit results. - select results_eq( - $$ - select * from hcp_billing_monthly_active_users_all(null, - date_trunc('month', now() - interval '3 month', 'utc')); - $$, - $$ - values (date_trunc('month', now() - interval '4 month', 'utc'), date_trunc('month', now() - interval '3 month', 'utc'), 6::bigint), - (date_trunc('month', now() - interval '5 month', 'utc'), date_trunc('month', now() - interval '4 month', 'utc'), 6::bigint), - (date_trunc('month', now() - interval '6 month', 'utc'), date_trunc('month', now() - interval '5 month', 'utc'), 6::bigint), - (date_trunc('month', now() - interval '7 month', 'utc'), date_trunc('month', now() - interval '6 month', 'utc'), 6::bigint), - (date_trunc('month', now() - interval '8 month', 'utc'), date_trunc('month', now() - interval '7 month', 'utc'), 6::bigint), - (date_trunc('month', now() - interval '9 month', 'utc'), date_trunc('month', now() - interval '8 month', 'utc'), 6::bigint), - (date_trunc('month', now() - interval '10 month', 'utc'), date_trunc('month', now() - interval '9 month', 'utc'), 6::bigint), - (date_trunc('month', now() - interval '11 month', 'utc'), date_trunc('month', now() - interval '10 month', 'utc'), 6::bigint), - (date_trunc('month', now() - interval '12 month', 'utc'), date_trunc('month', now() - interval '11 month', 'utc'), 6::bigint), - (date_trunc('month', now() - interval '13 month', 'utc'), date_trunc('month', now() - interval '12 month', 'utc'), 6::bigint) - $$); + select case when test_is_not_same_month('yesterday'::timestamptz, now()) + then skip('certain tests don''t work on the first day of the month', 3) + else results_eq( + $$ + select * from hcp_billing_monthly_active_users_all(null, + date_trunc('month', now() - interval '3 month', 'utc')); + $$, + $$ + values (date_trunc('month', now() - interval '4 month', 'utc'), date_trunc('month', now() - interval '3 month', 'utc'), 6::bigint), + (date_trunc('month', now() - interval '5 month', 'utc'), date_trunc('month', now() - interval '4 month', 'utc'), 6::bigint), + (date_trunc('month', now() - interval '6 month', 'utc'), date_trunc('month', now() - interval '5 month', 'utc'), 6::bigint), + (date_trunc('month', now() - interval '7 month', 'utc'), date_trunc('month', now() - interval '6 month', 'utc'), 6::bigint), + (date_trunc('month', now() - interval '8 month', 'utc'), date_trunc('month', now() - interval '7 month', 'utc'), 6::bigint), + (date_trunc('month', now() - interval '9 month', 'utc'), date_trunc('month', now() - interval '8 month', 'utc'), 6::bigint), + (date_trunc('month', now() - interval '10 month', 'utc'), date_trunc('month', now() - interval '9 month', 'utc'), 6::bigint), + (date_trunc('month', now() - interval '11 month', 'utc'), date_trunc('month', now() - interval '10 month', 'utc'), 6::bigint), + (date_trunc('month', now() - interval '12 month', 'utc'), date_trunc('month', now() - interval '11 month', 'utc'), 6::bigint), + (date_trunc('month', now() - interval '13 month', 'utc'), date_trunc('month', now() - interval '12 month', 'utc'), 6::bigint) + $$) + end; -- an end time that is before the start time will yield no results. - select is_empty( - $$ - select * from hcp_billing_monthly_active_users_all(date_trunc('month', now() - interval '2 month', 'utc'), - date_trunc('month', now() - interval '5 month', 'utc')); - $$); + select case when test_is_not_same_month('yesterday'::timestamptz, now()) + then skip('certain tests don''t work on the first day of the month', 3) + else is_empty( + $$ + select * from hcp_billing_monthly_active_users_all(date_trunc('month', now() - interval '2 month', 'utc'), + date_trunc('month', now() - interval '5 month', 'utc')); + $$) + end; select * from finish(); rollback;