blob: 80c7bd008c526613c87130447d3a18ec54cd4ac5 [file] [log] [blame]
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package billing_test
import (
"context"
"testing"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-provider-google-beta/google-beta/acctest"
"github.com/hashicorp/terraform-provider-google-beta/google-beta/envvar"
"github.com/hashicorp/terraform-provider-google-beta/google-beta/services/billing"
transport_tpg "github.com/hashicorp/terraform-provider-google-beta/google-beta/transport"
)
func TestAccBillingBudget_billingBudgetCurrencycode(t *testing.T) {
t.Parallel()
context := map[string]interface{}{
"billing_acct": envvar.GetTestMasterBillingAccountFromEnv(t),
"random_suffix": acctest.RandString(t, 10),
}
acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
CheckDestroy: testAccCheckBillingBudgetDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccBillingBudget_billingBudgetCurrencycode(context),
Check: resource.ComposeTestCheckFunc(),
},
},
})
}
func testAccBillingBudget_billingBudgetCurrencycode(context map[string]interface{}) string {
return acctest.Nprintf(`
data "google_billing_account" "account" {
billing_account = "%{billing_acct}"
}
data "google_project" "project" {
}
resource "google_billing_budget" "budget" {
billing_account = data.google_billing_account.account.id
display_name = "Example Billing Budget%{random_suffix}"
budget_filter {
projects = ["projects/${data.google_project.project.number}"]
labels = {
label = "bar"
}
}
amount {
specified_amount {
units = "100000"
}
}
threshold_rules {
threshold_percent = 1.0
}
threshold_rules {
threshold_percent = 1.0
spend_basis = "FORECASTED_SPEND"
}
}
`, context)
}
func TestAccBillingBudget_billingBudgetUpdate(t *testing.T) {
t.Parallel()
context := map[string]interface{}{
"billing_acct": envvar.GetTestMasterBillingAccountFromEnv(t),
"random_suffix": acctest.RandString(t, 10),
}
acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
CheckDestroy: testAccCheckBillingBudgetDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccBillingBudget_billingBudgetUpdateStart(context),
},
{
ResourceName: "google_billing_budget.budget",
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccBillingBudget_billingBudgetUpdateRemoveFilter(context),
},
{
ResourceName: "google_billing_budget.budget",
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccBillingBudget_billingBudgetCalendarUpdate(context),
},
{
ResourceName: "google_billing_budget.budget",
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccBillingBudget_billingBudgetUpdate(context),
},
{
ResourceName: "google_billing_budget.budget",
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccBillingBudget_billingBudgetCustomPeriodUpdate(context),
},
{
ResourceName: "google_billing_budget.budget",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func TestAccBillingBudget_billingFilterSubaccounts(t *testing.T) {
t.Parallel()
context := map[string]interface{}{
"master_billing_acct": envvar.GetTestMasterBillingAccountFromEnv(t),
"random_suffix": acctest.RandString(t, 10),
}
acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
CheckDestroy: testAccCheckBillingBudgetDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccBillingBudget_billingFilterSubaccounts(context),
},
{
ResourceName: "google_billing_budget.budget",
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccBillingBudget_billingFilterRemoveSubaccounts(context),
},
{
ResourceName: "google_billing_budget.budget",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func testAccBillingBudget_billingFilterSubaccounts(context map[string]interface{}) string {
return acctest.Nprintf(`
data "google_billing_account" "account" {
billing_account = "%{master_billing_acct}"
}
data "google_project" "project" {
}
resource "google_billing_subaccount" "subaccount" {
display_name = "My Billing Account"
master_billing_account = data.google_billing_account.account.id
}
resource "google_billing_budget" "budget" {
billing_account = data.google_billing_account.account.id
display_name = "Example Billing Budget%{random_suffix}"
budget_filter {
projects = ["projects/${data.google_project.project.number}"]
labels = {
label = "bar"
}
subaccounts = ["billingAccounts/${google_billing_subaccount.subaccount.billing_account_id}"]
}
amount {
specified_amount {
units = "100000"
}
}
threshold_rules {
threshold_percent = 1.0
}
threshold_rules {
threshold_percent = 1.0
spend_basis = "FORECASTED_SPEND"
}
}
`, context)
}
func testAccBillingBudget_billingFilterRemoveSubaccounts(context map[string]interface{}) string {
return acctest.Nprintf(`
data "google_billing_account" "account" {
billing_account = "%{master_billing_acct}"
}
data "google_project" "project" {
}
resource "google_billing_budget" "budget" {
billing_account = data.google_billing_account.account.id
display_name = "Example Billing Budget%{random_suffix}"
budget_filter {
projects = ["projects/${data.google_project.project.number}"]
labels = {
label = "bar"
}
subaccounts = []
}
amount {
specified_amount {
units = "100000"
}
}
threshold_rules {
threshold_percent = 1.0
}
threshold_rules {
threshold_percent = 1.0
spend_basis = "FORECASTED_SPEND"
}
}
`, context)
}
func testAccBillingBudget_billingBudgetUpdateStart(context map[string]interface{}) string {
return acctest.Nprintf(`
resource "google_pubsub_topic" "topic1" {
name = "tf-test-billing-budget1-%{random_suffix}"
}
resource "google_pubsub_topic" "topic2" {
name = "tf-test-billing-budget2-%{random_suffix}"
}
data "google_billing_account" "account" {
billing_account = "%{billing_acct}"
}
data "google_project" "project" {
}
resource "google_billing_budget" "budget" {
billing_account = data.google_billing_account.account.id
display_name = "Example Billing Budget%{random_suffix}"
budget_filter {
projects = ["projects/${data.google_project.project.number}"]
labels = {
label = "bar"
}
credit_types_treatment = "EXCLUDE_ALL_CREDITS"
}
amount {
specified_amount {
currency_code = "USD"
units = "100000"
}
}
threshold_rules {
threshold_percent = 0.5
}
threshold_rules {
threshold_percent = 0.9
spend_basis = "FORECASTED_SPEND"
}
all_updates_rule {
pubsub_topic = google_pubsub_topic.topic1.id
}
}
`, context)
}
func testAccBillingBudget_billingBudgetUpdateRemoveFilter(context map[string]interface{}) string {
return acctest.Nprintf(`
resource "google_pubsub_topic" "topic1" {
name = "tf-test-billing-budget1-%{random_suffix}"
}
resource "google_pubsub_topic" "topic2" {
name = "tf-test-billing-budget2-%{random_suffix}"
}
data "google_billing_account" "account" {
billing_account = "%{billing_acct}"
}
data "google_project" "project" {
}
resource "google_billing_budget" "budget" {
billing_account = data.google_billing_account.account.id
display_name = "Example Billing Budget%{random_suffix}"
budget_filter {
projects = []
labels = {}
}
amount {
specified_amount {
currency_code = "USD"
units = "100000"
}
}
threshold_rules {
threshold_percent = 0.5
}
threshold_rules {
threshold_percent = 0.9
spend_basis = "FORECASTED_SPEND"
}
all_updates_rule {
pubsub_topic = google_pubsub_topic.topic1.id
}
}
`, context)
}
func testAccBillingBudget_billingBudgetUpdate(context map[string]interface{}) string {
return acctest.Nprintf(`
resource "google_pubsub_topic" "topic1" {
name = "tf-test-billing-budget1-%{random_suffix}"
}
resource "google_pubsub_topic" "topic2" {
name = "tf-test-billing-budget2-%{random_suffix}"
}
data "google_billing_account" "account" {
billing_account = "%{billing_acct}"
}
data "google_project" "project" {
}
resource "google_billing_budget" "budget" {
billing_account = data.google_billing_account.account.id
display_name = "Example Billing Budget%{random_suffix}"
budget_filter {
projects = []
labels = {
label1 = "bar2"
}
credit_types_treatment = "INCLUDE_SPECIFIED_CREDITS"
services = ["services/24E6-581D-38E5"] # Bigquery
credit_types = ["PROMOTION", "FREE_TIER"]
}
amount {
specified_amount {
currency_code = "USD"
units = "2000"
}
}
threshold_rules {
threshold_percent = 0.5
}
threshold_rules {
threshold_percent = 0.9
spend_basis = "FORECASTED_SPEND"
}
all_updates_rule {
pubsub_topic = google_pubsub_topic.topic2.id
}
}
`, context)
}
func testAccBillingBudget_billingBudgetCalendarUpdate(context map[string]interface{}) string {
return acctest.Nprintf(`
resource "google_pubsub_topic" "topic1" {
name = "tf-test-billing-budget1-%{random_suffix}"
}
resource "google_pubsub_topic" "topic2" {
name = "tf-test-billing-budget2-%{random_suffix}"
}
data "google_billing_account" "account" {
billing_account = "%{billing_acct}"
}
data "google_project" "project" {
}
resource "google_billing_budget" "budget" {
billing_account = data.google_billing_account.account.id
display_name = "Example Billing Budget%{random_suffix}"
budget_filter {
projects = []
labels = {
label1 = "bar2"
}
calendar_period = "YEAR"
}
amount {
specified_amount {
currency_code = "USD"
units = "2000"
}
}
threshold_rules {
threshold_percent = 0.5
}
threshold_rules {
threshold_percent = 0.9
}
all_updates_rule {
pubsub_topic = google_pubsub_topic.topic2.id
}
}
`, context)
}
func testAccBillingBudget_billingBudgetCustomPeriodUpdate(context map[string]interface{}) string {
return acctest.Nprintf(`
resource "google_pubsub_topic" "topic1" {
name = "tf-test-billing-budget1-%{random_suffix}"
}
resource "google_pubsub_topic" "topic2" {
name = "tf-test-billing-budget2-%{random_suffix}"
}
data "google_billing_account" "account" {
billing_account = "%{billing_acct}"
}
data "google_project" "project" {
}
resource "google_billing_budget" "budget" {
billing_account = data.google_billing_account.account.id
display_name = "Example Billing Budget%{random_suffix}"
budget_filter {
projects = []
labels = {
label1 = "bar2"
}
custom_period {
start_date {
year = 2022
month = 1
day = 1
}
end_date {
year = 2023
month = 12
day = 31
}
}
credit_types = []
}
amount {
specified_amount {
currency_code = "USD"
units = "2000"
}
}
threshold_rules {
threshold_percent = 0.5
}
threshold_rules {
threshold_percent = 0.9
}
all_updates_rule {
pubsub_topic = google_pubsub_topic.topic2.id
}
}
`, context)
}
func TestBillingBudgetStateUpgradeV0(t *testing.T) {
t.Parallel()
cases := map[string]struct {
Attributes map[string]interface{}
Expected map[string]string
Meta interface{}
}{
"shorten long name": {
Attributes: map[string]interface{}{
"name": "billingAccounts/000000-111111-222222/budgets/9188612e-e4c0-4e69-9d14-9befebbcb87d",
},
Expected: map[string]string{
"name": "9188612e-e4c0-4e69-9d14-9befebbcb87d",
},
Meta: &transport_tpg.Config{},
},
"short name stays": {
Attributes: map[string]interface{}{
"name": "9188612e-e4c0-4e69-9d14-9befebbcb87d",
},
Expected: map[string]string{
"name": "9188612e-e4c0-4e69-9d14-9befebbcb87d",
},
Meta: &transport_tpg.Config{},
},
}
for tn, tc := range cases {
t.Run(tn, func(t *testing.T) {
actual, err := billing.ResourceBillingBudgetUpgradeV0(context.Background(), tc.Attributes, tc.Meta)
if err != nil {
t.Error(err)
}
for _, expectedName := range tc.Expected {
if actual["name"] != expectedName {
t.Errorf("expected: name -> %#v\n got: name -> %#v\n in: %#v",
expectedName, actual["name"], actual)
}
}
})
}
}
func TestAccBillingBudget_budgetFilterProjectsOrdering(t *testing.T) {
t.Parallel()
context := map[string]interface{}{
"org": envvar.GetTestOrgFromEnv(t),
"billing_acct": envvar.GetTestMasterBillingAccountFromEnv(t),
"project_billing_acct": envvar.GetTestBillingAccountFromEnv(t),
"random_suffix_1": acctest.RandString(t, 10),
"random_suffix_2": acctest.RandString(t, 10),
}
acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
CheckDestroy: testAccCheckBillingBudgetDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccBillingBudget_budgetFilterProjectsOrdering1(context),
},
{
ResourceName: "google_billing_budget.budget",
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccBillingBudget_budgetFilterProjectsOrdering2(context),
PlanOnly: true,
ExpectNonEmptyPlan: false,
},
{
ResourceName: "google_billing_budget.budget",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func testAccBillingBudget_budgetFilterProjectsOrdering1(context map[string]interface{}) string {
return acctest.Nprintf(`
data "google_billing_account" "account" {
billing_account = "%{billing_acct}"
}
resource "google_project" "project1" {
project_id = "tf-test-%{random_suffix_1}"
name = "tf-test-%{random_suffix_1}"
org_id = "%{org}"
billing_account = "%{project_billing_acct}"
deletion_policy = "DELETE"
}
resource "google_project" "project2" {
project_id = "tf-test-%{random_suffix_2}"
name = "tf-test-%{random_suffix_2}"
org_id = "%{org}"
billing_account = "%{project_billing_acct}"
deletion_policy = "DELETE"
}
resource "google_billing_budget" "budget" {
billing_account = data.google_billing_account.account.id
display_name = "Example Billing Budget"
budget_filter {
projects = [
"projects/${google_project.project1.number}",
"projects/${google_project.project2.number}",
]
}
amount {
last_period_amount = true
}
threshold_rules {
threshold_percent = 10.0
}
}
`, context)
}
func testAccBillingBudget_budgetFilterProjectsOrdering2(context map[string]interface{}) string {
return acctest.Nprintf(`
data "google_billing_account" "account" {
billing_account = "%{billing_acct}"
}
resource "google_project" "project1" {
project_id = "tf-test-%{random_suffix_1}"
name = "tf-test-%{random_suffix_1}"
org_id = "%{org}"
billing_account = "%{project_billing_acct}"
deletion_policy = "DELETE"
}
resource "google_project" "project2" {
project_id = "tf-test-%{random_suffix_2}"
name = "tf-test-%{random_suffix_2}"
org_id = "%{org}"
billing_account = "%{project_billing_acct}"
deletion_policy = "DELETE"
}
resource "google_billing_budget" "budget" {
billing_account = data.google_billing_account.account.id
display_name = "Example Billing Budget"
budget_filter {
projects = [
"projects/${google_project.project2.number}",
"projects/${google_project.project1.number}",
]
}
amount {
last_period_amount = true
}
threshold_rules {
threshold_percent = 10.0
}
}
`, context)
}