blob: a790bcdd975ce6fbbe805ab9b69323e1abdc7356 [file] [log] [blame]
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package fwresource
import (
"strings"
"testing"
"github.com/hashicorp/terraform-plugin-framework/types"
)
func TestLocationDescription_GetZone(t *testing.T) {
cases := map[string]struct {
ld LocationDescription
ExpectedZone types.String
ExpectedError bool
}{
"returns the value of the zone field in resource config": {
ld: LocationDescription{
// A resource would not have all 3 fields set, but if they were all present zone is used
ResourceZone: types.StringValue("resource-zone-a"),
ResourceRegion: types.StringValue("resource-region"),
ResourceLocation: types.StringValue("resource-location"),
// Provider config doesn't override resource config
ProviderRegion: types.StringValue("provider-region"),
ProviderZone: types.StringValue("provider-zone-a"),
},
ExpectedZone: types.StringValue("resource-zone-a"),
},
"shortens zone values set as self links in the resource config": {
ld: LocationDescription{
ResourceZone: types.StringValue("https://www.googleapis.com/compute/v1/projects/my-project/zones/resource-zone-a"),
},
ExpectedZone: types.StringValue("resource-zone-a"),
},
"returns the value of the zone field in provider config when zone is unset in resource config": {
ld: LocationDescription{
ResourceLocation: types.StringValue("resource-location"), // unused
ResourceRegion: types.StringValue("resource-region"), // unused
ProviderZone: types.StringValue("provider-zone-a"),
},
ExpectedZone: types.StringValue("provider-zone-a"),
},
// Handling of empty strings
"returns the value of the zone field in provider config when zone is set to an empty string in resource config": {
ld: LocationDescription{
ResourceZone: types.StringValue(""),
ProviderZone: types.StringValue("provider-zone-a"),
},
ExpectedZone: types.StringValue("provider-zone-a"),
},
// Error states
"returns an error when a zone value can't be found": {
ld: LocationDescription{
ResourceLocation: types.StringValue("resource-location"), // unused
ResourceRegion: types.StringValue("resource-region"), // unused
},
ExpectedError: true,
},
"returns an error if zone is set as an empty string in both resource and provider configs": {
ld: LocationDescription{
ResourceZone: types.StringValue(""),
ProviderZone: types.StringValue(""),
},
ExpectedError: true,
},
"returns an error that mention non-standard schema field names when a zone value can't be found": {
ld: LocationDescription{
ZoneSchemaField: types.StringValue("foobar"),
},
ExpectedError: true,
},
}
for tn, tc := range cases {
t.Run(tn, func(t *testing.T) {
zone, err := tc.ld.GetZone()
if err != nil {
if tc.ExpectedError {
if !tc.ld.ZoneSchemaField.IsNull() {
if !strings.Contains(err.Error(), tc.ld.ZoneSchemaField.ValueString()) {
t.Fatalf("expected error to use provider schema field value %s, instead got: %s", tc.ld.ZoneSchemaField.ValueString(), err)
}
}
return
}
t.Fatalf("unexpected error using test: %s", err)
}
if err == nil && tc.ExpectedError {
t.Fatal("expected error but got none")
}
if zone != tc.ExpectedZone {
t.Fatalf("Incorrect zone: got %s, want %s", zone, tc.ExpectedZone)
}
})
}
}
func TestLocationDescription_GetRegion(t *testing.T) {
cases := map[string]struct {
ld LocationDescription
ExpectedRegion types.String
ExpectedError bool
}{
"returns the value of the region field in resource config": {
ld: LocationDescription{
// A resource would not have all 3 fields set, but if they were all present region is used first
ResourceRegion: types.StringValue("resource-region"),
ResourceLocation: types.StringValue("resource-location"),
ResourceZone: types.StringValue("resource-zone-a"),
// Provider config doesn't override resource config
ProviderRegion: types.StringValue("provider-region"),
ProviderZone: types.StringValue("provider-zone-a"),
},
ExpectedRegion: types.StringValue("resource-region"),
},
"shortens region values set as self links in the resource config": {
ld: LocationDescription{
ResourceRegion: types.StringValue("https://www.googleapis.com/compute/v1/projects/my-project/regions/us-central1"),
},
ExpectedRegion: types.StringValue("us-central1"),
},
"returns a region derived from the zone field in resource config when region is unset": {
ld: LocationDescription{
ResourceZone: types.StringValue("provider-zone-a"),
ResourceLocation: types.StringValue("resource-location"), // unused
},
ExpectedRegion: types.StringValue("provider-zone"), // is truncated
},
"shortens region values when derived from a zone self link set in the resource config": {
ld: LocationDescription{
ResourceZone: types.StringValue("https://www.googleapis.com/compute/v1/projects/my-project/zones/us-central1-a"),
},
ExpectedRegion: types.StringValue("us-central1"),
},
"shortens region values set as self links in the provider config": {
ld: LocationDescription{
ProviderRegion: types.StringValue("https://www.googleapis.com/compute/v1/projects/my-project/regions/us-central1"),
},
ExpectedRegion: types.StringValue("us-central1"),
},
"shortens region values when derived from a zone self link set in the provider config": {
ld: LocationDescription{
ProviderZone: types.StringValue("https://www.googleapis.com/compute/v1/projects/my-project/zones/us-central1-a"),
},
ExpectedRegion: types.StringValue("us-central1"),
},
"returns the value of the region field in provider config when region/zone is unset in resource config": {
ld: LocationDescription{
ProviderRegion: types.StringValue("provider-region"),
ProviderZone: types.StringValue("provider-zone-a"), // unused
},
ExpectedRegion: types.StringValue("provider-region"),
},
"returns a region derived from the zone field in provider config when region unset in both resource and provider config": {
ld: LocationDescription{
ProviderZone: types.StringValue("provider-zone-a"),
},
ExpectedRegion: types.StringValue("provider-zone"), // is truncated
},
// Handling of empty strings
"returns a region derived from the zone field in resource config when region is set as an empty string": {
ld: LocationDescription{
ResourceRegion: types.StringValue(""),
ResourceZone: types.StringValue("provider-zone-a"),
},
ExpectedRegion: types.StringValue("provider-zone"), // is truncated
},
"returns the value of the region field in provider config when region/zone set as an empty string in resource config": {
ld: LocationDescription{
ResourceRegion: types.StringValue(""),
ResourceZone: types.StringValue(""),
ProviderRegion: types.StringValue("provider-region"),
},
ExpectedRegion: types.StringValue("provider-region"),
},
// Error states
"returns an error when region/zone values can't be found (location is ignored)": {
ld: LocationDescription{
ResourceLocation: types.StringValue("resource-location"),
},
ExpectedError: true,
},
"returns an error if region and zone set as empty strings in both resource and provider configs": {
ld: LocationDescription{
ResourceRegion: types.StringValue(""),
ResourceZone: types.StringValue(""),
ProviderRegion: types.StringValue(""),
ProviderZone: types.StringValue(""),
},
ExpectedError: true,
},
"returns an error that mention non-standard schema field names when region value can't be found": {
ld: LocationDescription{
RegionSchemaField: types.StringValue("foobar"),
},
ExpectedError: true,
},
}
for tn, tc := range cases {
t.Run(tn, func(t *testing.T) {
region, err := tc.ld.GetRegion()
if err != nil {
if tc.ExpectedError {
if !tc.ld.RegionSchemaField.IsNull() {
if !strings.Contains(err.Error(), tc.ld.RegionSchemaField.ValueString()) {
t.Fatalf("expected error to use provider schema field value %s, instead got: %s", tc.ld.RegionSchemaField.ValueString(), err)
}
}
return
}
t.Fatalf("unexpected error using test: %s", err)
}
if err == nil && tc.ExpectedError {
t.Fatal("expected error but got none")
}
if region != tc.ExpectedRegion {
t.Fatalf("Incorrect region: got %s, want %s", region, tc.ExpectedRegion)
}
})
}
}
func TestLocationDescription_GetLocation(t *testing.T) {
cases := map[string]struct {
ld LocationDescription
ExpectedLocation types.String
ExpectedError bool
}{
"returns the value of the location field in resource config": {
ld: LocationDescription{
// A resource would not have all 3 fields set, but if they were all present location is used first
ResourceLocation: types.StringValue("resource-location"),
ResourceRegion: types.StringValue("resource-region"),
ResourceZone: types.StringValue("resource-zone-a"),
// Provider config doesn't override resource config
ProviderRegion: types.StringValue("provider-region"),
ProviderZone: types.StringValue("provider-zone-a"),
},
ExpectedLocation: types.StringValue("resource-location"),
},
"shortens the location value when it is set as a self link in the resource config": {
ld: LocationDescription{
ResourceLocation: types.StringValue("https://www.googleapis.com/compute/v1/projects/my-project/locations/resource-location"),
},
ExpectedLocation: types.StringValue("resource-location"),
},
"returns the region value set in the resource config when location is not in the schema": {
ld: LocationDescription{
ResourceRegion: types.StringValue("resource-region"),
ResourceZone: types.StringValue("resource-zone-a"), // unused
},
ExpectedLocation: types.StringValue("resource-region"),
},
"shortens the region value when it is set as a self link in the resource config": {
ld: LocationDescription{
ResourceRegion: types.StringValue("https://www.googleapis.com/compute/v1/projects/my-project/regions/resource-region"),
},
ExpectedLocation: types.StringValue("resource-region"),
},
"returns the zone value set in the resource config when neither location nor region in the schema": {
ld: LocationDescription{
ResourceZone: types.StringValue("resource-zone-a"),
},
ExpectedLocation: types.StringValue("resource-zone-a"),
},
"shortens zone values set as self links in the resource config": {
ld: LocationDescription{
ResourceZone: types.StringValue("https://www.googleapis.com/compute/v1/projects/my-project/zones/resource-zone-a"),
},
ExpectedLocation: types.StringValue("resource-zone-a"),
},
"returns the region value from the provider config when none of location/region/zone are set in the resource config": {
ld: LocationDescription{
ProviderRegion: types.StringValue("provider-region"), // Preferred to use region value over zone value if both are set
ProviderZone: types.StringValue("provider-zone-a"),
},
ExpectedLocation: types.StringValue("provider-region"),
},
"returns the zone value from the provider config when none of location/region/zone are set in the resource config and region is not set in the provider config": {
ld: LocationDescription{
ProviderZone: types.StringValue("provider-zone-a"),
},
ExpectedLocation: types.StringValue("provider-zone-a"),
},
"shortens the zone value when it is set as a self link in the provider config": {
ld: LocationDescription{
ProviderZone: types.StringValue("https://www.googleapis.com/compute/v1/projects/my-project/zones/provider-zone-a"),
},
ExpectedLocation: types.StringValue("provider-zone-a"),
},
// Handling of empty strings
"returns the region value set in the resource config when location is an empty string": {
ld: LocationDescription{
ResourceLocation: types.StringValue(""),
ResourceRegion: types.StringValue("resource-region"),
},
ExpectedLocation: types.StringValue("resource-region"),
},
"returns the zone value set in the resource config when both location or region are empty strings": {
ld: LocationDescription{
ResourceLocation: types.StringValue(""),
ResourceRegion: types.StringValue(""),
ResourceZone: types.StringValue("resource-zone-a"),
},
ExpectedLocation: types.StringValue("resource-zone-a"),
},
"returns the zone value from the provider config when all of location/region/zone are set as empty strings in the resource config": {
ld: LocationDescription{
ResourceLocation: types.StringValue(""),
ResourceRegion: types.StringValue(""),
ResourceZone: types.StringValue(""),
ProviderZone: types.StringValue("provider-zone-a"),
},
ExpectedLocation: types.StringValue("provider-zone-a"),
},
"returns an error when none of location/region/zone are set on the resource, and neither region or zone is set on the provider": {
ExpectedError: true,
},
"returns an error if location/region/zone are set as empty strings in both resource and provider configs": {
ld: LocationDescription{
ResourceLocation: types.StringValue(""),
ResourceRegion: types.StringValue(""),
ResourceZone: types.StringValue(""),
ProviderRegion: types.StringValue(""),
ProviderZone: types.StringValue(""),
},
ExpectedError: true,
},
"returns an error that mention non-standard schema field names when location value can't be found": {
ld: LocationDescription{
LocationSchemaField: types.StringValue("foobar"),
},
ExpectedError: true,
},
}
for tn, tc := range cases {
t.Run(tn, func(t *testing.T) {
region, err := tc.ld.GetLocation()
if err != nil {
if tc.ExpectedError {
if !tc.ld.LocationSchemaField.IsNull() {
if !strings.Contains(err.Error(), tc.ld.LocationSchemaField.ValueString()) {
t.Fatalf("expected error to use provider schema field value %s, instead got: %s", tc.ld.LocationSchemaField.ValueString(), err)
}
}
return
}
t.Fatalf("unexpected error using test: %s", err)
}
if err == nil && tc.ExpectedError {
t.Fatal("expected error but got none")
}
if region != tc.ExpectedLocation {
t.Fatalf("Incorrect location: got %s, want %s", region, tc.ExpectedLocation)
}
})
}
}