From bb98dde7d1f896411ad346490d7519f2e251e163 Mon Sep 17 00:00:00 2001 From: Morgan Adamiec Date: Tue, 16 Aug 2022 15:28:01 +0100 Subject: [PATCH 1/7] Add generated file to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d90cc4b..af02858 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ .terraform *.tfstate *.tfstate* +.terraform.lock.hcl From b64a07a4bf8e00268219576fb6ade2033110f72d Mon Sep 17 00:00:00 2001 From: Morgan Adamiec Date: Tue, 16 Aug 2022 15:31:00 +0100 Subject: [PATCH 2/7] Check error when reading apps --- internal/provider/resource_ably_app.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/internal/provider/resource_ably_app.go b/internal/provider/resource_ably_app.go index 10b9185..a340ece 100644 --- a/internal/provider/resource_ably_app.go +++ b/internal/provider/resource_ably_app.go @@ -128,7 +128,14 @@ func (r resourceApp) Read(ctx context.Context, req tfsdk.ReadResourceRequest, re // Fetches all Ably Apps in the account. The function invokes the Client Library Apps() method. // NOTE: Control API & Client Lib do not currently support fetching single app given app id - apps, _ := r.p.client.Apps() + apps, err := r.p.client.Apps() + if err != nil { + resp.Diagnostics.AddError( + "Error reading Resource", + "Could not create resource, unexpected error: "+err.Error(), + ) + return + } // Loops through apps and if account id matches, sets state. for _, v := range apps { From f3138aa76822f301bfd4bcc19791a8ee6410e5d3 Mon Sep 17 00:00:00 2001 From: Morgan Adamiec Date: Tue, 16 Aug 2022 16:01:24 +0100 Subject: [PATCH 3/7] Add namespace provider --- examples/playground/namespace.tf | 10 + internal/provider/models.go | 12 + internal/provider/provider.go | 3 +- internal/provider/resource_ably_namespace.go | 278 ++++++++++++++++++ .../provider/resource_ably_namespace_test.go | 83 ++++++ 5 files changed, 385 insertions(+), 1 deletion(-) create mode 100644 examples/playground/namespace.tf create mode 100644 internal/provider/resource_ably_namespace.go create mode 100644 internal/provider/resource_ably_namespace_test.go diff --git a/examples/playground/namespace.tf b/examples/playground/namespace.tf new file mode 100644 index 0000000..9fb571a --- /dev/null +++ b/examples/playground/namespace.tf @@ -0,0 +1,10 @@ +resource "ably_namespace" "namespace0" { + app_id = ably_app.app0.id + id = "namespace" + authenticated = false + persisted = false + persist_last = false + push_enabled = false + tls_only = false + expose_timeserial = false +} diff --git a/internal/provider/models.go b/internal/provider/models.go index e2bba57..522599d 100644 --- a/internal/provider/models.go +++ b/internal/provider/models.go @@ -12,3 +12,15 @@ type AblyApp struct { Status types.String `tfsdk:"status"` TLSOnly types.Bool `tfsdk:"tls_only"` } + +// Ably Namespace +type AblyNamespace struct { + AppID types.String `tfsdk:"app_id"` + ID types.String `tfsdk:"id"` + Authenticated types.Bool `tfsdk:"authenticated"` + Persisted types.Bool `tfsdk:"persisted"` + PersistLast types.Bool `tfsdk:"persist_last"` + PushEnabled types.Bool `tfsdk:"push_enabled"` + TlsOnly types.Bool `tfsdk:"tls_only"` + ExposeTimeserial types.Bool `tfsdk:"expose_timeserial"` +} diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 2eede37..e83b9dc 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -118,7 +118,8 @@ func (p *provider) Configure(ctx context.Context, req tfsdk.ConfigureProviderReq // GetResources - Defines provider resources func (p *provider) GetResources(_ context.Context) (map[string]tfsdk.ResourceType, diag.Diagnostics) { return map[string]tfsdk.ResourceType{ - "ably_app": resourceAppType{}, + "ably_app": resourceAppType{}, + "ably_namespace": resourceNamespaceType{}, }, nil } diff --git a/internal/provider/resource_ably_namespace.go b/internal/provider/resource_ably_namespace.go new file mode 100644 index 0000000..17d8873 --- /dev/null +++ b/internal/provider/resource_ably_namespace.go @@ -0,0 +1,278 @@ +package ably_control + +import ( + "context" + + ably_control_go "github.com/ably/ably-control-go" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type resourceNamespaceType struct{} + +// Get Namespace Resource schema +func (r resourceNamespaceType) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "app_id": { + Type: types.StringType, + Required: true, + Description: "The application ID.", + }, + "id": { + Type: types.StringType, + Required: true, + Description: "The namespace ID.", + }, + "authenticated": { + Type: types.BoolType, + Optional: true, + Description: "Require clients to be authenticated to use channels in this namespace.", + }, + "persisted": { + Type: types.BoolType, + Optional: true, + Description: "If true, messages will be stored for 24 hours.", + }, + "persist_last": { + Type: types.BoolType, + Optional: true, + Description: "If true, the last message on each channel will persist for 365 days.", + }, + "push_enabled": { + Type: types.BoolType, + Optional: true, + Description: "If true, publishing messages with a push payload in the extras field is permitted.", + }, + "tls_only": { + Type: types.BoolType, + Optional: true, + Description: "If true, only clients that are connected using TLS will be permitted to subscribe.", + }, + "expose_timeserial": { + Type: types.BoolType, + Optional: true, + Description: "If true, messages received on a channel will contain a unique timeserial that can be referenced by later messages for use with message interactions.", + }, + }, + }, nil +} + +// New resource instance +func (r resourceNamespaceType) NewResource(_ context.Context, p tfsdk.Provider) (tfsdk.Resource, diag.Diagnostics) { + return resourceNamespace{ + p: *(p.(*provider)), + }, nil +} + +type resourceNamespace struct { + p provider +} + +// Create a new resource +func (r resourceNamespace) Create(ctx context.Context, req tfsdk.CreateResourceRequest, resp *tfsdk.CreateResourceResponse) { + // Checks whether the provider and API Client are configured. If they are not, the provider responds with an error. + if !r.p.configured { + resp.Diagnostics.AddError( + "Provider not configured", + "The provider hasn't been configured before apply", + ) + return + } + + // Gets plan values + var plan AblyNamespace + diags := req.Plan.Get(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + // Generates an API request body from the plan values + namespace_values := ably_control_go.Namespace{ + ID: plan.ID.Value, + Authenticated: plan.Authenticated.Value, + Persisted: plan.Persisted.Value, + PersistLast: plan.PersistLast.Value, + PushEnabled: plan.PushEnabled.Value, + TlsOnly: plan.TlsOnly.Value, + ExposeTimeserial: plan.ExposeTimeserial.Value, + } + + // Creates a new Ably namespace by invoking the CreateNamespace function from the Client Library + ably_namespace, err := r.p.client.CreateNamespace(plan.AppID.Value, &namespace_values) + if err != nil { + resp.Diagnostics.AddError( + "Error creating Resource", + "Could not create resource, unexpected error: "+err.Error(), + ) + return + } + + // Maps response body to resource schema attributes. + resp_apps := AblyNamespace{ + AppID: types.String{Value: plan.AppID.Value}, + ID: types.String{Value: ably_namespace.ID}, + Authenticated: types.Bool{Value: ably_namespace.Authenticated}, + Persisted: types.Bool{Value: ably_namespace.Persisted}, + PersistLast: types.Bool{Value: ably_namespace.PersistLast}, + PushEnabled: types.Bool{Value: ably_namespace.PushEnabled}, + TlsOnly: types.Bool{Value: ably_namespace.TlsOnly}, + ExposeTimeserial: types.Bool{Value: namespace_values.ExposeTimeserial}, + } + + // Sets state for the new Ably App. + diags = resp.State.Set(ctx, resp_apps) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} + +// Read resource +func (r resourceNamespace) Read(ctx context.Context, req tfsdk.ReadResourceRequest, resp *tfsdk.ReadResourceResponse) { + // Gets the current state. If it is unable to, the provider responds with an error. + var state AblyNamespace + diags := req.State.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + + if resp.Diagnostics.HasError() { + return + } + + // Gets the Ably App ID and namespace ID value for the resource + app_id := state.AppID.Value + namespace_id := state.ID.Value + + // Fetches all Ably Namespaces in the app. The function invokes the Client Library Namespaces() method. + // NOTE: Control API & Client Lib do not currently support fetching single namespace given namespace id + namespaces, err := r.p.client.Namespaces(app_id) + if err != nil { + resp.Diagnostics.AddError( + "Error updating Resource", + "Could not update resource, unexpected error: "+err.Error(), + ) + return + } + + // Loops through namespaces and if id matches, sets state. + for _, v := range namespaces { + if v.ID == namespace_id { + resp_namespaces := AblyNamespace{ + AppID: types.String{Value: app_id}, + ID: types.String{Value: namespace_id}, + Authenticated: types.Bool{Value: v.Authenticated}, + Persisted: types.Bool{Value: v.Persisted}, + PersistLast: types.Bool{Value: v.PersistLast}, + PushEnabled: types.Bool{Value: v.PushEnabled}, + TlsOnly: types.Bool{Value: v.TlsOnly}, + ExposeTimeserial: types.Bool{Value: v.ExposeTimeserial}, + } + // Sets state to namespace values. + diags = resp.State.Set(ctx, &resp_namespaces) + + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + } + } +} + +// Update resource +func (r resourceNamespace) Update(ctx context.Context, req tfsdk.UpdateResourceRequest, resp *tfsdk.UpdateResourceResponse) { + // Get plan values + var plan AblyNamespace + diags := req.Plan.Get(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + // Get current state + var state AblyNamespace + diags = req.State.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + // Gets the app ID and ID + app_id := state.AppID.Value + namespace_id := state.ID.Value + + // Instantiates struct of type ably_control_go.Namespace and sets values to output of plan + namespace_values := ably_control_go.Namespace{ + ID: namespace_id, + Authenticated: plan.Authenticated.Value, + Persisted: plan.Persisted.Value, + PersistLast: plan.PersistLast.Value, + PushEnabled: plan.PushEnabled.Value, + TlsOnly: plan.TlsOnly.Value, + ExposeTimeserial: plan.ExposeTimeserial.Value, + } + + // Updates an Ably Namespace. The function invokes the Client Library UpdateNamespace method. + ably_namespace, err := r.p.client.UpdateNamespace(app_id, &namespace_values) + if err != nil { + resp.Diagnostics.AddError( + "Error updating Resource", + "Could not update resource, unexpected error: "+err.Error(), + ) + return + } + + resp_namespaces := AblyNamespace{ + AppID: types.String{Value: app_id}, + ID: types.String{Value: ably_namespace.ID}, + Authenticated: types.Bool{Value: ably_namespace.Authenticated}, + Persisted: types.Bool{Value: ably_namespace.Persisted}, + PersistLast: types.Bool{Value: ably_namespace.PersistLast}, + PushEnabled: types.Bool{Value: ably_namespace.PushEnabled}, + TlsOnly: types.Bool{Value: ably_namespace.TlsOnly}, + ExposeTimeserial: types.Bool{Value: ably_namespace.ExposeTimeserial}, + } + + // Sets state to new namespace. + diags = resp.State.Set(ctx, resp_namespaces) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} + +// Delete resource +func (r resourceNamespace) Delete(ctx context.Context, req tfsdk.DeleteResourceRequest, resp *tfsdk.DeleteResourceResponse) { + // Get current state + var state AblyNamespace + diags := req.State.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + // Gets the current state. If it is unable to, the provider responds with an error. + app_id := state.AppID.Value + namespace_id := state.ID.Value + + err := r.p.client.DeleteNamespace(app_id, namespace_id) + if err != nil { + resp.Diagnostics.AddError( + "Error deleting Resource", + "Could not delete resource, unexpected error: "+err.Error(), + ) + return + } + + // Remove resource from state + resp.State.RemoveResource(ctx) +} + +// Import resource +func (r resourceNamespace) ImportState(ctx context.Context, req tfsdk.ImportResourceStateRequest, resp *tfsdk.ImportResourceStateResponse) { + // Save the import identifier in the id attribute + // Recent PR in TF Plugin Framework for paths but Hashicorp examples not updated - https://github.com/hashicorp/terraform-plugin-framework/pull/390 + tfsdk.ResourceImportStatePassthroughID(ctx, path.Root("id"), req, resp) +} diff --git a/internal/provider/resource_ably_namespace_test.go b/internal/provider/resource_ably_namespace_test.go new file mode 100644 index 0000000..6682b40 --- /dev/null +++ b/internal/provider/resource_ably_namespace_test.go @@ -0,0 +1,83 @@ +package ably_control + +import ( + "fmt" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "testing" +) + +func TestAccAblyNamespace(t *testing.T) { + app_name := acctest.RandStringFromCharSet(15, acctest.CharSetAlphaNum) + namespace_name := acctest.RandStringFromCharSet(15, acctest.CharSetAlphaNum) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + // Create and Read testing of ably_app.app0 + { + Config: testAccAblyNamespaceConfig(app_name, namespace_name, true, true, true, true, true, true), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ably_app.app0", "name", app_name), + resource.TestCheckResourceAttr("ably_namespace.namespace0", "id", namespace_name), + resource.TestCheckResourceAttr("ably_namespace.namespace0", "authenticated", "true"), + resource.TestCheckResourceAttr("ably_namespace.namespace0", "persisted", "true"), + resource.TestCheckResourceAttr("ably_namespace.namespace0", "persist_last", "true"), + resource.TestCheckResourceAttr("ably_namespace.namespace0", "push_enabled", "true"), + resource.TestCheckResourceAttr("ably_namespace.namespace0", "tls_only", "true"), + resource.TestCheckResourceAttr("ably_namespace.namespace0", "expose_timeserial", "true"), + ), + }, + // Update and Read testing of ably_app.app0 + { + Config: testAccAblyNamespaceConfig(app_name, namespace_name, false, false, false, false, false, false), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ably_app.app0", "name", app_name), + resource.TestCheckResourceAttr("ably_namespace.namespace0", "id", namespace_name), + resource.TestCheckResourceAttr("ably_namespace.namespace0", "authenticated", "false"), + resource.TestCheckResourceAttr("ably_namespace.namespace0", "persisted", "false"), + resource.TestCheckResourceAttr("ably_namespace.namespace0", "persist_last", "false"), + resource.TestCheckResourceAttr("ably_namespace.namespace0", "push_enabled", "false"), + resource.TestCheckResourceAttr("ably_namespace.namespace0", "tls_only", "false"), + resource.TestCheckResourceAttr("ably_namespace.namespace0", "expose_timeserial", "false"), + ), + }, + // Delete testing automatically occurs in TestCase + }, + }) +} + +// Function with inline HCL to provision an ably_app resource +// Takes App name, status and tls_only status as function params. +func testAccAblyNamespaceConfig(appName string, namespaceName string, authenticated, peristed, persistLast, pushEnabled, tlsOnly, exposeTimeserial bool) string { + return fmt.Sprintf(` +terraform { + required_providers { + ably = { + source = "github.com/ably/ably" + } + } +} + +# You can provide your Ably Token & URL inline or use environment variables ABLY_ACCOUNT_TOKEN & ABLY_URL +provider "ably" {} + +resource "ably_app" "app0" { + name = %[1]q + status = "enabled" + tls_only = true +} + +resource "ably_namespace" "namespace0" { + app_id = ably_app.app0.id + id = %[2]q + authenticated = %[3]t + persisted = %[4]t + persist_last = %[5]t + push_enabled = %[6]t + tls_only = %[7]t + expose_timeserial = %[8]t +} + +`, appName, namespaceName, authenticated, peristed, persistLast, pushEnabled, tlsOnly, exposeTimeserial) +} From bd1ff34a766a4ff19b518b9fc803509a717c9671 Mon Sep 17 00:00:00 2001 From: Morgan Adamiec Date: Fri, 19 Aug 2022 15:47:43 +0100 Subject: [PATCH 4/7] Update field names in namespace example --- examples/resources/namespace.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/resources/namespace.tf b/examples/resources/namespace.tf index e6a751f..d93d3cc 100644 --- a/examples/resources/namespace.tf +++ b/examples/resources/namespace.tf @@ -1,6 +1,6 @@ resource "ably_namespace" "namespace1" { - app_id = ably_app.app1.app_id - namespace_id = "namespace" + app_id = ably_app.app1.id + id = "namespace" authenticated = false persisted = false persist_last = false From f6a291361d07aa2029804c6cff76d3a44033d3b1 Mon Sep 17 00:00:00 2001 From: Morgan Adamiec Date: Fri, 19 Aug 2022 15:50:36 +0100 Subject: [PATCH 5/7] Update namespace ID docs --- internal/provider/resource_ably_namespace.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/provider/resource_ably_namespace.go b/internal/provider/resource_ably_namespace.go index 17d8873..916fbbb 100644 --- a/internal/provider/resource_ably_namespace.go +++ b/internal/provider/resource_ably_namespace.go @@ -24,7 +24,7 @@ func (r resourceNamespaceType) GetSchema(_ context.Context) (tfsdk.Schema, diag. "id": { Type: types.StringType, Required: true, - Description: "The namespace ID.", + Description: "The namespace or channel name that the channel rule will apply to.", }, "authenticated": { Type: types.BoolType, From 168ab0e5adb3a433f8dcdf42f9772884a355da7d Mon Sep 17 00:00:00 2001 From: Morgan Adamiec Date: Mon, 22 Aug 2022 15:41:12 +0100 Subject: [PATCH 6/7] Rquire namespace import have an appid and namespaceid --- internal/provider/resource_ably_namespace.go | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/internal/provider/resource_ably_namespace.go b/internal/provider/resource_ably_namespace.go index 916fbbb..7ff0265 100644 --- a/internal/provider/resource_ably_namespace.go +++ b/internal/provider/resource_ably_namespace.go @@ -2,6 +2,8 @@ package ably_control import ( "context" + "fmt" + "strings" ably_control_go "github.com/ably/ably-control-go" "github.com/hashicorp/terraform-plugin-framework/diag" @@ -272,7 +274,16 @@ func (r resourceNamespace) Delete(ctx context.Context, req tfsdk.DeleteResourceR // Import resource func (r resourceNamespace) ImportState(ctx context.Context, req tfsdk.ImportResourceStateRequest, resp *tfsdk.ImportResourceStateResponse) { - // Save the import identifier in the id attribute - // Recent PR in TF Plugin Framework for paths but Hashicorp examples not updated - https://github.com/hashicorp/terraform-plugin-framework/pull/390 - tfsdk.ResourceImportStatePassthroughID(ctx, path.Root("id"), req, resp) + idParts := strings.Split(req.ID, ",") + + if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { + resp.Diagnostics.AddError( + "Unexpected Import Identifier", + fmt.Sprintf("Expected import identifier with format: app_id,namespace_id. Got: %q", req.ID), + ) + return + } + + tfsdk.ResourceImportStatePassthroughID(ctx, path.Root("app_id"), tfsdk.ImportResourceStateRequest{ID: idParts[0]}, resp) + tfsdk.ResourceImportStatePassthroughID(ctx, path.Root("id"), tfsdk.ImportResourceStateRequest{ID: idParts[1]}, resp) } From 070627f814d61ab4a0d221167a2451f8b7fc719e Mon Sep 17 00:00:00 2001 From: Morgan Adamiec Date: Tue, 23 Aug 2022 10:33:23 +0100 Subject: [PATCH 7/7] Force recreate namespace on ID change and test this --- internal/provider/resource_ably_namespace.go | 3 ++ .../provider/resource_ably_namespace_test.go | 49 +++++++++++++++++-- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/internal/provider/resource_ably_namespace.go b/internal/provider/resource_ably_namespace.go index 7ff0265..2540b3b 100644 --- a/internal/provider/resource_ably_namespace.go +++ b/internal/provider/resource_ably_namespace.go @@ -27,6 +27,9 @@ func (r resourceNamespaceType) GetSchema(_ context.Context) (tfsdk.Schema, diag. Type: types.StringType, Required: true, Description: "The namespace or channel name that the channel rule will apply to.", + PlanModifiers: []tfsdk.AttributePlanModifier{ + tfsdk.RequiresReplace(), + }, }, "authenticated": { Type: types.BoolType, diff --git a/internal/provider/resource_ably_namespace_test.go b/internal/provider/resource_ably_namespace_test.go index 6682b40..89c7402 100644 --- a/internal/provider/resource_ably_namespace_test.go +++ b/internal/provider/resource_ably_namespace_test.go @@ -2,9 +2,11 @@ package ably_control import ( "fmt" + "testing" + + ably_control_go "github.com/ably/ably-control-go" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "testing" ) func TestAccAblyNamespace(t *testing.T) { @@ -16,7 +18,15 @@ func TestAccAblyNamespace(t *testing.T) { Steps: []resource.TestStep{ // Create and Read testing of ably_app.app0 { - Config: testAccAblyNamespaceConfig(app_name, namespace_name, true, true, true, true, true, true), + Config: testAccAblyNamespaceConfig(app_name, ably_control_go.Namespace{ + ID: namespace_name, + Authenticated: true, + Persisted: true, + PersistLast: true, + PushEnabled: true, + TlsOnly: true, + ExposeTimeserial: true, + }), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ably_app.app0", "name", app_name), resource.TestCheckResourceAttr("ably_namespace.namespace0", "id", namespace_name), @@ -30,7 +40,15 @@ func TestAccAblyNamespace(t *testing.T) { }, // Update and Read testing of ably_app.app0 { - Config: testAccAblyNamespaceConfig(app_name, namespace_name, false, false, false, false, false, false), + Config: testAccAblyNamespaceConfig(app_name, ably_control_go.Namespace{ + ID: namespace_name, + Authenticated: false, + Persisted: false, + PersistLast: false, + PushEnabled: false, + TlsOnly: false, + ExposeTimeserial: false, + }), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("ably_app.app0", "name", app_name), resource.TestCheckResourceAttr("ably_namespace.namespace0", "id", namespace_name), @@ -42,6 +60,27 @@ func TestAccAblyNamespace(t *testing.T) { resource.TestCheckResourceAttr("ably_namespace.namespace0", "expose_timeserial", "false"), ), }, + { + Config: testAccAblyNamespaceConfig(app_name, ably_control_go.Namespace{ + ID: namespace_name + "new", + Authenticated: false, + Persisted: false, + PersistLast: false, + PushEnabled: false, + TlsOnly: false, + ExposeTimeserial: false, + }), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ably_app.app0", "name", app_name), + resource.TestCheckResourceAttr("ably_namespace.namespace0", "id", namespace_name+"new"), + resource.TestCheckResourceAttr("ably_namespace.namespace0", "authenticated", "false"), + resource.TestCheckResourceAttr("ably_namespace.namespace0", "persisted", "false"), + resource.TestCheckResourceAttr("ably_namespace.namespace0", "persist_last", "false"), + resource.TestCheckResourceAttr("ably_namespace.namespace0", "push_enabled", "false"), + resource.TestCheckResourceAttr("ably_namespace.namespace0", "tls_only", "false"), + resource.TestCheckResourceAttr("ably_namespace.namespace0", "expose_timeserial", "false"), + ), + }, // Delete testing automatically occurs in TestCase }, }) @@ -49,7 +88,7 @@ func TestAccAblyNamespace(t *testing.T) { // Function with inline HCL to provision an ably_app resource // Takes App name, status and tls_only status as function params. -func testAccAblyNamespaceConfig(appName string, namespaceName string, authenticated, peristed, persistLast, pushEnabled, tlsOnly, exposeTimeserial bool) string { +func testAccAblyNamespaceConfig(appName string, namespace ably_control_go.Namespace) string { return fmt.Sprintf(` terraform { required_providers { @@ -79,5 +118,5 @@ resource "ably_namespace" "namespace0" { expose_timeserial = %[8]t } -`, appName, namespaceName, authenticated, peristed, persistLast, pushEnabled, tlsOnly, exposeTimeserial) +`, appName, namespace.ID, namespace.Authenticated, namespace.Persisted, namespace.PersistLast, namespace.PushEnabled, namespace.TlsOnly, namespace.ExposeTimeserial) }