fix: some more fix tests (#72)
All checks were successful
Publish / Check GoReleaser config (push) Successful in 5s
Publish / Publish provider (push) Successful in 12m42s

## Description

<!-- **Please link some issue here describing what you are trying to achieve.**

In case there is no issue present for your PR, please consider creating one.
At least please give us some description what you are trying to achieve and why your change is needed. -->

relates to #1234

## Checklist

- [ ] Issue was linked above
- [ ] Code format was applied: `make fmt`
- [ ] Examples were added / adjusted (see `examples/` directory)
- [x] Docs are up-to-date: `make generate-docs` (will be checked by CI)
- [ ] Unit tests got implemented or updated
- [ ] Acceptance tests got implemented or updated (see e.g. [here](f5f99d1709/stackit/internal/services/dns/dns_acc_test.go))
- [x] Unit tests are passing: `make test` (will be checked by CI)
- [x] No linter issues: `make lint` (will be checked by CI)

Reviewed-on: #72
Co-authored-by: Marcel S. Henselin <marcel.henselin@stackit.cloud>
Co-committed-by: Marcel S. Henselin <marcel.henselin@stackit.cloud>
This commit is contained in:
Marcel_Henselin 2026-02-16 16:12:53 +00:00 committed by Marcel_Henselin
parent 7ee82366d7
commit f05e90c35a
Signed by: tf-provider.git.onstackit.cloud
GPG key ID: 6D7E8A1ED8955A9C
10 changed files with 137 additions and 243 deletions

View file

@ -281,24 +281,12 @@ func (r *databaseResource) Read(
return
}
// Read identity data
var identityData DatabaseResourceIdentityModel
resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...)
if resp.Diagnostics.HasError() {
return
}
ctx = core.InitProviderContext(ctx)
projectId, region, instanceId, databaseId, errExt := r.extractIdentityData(model, identityData)
if errExt != nil {
core.LogAndAddError(
ctx,
&resp.Diagnostics,
extractErrorSummary,
fmt.Sprintf(extractErrorMessage, errExt),
)
}
projectId := model.ProjectId.ValueString()
instanceId := model.InstanceId.ValueString()
region := model.Region.ValueString()
databaseId := model.DatabaseId.ValueInt64()
ctx = tflog.SetField(ctx, "project_id", projectId)
ctx = tflog.SetField(ctx, "instance_id", instanceId)

View file

