Improve local dev override docs and add read-only example

This commit is contained in:
beatz174-bit committed 2026-04-21 17:11:15 +10:00
1 parent da55eb3c9f
commit d2ad986558
13 files changed
+388 -186

No files matched your search

+2 -2
View File
@@ -115,13 +115,13 @@ func (d *dnsRecordsDataSource) Read(ctx context.Context, req datasource.ReadRequ
domainID, domainName, err := d.clientProvider.client.GetRootDomain(ctx, config.Hostname.ValueString())
if err != nil {
resp.Diagnostics.AddError("Unable to resolve Dynu domain from hostname", err.Error())
resp.Diagnostics.AddError(diagnosticSummary("Unable to resolve Dynu domain from hostname", err), err.Error())
return
}
records, err := d.clientProvider.client.ListDNSRecords(ctx, domainID)
if err != nil {
resp.Diagnostics.AddError("Unable to list Dynu DNS records", err.Error())
resp.Diagnostics.AddError(diagnosticSummary("Unable to list Dynu DNS records", err), err.Error())
return
}
+2 -2
View File
@@ -88,13 +88,13 @@ func (d *domainDataSource) Read(ctx context.Context, req datasource.ReadRequest,
domainID, _, err := d.clientProvider.client.GetRootDomain(ctx, config.Hostname.ValueString())
if err != nil {
resp.Diagnostics.AddError("Unable to resolve Dynu domain from hostname", err.Error())
resp.Diagnostics.AddError(diagnosticSummary("Unable to resolve Dynu domain from hostname", err), err.Error())
return
}
domain, err := d.clientProvider.client.GetDomainByID(ctx, domainID)
if err != nil {
resp.Diagnostics.AddError("Unable to get Dynu domain", err.Error())
resp.Diagnostics.AddError(diagnosticSummary("Unable to get Dynu domain", err), err.Error())
return
}
+1 -1
View File
@@ -80,7 +80,7 @@ func (d *domainsDataSource) Configure(_ context.Context, req datasource.Configur
func (d *domainsDataSource) Read(ctx context.Context, _ datasource.ReadRequest, resp *datasource.ReadResponse) {
domains, err := d.clientProvider.client.ListDomains(ctx)
if err != nil {
resp.Diagnostics.AddError("Unable to list Dynu domains", err.Error())
resp.Diagnostics.AddError(diagnosticSummary("Unable to list Dynu domains", err), err.Error())
return
}
+23
View File
@@ -0,0 +1,23 @@
package provider
import (
"errors"
"github.com/dynu/terraform-provider-dynu/internal/dynuclient"
)
func diagnosticSummary(defaultSummary string, err error) string {
var apiErr *dynuclient.APIError
if !errors.As(err, &apiErr) {
return defaultSummary
}
switch apiErr.StatusCode {
case 401, 403:
return defaultSummary + " (authentication failed)"
case 404:
return defaultSummary + " (not found)"
default:
return defaultSummary
}
}
@@ -157,6 +157,59 @@ func TestIntegrationDataSourceDiagnosticsFromAPIError(t *testing.T) {
}
}
func TestIntegrationDataSourceDiagnosticsFromAuthError(t *testing.T) {
fake := fakedynu.NewServer()
defer fake.Close()
fake.SetAPIError("/dns/getroot/www.a.example.com", fakedynu.APIError{HTTPStatus: 401, StatusCode: 401, Type: "Unauthorized", Message: "invalid api key"})
ds := NewDomainDataSource().(*domainDataSource)
configureDataSource(t, ds, fake.BaseURL())
var schemaResp datasource.SchemaResponse
ds.Schema(context.Background(), datasource.SchemaRequest{}, &schemaResp)
req := datasource.ReadRequest{Config: tfsdk.Config{
Schema: schemaResp.Schema,
Raw: tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"hostname": tftypes.String}}, map[string]tftypes.Value{
"hostname": tftypes.NewValue(tftypes.String, "www.a.example.com"),
}),
}}
resp := datasource.ReadResponse{State: tfsdk.State{Schema: schemaResp.Schema}}
ds.Read(context.Background(), req, &resp)
if !resp.Diagnostics.HasError() {
t.Fatal("expected diagnostics error")
}
if !strings.Contains(resp.Diagnostics[0].Summary(), "authentication failed") {
t.Fatalf("unexpected diagnostics summary: %s", resp.Diagnostics[0].Summary())
}
}
func TestIntegrationDataSourceDiagnosticsFromNotFoundError(t *testing.T) {
fake := fakedynu.NewServer()
defer fake.Close()
ds := NewDomainDataSource().(*domainDataSource)
configureDataSource(t, ds, fake.BaseURL())
var schemaResp datasource.SchemaResponse
ds.Schema(context.Background(), datasource.SchemaRequest{}, &schemaResp)
req := datasource.ReadRequest{Config: tfsdk.Config{
Schema: schemaResp.Schema,
Raw: tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"hostname": tftypes.String}}, map[string]tftypes.Value{
"hostname": tftypes.NewValue(tftypes.String, "missing.a.example.com"),
}),
}}
resp := datasource.ReadResponse{State: tfsdk.State{Schema: schemaResp.Schema}}
ds.Read(context.Background(), req, &resp)
if !resp.Diagnostics.HasError() {
t.Fatal("expected diagnostics error")
}
if !strings.Contains(resp.Diagnostics[0].Summary(), "not found") {
t.Fatalf("unexpected diagnostics summary: %s", resp.Diagnostics[0].Summary())
}
}
func configureDataSource(t *testing.T, ds datasource.DataSourceWithConfigure, baseURL string) {
t.Helper()
resp := datasource.ConfigureResponse{}
+64
View File
@@ -1,8 +1,14 @@
package provider
import (
"context"
"os"
"path/filepath"
"strings"
"testing"
"github.com/dynu/terraform-provider-dynu/internal/dynuclient"
"github.com/hashicorp/terraform-plugin-framework/provider"
"github.com/hashicorp/terraform-plugin-framework/types"
)
@@ -28,3 +34,61 @@ func TestResolveAPIKey(t *testing.T) {
})
}
}
func TestProviderSchema(t *testing.T) {
p := New("test")()
var resp provider.SchemaResponse
p.Schema(context.Background(), provider.SchemaRequest{}, &resp)
apiKeyAttr, ok := resp.Schema.Attributes["api_key"]
if !ok {
t.Fatal("expected api_key in provider schema")
}
if !apiKeyAttr.IsOptional() {
t.Fatal("expected api_key to be optional")
}
baseURLAttr, ok := resp.Schema.Attributes["base_url"]
if !ok {
t.Fatal("expected base_url in provider schema")
}
if !baseURLAttr.IsOptional() {
t.Fatal("expected base_url to be optional")
}
}
func TestDiagnosticSummary(t *testing.T) {
tests := []struct {
name string
err error
summary string
want string
}{
{name: "non api error", err: os.ErrNotExist, summary: "Unable to list Dynu domains", want: "Unable to list Dynu domains"},
{name: "auth error", err: &dynuclient.APIError{StatusCode: 401, Type: "Unauthorized", Message: "invalid"}, summary: "Unable to list Dynu domains", want: "Unable to list Dynu domains (authentication failed)"},
{name: "not found", err: &dynuclient.APIError{StatusCode: 404, Type: "Not Found", Message: "missing"}, summary: "Unable to resolve Dynu domain from hostname", want: "Unable to resolve Dynu domain from hostname (not found)"},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
if got := diagnosticSummary(tc.summary, tc.err); got != tc.want {
t.Fatalf("diagnosticSummary() = %q, want %q", got, tc.want)
}
})
}
}
func TestReadOnlyExampleUsesValidProviderArguments(t *testing.T) {
contents, err := os.ReadFile(filepath.Join("..", "..", "examples", "read_only", "providers.tf"))
if err != nil {
t.Fatalf("read example providers.tf: %v", err)
}
config := string(contents)
if strings.Contains(config, "username") {
t.Fatal("example providers.tf must not use unsupported provider argument 'username'")
}
if !strings.Contains(config, "api_key") {
t.Fatal("example providers.tf must include api_key argument")
}
}