@ -164,16 +164,16 @@ func TestMapFieldsCreate(t *testing.T) {
},
testRegion,
resourceModel{
Id: types.Int64Value(1),
UserId: types.Int64Value(1),
InstanceId: types.StringValue("iid"),
ProjectId: types.StringValue("pid"),
Name: types.StringNull(),
Roles: types.List(types.SetNull(types.StringType)),
Password: types.StringNull(),
Region: types.StringValue(testRegion),
Status: types.StringNull(),
ConnectionString: types.StringNull(),
Id: types.Int64Value(1),
UserId: types.Int64Value(1),
InstanceId: types.StringValue("iid"),
ProjectId: types.StringValue("pid"),
Name: types.StringNull(),
Roles: types.List(types.SetNull(types.StringType)),
Password: types.StringNull(),
Region: types.StringValue(testRegion),
Status: types.StringNull(),
//ConnectionString: types.StringNull(),
},
true,
},
@ -186,16 +186,16 @@ func TestMapFieldsCreate(t *testing.T) {
},
testRegion,
resourceModel{
Id: types.Int64Value(1),
UserId: types.Int64Value(1),
InstanceId: types.StringValue("iid"),
ProjectId: types.StringValue("pid"),
Name: types.StringValue("username"),
Roles: types.List(types.SetNull(types.StringType)),
Password: types.StringNull(),
Region: types.StringValue(testRegion),
Status: types.StringValue("status"),
ConnectionString: types.StringNull(),
Id: types.Int64Value(1),
UserId: types.Int64Value(1),
InstanceId: types.StringValue("iid"),
ProjectId: types.StringValue("pid"),
Name: types.StringValue("username"),
Roles: types.List(types.SetNull(types.StringType)),
Password: types.StringNull(),
Region: types.StringValue(testRegion),
Status: types.StringValue("status"),
//ConnectionString: types.StringNull(),
},
true,
},
@ -208,16 +208,16 @@ func TestMapFieldsCreate(t *testing.T) {
},
testRegion,
resourceModel{
Id: types.Int64Value(1),
UserId: types.Int64Value(1),
InstanceId: types.StringValue("iid"),
ProjectId: types.StringValue("pid"),
Name: types.StringNull(),
Roles: types.List(types.SetNull(types.StringType)),
Password: types.StringNull(),
Region: types.StringValue(testRegion),
Status: types.StringNull(),
ConnectionString: types.StringNull(),
Id: types.Int64Value(1),
UserId: types.Int64Value(1),
InstanceId: types.StringValue("iid"),
ProjectId: types.StringValue("pid"),
Name: types.StringNull(),
Roles: types.List(types.SetNull(types.StringType)),
Password: types.StringNull(),
Region: types.StringValue(testRegion),
Status: types.StringNull(),
//ConnectionString: types.StringNull(),
},
true,
},
@ -285,15 +285,15 @@ func TestMapFields(t *testing.T) {
},
testRegion,
resourceModel{
Id: types.Int64Value(1),
UserId: types.Int64Value(int64(1)),
InstanceId: types.StringValue("iid"),
ProjectId: types.StringValue("pid"),
Name: types.StringNull(),
Roles: types.List(types.SetNull(types.StringType)),
Region: types.StringValue(testRegion),
Status: types.StringNull(),
ConnectionString: types.StringNull(),
Id: types.Int64Value(1),
UserId: types.Int64Value(int64(1)),
InstanceId: types.StringValue("iid"),
ProjectId: types.StringValue("pid"),
Name: types.StringNull(),
Roles: types.List(types.SetNull(types.StringType)),
Region: types.StringValue(testRegion),
Status: types.StringNull(),
//ConnectionString: types.StringNull(),
},
true,
},
@ -324,9 +324,9 @@ func TestMapFields(t *testing.T) {
},
),
),
Region: types.StringValue(testRegion),
Status: types.StringNull(),
ConnectionString: types.StringNull(),
Region: types.StringValue(testRegion),
Status: types.StringNull(),
//ConnectionString: types.StringNull(),
},
true,
},
@ -338,15 +338,15 @@ func TestMapFields(t *testing.T) {
},
testRegion,
resourceModel{
Id: types.Int64Value(1),
UserId: types.Int64Value(1),
InstanceId: types.StringValue("iid"),
ProjectId: types.StringValue("pid"),
Name: types.StringNull(),
Roles: types.List(types.SetNull(types.StringType)),
Region: types.StringValue(testRegion),
Status: types.StringNull(),
ConnectionString: types.StringNull(),
Id: types.Int64Value(1),
UserId: types.Int64Value(1),
InstanceId: types.StringValue("iid"),
ProjectId: types.StringValue("pid"),
Name: types.StringNull(),
Roles: types.List(types.SetNull(types.StringType)),
Region: types.StringValue(testRegion),
Status: types.StringNull(),
//ConnectionString: types.StringNull(),
},
true,
},

View file

@ -186,25 +186,25 @@ func (r *databaseResource) Create(ctx context.Context, req resource.CreateReques
payLoad.Name = data.Name.ValueStringPointer()
payLoad.Owner = data.Owner.ValueStringPointer()
_, err := wait.WaitForUserWaitHandler(
ctx,
r.client,
projectId,
instanceId,
region,
data.Owner.ValueString(),
).
SetSleepBeforeWait(10 * time.Second).
WaitWithContext(ctx)
if err != nil {
core.LogAndAddError(
ctx,
&resp.Diagnostics,
createErr,
fmt.Sprintf("Calling API: %v", err),
)
return
}
//_, err := wait.WaitForUserWaitHandler(
// ctx,
// r.client,
// projectId,
// instanceId,
// region,
// data.Owner.ValueString(),
//).
// SetSleepBeforeWait(10 * time.Second).
// WaitWithContext(ctx)
//if err != nil {
// core.LogAndAddError(
// ctx,
// &resp.Diagnostics,
// createErr,
// fmt.Sprintf("Calling API: %v", err),
// )
// return
//}
createResp, err := r.client.CreateDatabaseRequest(ctx, projectId, region, instanceId).
CreateDatabaseRequestPayload(payLoad).
@ -361,15 +361,10 @@ func (r *databaseResource) Read(ctx context.Context, req resource.ReadRequest, r
ctx = core.InitProviderContext(ctx)
projectId, region, instanceId, databaseName, errExt := r.extractIdentityData(model, identityData)
if errExt != nil {
core.LogAndAddError(
ctx,
&resp.Diagnostics,
extractErrorSummary,
fmt.Sprintf(extractErrorMessage, errExt),
)
}
projectId := model.ProjectId.ValueString()
region := model.Region.ValueString()
instanceId := model.InstanceId.ValueString()
databaseName := model.DatabaseName.ValueString()
ctx = tflog.SetField(ctx, "project_id", projectId)
ctx = tflog.SetField(ctx, "instance_id", instanceId)
@ -445,15 +440,10 @@ func (r *databaseResource) Delete(ctx context.Context, req resource.DeleteReques
ctx = core.InitProviderContext(ctx)
projectId, region, instanceId, databaseName, errExt := r.extractIdentityData(model, identityData)
if errExt != nil {
core.LogAndAddError(
ctx,
&resp.Diagnostics,
extractErrorSummary,
fmt.Sprintf(extractErrorMessage, errExt),
)
}
projectId := model.ProjectId.ValueString()
region := model.Region.ValueString()
instanceId := model.InstanceId.ValueString()
databaseName := model.DatabaseName.ValueString()
ctx = tflog.SetField(ctx, "project_id", projectId)
ctx = tflog.SetField(ctx, "instance_id", instanceId)
@ -508,23 +498,6 @@ func (r *databaseResource) ModifyPlan(
return
}
var identityModel DatabaseResourceIdentityModel
identityModel.ProjectID = planModel.ProjectId
identityModel.Region = planModel.Region
if !planModel.InstanceId.IsNull() && !planModel.InstanceId.IsUnknown() {
identityModel.InstanceID = planModel.InstanceId
}
if !planModel.Name.IsNull() && !planModel.Name.IsUnknown() {
identityModel.DatabaseName = planModel.Name
}
resp.Diagnostics.Append(resp.Identity.Set(ctx, identityModel)...)
if resp.Diagnostics.HasError() {
return
}
resp.Diagnostics.Append(resp.Plan.Set(ctx, planModel)...)
if resp.Diagnostics.HasError() {
return
@ -594,46 +567,3 @@ func (r *databaseResource) ImportState(
tflog.Info(ctx, "sqlserverflexalpha database state imported")
}
// extractIdentityData extracts essential identifiers from the resource model, falling back to the identity model.
func (r *databaseResource) extractIdentityData(
model resourceModel,
identity DatabaseResourceIdentityModel,
) (projectId, region, instanceId, databaseName string, err error) {
if !model.Name.IsNull() && !model.Name.IsUnknown() {
databaseName = model.Name.ValueString()
} else {
if identity.DatabaseName.IsNull() || identity.DatabaseName.IsUnknown() {
return "", "", "", "", fmt.Errorf("database_name not found in config")
}
databaseName = identity.DatabaseName.ValueString()
}
if !model.ProjectId.IsNull() && !model.ProjectId.IsUnknown() {
projectId = model.ProjectId.ValueString()
} else {
if identity.ProjectID.IsNull() || identity.ProjectID.IsUnknown() {
return "", "", "", "", fmt.Errorf("project_id not found in config")
}
projectId = identity.ProjectID.ValueString()
}
if !model.Region.IsNull() && !model.Region.IsUnknown() {
region = r.providerData.GetRegionWithOverride(model.Region)
} else {
if identity.Region.IsNull() || identity.Region.IsUnknown() {
return "", "", "", "", fmt.Errorf("region not found in config")
}
region = r.providerData.GetRegionWithOverride(identity.Region)
}
if !model.InstanceId.IsNull() && !model.InstanceId.IsUnknown() {
instanceId = model.InstanceId.ValueString()
} else {
if identity.InstanceID.IsNull() || identity.InstanceID.IsUnknown() {
return "", "", "", "", fmt.Errorf("instance_id not found in config")
}
instanceId = identity.InstanceID.ValueString()
}
return projectId, region, instanceId, databaseName, nil
}

View file

@ -43,9 +43,12 @@ func TestMapDataSourceFields(t *testing.T) {
"simple_values",
&sqlserverflexalpha.GetUserResponse{
Roles: &[]string{
"role_1",
"role_2",
"",
"##STACKIT_SQLAgentUser##",
"##STACKIT_DatabaseManager##",
"##STACKIT_LoginManager##",
"##STACKIT_SQLAgentManager##",
"##STACKIT_ProcessManager##",
"##STACKIT_ServerManager##",
},
Username: utils.Ptr("username"),
Host: utils.Ptr("host"),
@ -63,9 +66,12 @@ func TestMapDataSourceFields(t *testing.T) {
Roles: types.List(
types.SetValueMust(
types.StringType, []attr.Value{
types.StringValue(""),
types.StringValue("role_1"),
types.StringValue("role_2"),
types.StringValue("##STACKIT_DatabaseManager##"),
types.StringValue("##STACKIT_LoginManager##"),
types.StringValue("##STACKIT_ProcessManager##"),
types.StringValue("##STACKIT_SQLAgentManager##"),
types.StringValue("##STACKIT_SQLAgentUser##"),
types.StringValue("##STACKIT_ServerManager##"),
},
),
),

View file

@ -2,7 +2,6 @@ package sqlserverflexbeta
import (
"fmt"
"strings"
"github.com/hashicorp/terraform-plugin-framework/types"
@ -34,7 +33,7 @@ func mapFields(source *sqlserverflexbeta.GetDatabaseResponse, model *dataSourceM
model.Id = types.Int64Value(databaseId)
model.DatabaseName = types.StringValue(source.GetName())
model.Name = types.StringValue(source.GetName())
model.Owner = types.StringValue(strings.Trim(source.GetOwner(), "\""))
model.Owner = types.StringValue(source.GetOwner())
model.Region = types.StringValue(region)
model.ProjectId = types.StringValue(model.ProjectId.ValueString())
model.InstanceId = types.StringValue(model.InstanceId.ValueString())
@ -75,7 +74,7 @@ func mapResourceFields(source *sqlserverflexbeta.GetDatabaseResponse, model *res
model.Id = types.Int64Value(databaseId)
model.DatabaseName = types.StringValue(source.GetName())
model.Name = types.StringValue(source.GetName())
model.Owner = types.StringValue(strings.Trim(source.GetOwner(), "\""))
model.Owner = types.StringValue(source.GetOwner())
model.Region = types.StringValue(region)
model.ProjectId = types.StringValue(model.ProjectId.ValueString())
model.InstanceId = types.StringValue(model.InstanceId.ValueString())

View file

@ -247,7 +247,6 @@ func (r *databaseResource) Create(ctx context.Context, req resource.CreateReques
return
}
// TODO: is this necessary to wait for the database-> API say 200 ?
waitResp, err := wait.CreateDatabaseWaitHandler(
ctx,
r.client,
@ -310,19 +309,8 @@ func (r *databaseResource) Create(ctx context.Context, req resource.CreateReques
return
}
database, err := r.client.GetDatabaseRequest(ctx, projectId, region, instanceId, databaseName).Execute()
if err != nil {
core.LogAndAddError(
ctx,
&resp.Diagnostics,
"Error creating database",
fmt.Sprintf("Getting database details after creation: %v", err),
)
return
}
// Map response body to schema
err = mapResourceFields(database, &data, region)
err = mapResourceFields(waitResp, &data, region)
if err != nil {
core.LogAndAddError(
ctx,
@ -361,15 +349,10 @@ func (r *databaseResource) Read(ctx context.Context, req resource.ReadRequest, r
ctx = core.InitProviderContext(ctx)
projectId, region, instanceId, databaseName, errExt := r.extractIdentityData(model, identityData)
if errExt != nil {
core.LogAndAddError(
ctx,
&resp.Diagnostics,
extractErrorSummary,
fmt.Sprintf(extractErrorMessage, errExt),
)
}
projectId := model.ProjectId.ValueString()
region := model.Region.ValueString()
instanceId := model.InstanceId.ValueString()
databaseName := model.DatabaseName.ValueString()
ctx = tflog.SetField(ctx, "project_id", projectId)
ctx = tflog.SetField(ctx, "instance_id", instanceId)

View file

@ -302,9 +302,9 @@ func TestAccInstanceNoEncryption(t *testing.T) {
"##STACKIT_DatabaseManager##",
"##STACKIT_LoginManager##",
"##STACKIT_ProcessManager##",
"##STACKIT_ServerManager##",
"##STACKIT_SQLAgentManager##",
"##STACKIT_SQLAgentUser##",
"##STACKIT_ServerManager##",
},
},
}
@ -402,7 +402,7 @@ func TestAccInstanceEncryption(t *testing.T) {
{
Name: userName,
ProjectId: os.Getenv("TF_ACC_PROJECT_ID"),
Roles: []string{"##STACKIT_LoginManager##", "##STACKIT_DatabaseManager##"},
Roles: []string{"##STACKIT_DatabaseManager##", "##STACKIT_LoginManager##"},
},
}
data.Databases = []Database{

View file

@ -94,8 +94,8 @@ func mapFields(userResp *sqlserverflexbeta.GetUserResponse, model *resourceModel
model.Username = types.StringPointerValue(user.Username)
// Map roles
if user.Roles != nil {
resRoles := *user.Roles
if userResp.Roles != nil {
resRoles := *userResp.Roles
slices.Sort(resRoles)
var roles []attr.Value
@ -103,11 +103,11 @@ func mapFields(userResp *sqlserverflexbeta.GetUserResponse, model *resourceModel
roles = append(roles, types.StringValue(string(role)))
}
rolesSet, diags := types.SetValue(types.StringType, roles)
rolesSet, diags := types.ListValue(types.StringType, roles)
if diags.HasError() {
return fmt.Errorf("failed to map roles: %w", core.DiagsToError(diags))
}
model.Roles = types.List(rolesSet)
model.Roles = rolesSet
}
// Ensure roles is not null
@ -153,11 +153,11 @@ func mapFieldsCreate(userResp *sqlserverflexbeta.CreateUserResponse, model *reso
for _, role := range resRoles {
roles = append(roles, types.StringValue(string(role)))
}
rolesSet, diags := types.SetValue(types.StringType, roles)
rolesList, diags := types.ListValue(types.StringType, roles)
if diags.HasError() {
return fmt.Errorf("failed to map roles: %w", core.DiagsToError(diags))
}
model.Roles = types.List(rolesSet)
model.Roles = rolesList
}
if model.Roles.IsNull() || model.Roles.IsUnknown() {

View file

@ -11,7 +11,6 @@ import (
"strings"
"time"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/identityschema"
@ -108,37 +107,25 @@ func (r *userResource) ModifyPlan(
return
}
// TODO: verify if this is needed - START
var configRoles []string
diags := configModel.Roles.ElementsAs(ctx, &configRoles, false)
resp.Diagnostics.Append(diags...)
if diags.HasError() {
return
}
var planRoles []string
diags = planModel.Roles.ElementsAs(ctx, &planRoles, false)
resp.Diagnostics.Append(diags...)
if diags.HasError() {
return
}
slices.Sort(configRoles)
slices.Sort(planRoles)
if !slices.Equal(configRoles, planRoles) {
var roles []attr.Value
for _, role := range configRoles {
roles = append(roles, types.StringValue(string(role)))
}
rolesSet, diags := types.SetValue(types.StringType, roles)
resp.Diagnostics.Append(diags...)
if diags.HasError() {
return
}
planModel.Roles = types.List(rolesSet)
}
// TODO: verify if this is needed - END
//// TODO: verify if this is needed - START
//var planRoles []string
//diags := planModel.Roles.ElementsAs(ctx, &planRoles, false)
//resp.Diagnostics.Append(diags...)
//if diags.HasError() {
// return
//}
//slices.Sort(planRoles)
//var roles []attr.Value
//for _, role := range planRoles {
// roles = append(roles, types.StringValue(string(role)))
//}
//rolesSet, diags := types.ListValue(types.StringType, roles)
//resp.Diagnostics.Append(diags...)
//if diags.HasError() {
// return
//}
//planModel.Roles = rolesSet
//// TODO: verify if this is needed - END
resp.Diagnostics.Append(resp.Plan.Set(ctx, planModel)...)
if resp.Diagnostics.HasError() {

View file

@ -489,17 +489,18 @@ func (p *Provider) Configure(ctx context.Context, req provider.ConfigureRequest,
return
}
roundTripper := core.NewRetryRoundTripper(
baseRoundTripper,
maxRetries,
initialDelay,
maxDelay,
perTryTimeout,
)
//roundTripper := core.NewRetryRoundTripper(
// baseRoundTripper,
// maxRetries,
// initialDelay,
// maxDelay,
// perTryTimeout,
//)
// Make round tripper and custom endpoints available during DataSource and Resource
// type Configure methods.
providerData.RoundTripper = roundTripper
// providerData.RoundTripper = roundTripper
providerData.RoundTripper = baseRoundTripper
resp.DataSourceData = providerData
resp.ResourceData = providerData