diff --git a/examples/azure/terraform-azure-servicebus-example/README.md b/examples/azure/terraform-azure-servicebus-example/README.md new file mode 100644 index 000000000..64ecad686 --- /dev/null +++ b/examples/azure/terraform-azure-servicebus-example/README.md @@ -0,0 +1,31 @@ +# Terraform Azure Service Bus Example + +This folder contains a Terraform module that deploys resources in [Azure](https://azure.microsoft.com/) to demonstrate how you can use Terratest to write automated tests for your Azure Terraform code. This module deploys a Service Bus. + +- A [Service Bus](https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-messaging-overview) with the namespace specified in the `namespace_name` variable. + +Check out [test/azure/terraform_azure_servicebus_example_test.go](./../../../test/azure/terraform_azure_servicebus_example_test.go) to see how you can write automated tests for this module and validate the configuration of the parameters and options. + +**WARNING**: This module and the automated tests for it deploy real resources into your Azure account which can cost you money. The resources are all part of the [Azure Free Account](https://azure.microsoft.com/en-us/free/), so if you haven't used that up, +it should be free, but you are completely responsible for all Azure charges. + +## Running this module manually +1. Sign up for [Azure](https://azure.microsoft.com/). +1. Configure your Azure credentials using one of the [supported methods for Azure CLI + tools](https://docs.microsoft.com/en-us/cli/azure/azure-cli-configuration?view=azure-cli-latest) +1. Install [Terraform](https://www.terraform.io/) and make sure it's on your `PATH`. +1. Ensure [environment variables](../README.md#review-environment-variables) are available +1. Run `terraform init` +1. Run `terraform apply` +1. When you're done, run `terraform destroy`. + + +## Running automated tests against this module +1. Sign up for [Azure](https://azure.microsoft.com/) +1. Configure your Azure credentials using one of the [supported methods for Azure CLI + tools](https://docs.microsoft.com/en-us/cli/azure/azure-cli-configuration?view=azure-cli-latest) +1. Install [Terraform](https://www.terraform.io/) and make sure it's on your `PATH` +1. Configure your Terratest [Go test environment](../README.md) +1. `cd test/azure` +1. `go build terraform_azure_servicebus_example_test.go` +1. `go test -v -run TestTerraformAzureServiceBusExample` diff --git a/examples/azure/terraform-azure-servicebus-example/main.tf b/examples/azure/terraform-azure-servicebus-example/main.tf new file mode 100644 index 000000000..6ff4550c0 --- /dev/null +++ b/examples/azure/terraform-azure-servicebus-example/main.tf @@ -0,0 +1,159 @@ +# --------------------------------------------------------------------------------------------------------------------- +# DEPLOY AN AZURE SERVICE BUS +# This is an example of how to deploy an Azure service bus. +# See test/terraform_azure_example_test.go for how to write automated tests for this code. +# --------------------------------------------------------------------------------------------------------------------- + + +# --------------------------------------------------------------------------------------------------------------------- +# CONFIGURE OUR AZURE CONNECTION +# --------------------------------------------------------------------------------------------------------------------- + +provider "azurerm" { + version = "~>2.29" + features {} +} + +# --------------------------------------------------------------------------------------------------------------------- +# DEPLOY A RESOURCE GROUP +# --------------------------------------------------------------------------------------------------------------------- + +resource "azurerm_resource_group" "servicebus_rg" { + name = "terratest-sb-rg-${var.postfix}" + location = var.location +} + +# --------------------------------------------------------------------------------------------------------------------- +# Define locals variables +# --------------------------------------------------------------------------------------------------------------------- +locals { + topic_authorization_rules = flatten([ + for topic in var.topics : [ + for rule in topic.authorization_rules : + merge( + rule, { + topic_name = topic.name + }) + ] + ]) + + topic_subscriptions = flatten([ + for topic in var.topics : [ + for subscription in topic.subscriptions : + merge( + subscription, { + topic_name = topic.name + }) + ] + ]) + + topic_subscription_rules = flatten([ + for subscription in local.topic_subscriptions : + merge({ + filter_type = "" + sql_filter = "" + action = "" + }, subscription, { + topic_name = subscription.topic_name + subscription_name = subscription.name + }) + if subscription.filter_type != null + ]) +} + +# --------------------------------------------------------------------------------------------------------------------- +# DEPLOY AZURE Service Bus Namespace +# --------------------------------------------------------------------------------------------------------------------- +resource "azurerm_servicebus_namespace" "servicebus" { + name = "terratest-namespace-${var.namespace_name}" + location = azurerm_resource_group.servicebus_rg.location + resource_group_name = azurerm_resource_group.servicebus_rg.name + sku = var.sku + tags = var.tags +} + +# --------------------------------------------------------------------------------------------------------------------- +# DEPLOY AZURE Service Bus Namespace Authorization Rule +# --------------------------------------------------------------------------------------------------------------------- +resource "azurerm_servicebus_namespace_authorization_rule" "sbnamespaceauth" { + count = length(var.namespace_authorization_rules) + + name = var.namespace_authorization_rules[count.index].policy_name + namespace_name = azurerm_servicebus_namespace.servicebus.name + resource_group_name = azurerm_resource_group.servicebus_rg.name + + listen = var.namespace_authorization_rules[count.index].claims.listen + send = var.namespace_authorization_rules[count.index].claims.send + manage = var.namespace_authorization_rules[count.index].claims.manage +} + +# --------------------------------------------------------------------------------------------------------------------- +# DEPLOY AZURE Service Bus Topic +# --------------------------------------------------------------------------------------------------------------------- +resource "azurerm_servicebus_topic" "sptopic" { + count = length(var.topics) + + name = var.topics[count.index].name + resource_group_name = azurerm_resource_group.servicebus_rg.name + namespace_name = azurerm_servicebus_namespace.servicebus.name + + requires_duplicate_detection = var.topics[count.index].requires_duplicate_detection + default_message_ttl = var.topics[count.index].default_message_ttl + enable_partitioning = var.topics[count.index].enable_partitioning + support_ordering = var.topics[count.index].support_ordering +} + +# --------------------------------------------------------------------------------------------------------------------- +# DEPLOY AZURE Service Bus Topic Authorization Rule +# --------------------------------------------------------------------------------------------------------------------- +resource "azurerm_servicebus_topic_authorization_rule" "topicaauth" { + count = length(local.topic_authorization_rules) + + name = local.topic_authorization_rules[count.index].policy_name + resource_group_name = azurerm_resource_group.servicebus_rg.name + namespace_name = azurerm_servicebus_namespace.servicebus.name + topic_name = local.topic_authorization_rules[count.index].topic_name + + listen = local.topic_authorization_rules[count.index].claims.listen + send = local.topic_authorization_rules[count.index].claims.send + manage = local.topic_authorization_rules[count.index].claims.manage + + depends_on = [azurerm_servicebus_topic.sptopic] +} + +# --------------------------------------------------------------------------------------------------------------------- +# DEPLOY AZURE Service Bus Subscription +# --------------------------------------------------------------------------------------------------------------------- +resource "azurerm_servicebus_subscription" "subscription" { + count = length(local.topic_subscriptions) + + name = local.topic_subscriptions[count.index].name + resource_group_name = azurerm_resource_group.servicebus_rg.name + namespace_name = azurerm_servicebus_namespace.servicebus.name + topic_name = local.topic_subscriptions[count.index].topic_name + + max_delivery_count = local.topic_subscriptions[count.index].max_delivery_count + lock_duration = local.topic_subscriptions[count.index].lock_duration + forward_to = local.topic_subscriptions[count.index].forward_to + dead_lettering_on_message_expiration = local.topic_subscriptions[count.index].dead_lettering_on_message_expiration + + depends_on = [azurerm_servicebus_topic.sptopic] +} + +# --------------------------------------------------------------------------------------------------------------------- +# DEPLOY AZURE Service Bus Subscription Rules +# --------------------------------------------------------------------------------------------------------------------- +resource "azurerm_servicebus_subscription_rule" "subrules" { + count = length(local.topic_subscription_rules) + + name = local.topic_subscription_rules[count.index].name + resource_group_name = azurerm_resource_group.servicebus_rg.name + namespace_name = azurerm_servicebus_namespace.servicebus.name + topic_name = local.topic_subscription_rules[count.index].topic_name + subscription_name = local.topic_subscription_rules[count.index].subscription_name + filter_type = local.topic_subscription_rules[count.index].filter_type != "" ? "SqlFilter" : null + sql_filter = local.topic_subscription_rules[count.index].sql_filter + action = local.topic_subscription_rules[count.index].action + + depends_on = [azurerm_servicebus_subscription.subscription] +} diff --git a/examples/azure/terraform-azure-servicebus-example/outputs.tf b/examples/azure/terraform-azure-servicebus-example/outputs.tf new file mode 100644 index 000000000..d8435b170 --- /dev/null +++ b/examples/azure/terraform-azure-servicebus-example/outputs.tf @@ -0,0 +1,66 @@ +output "resource_group" { + description = "The resource group name of the Service Bus namespace." + value = azurerm_resource_group.servicebus_rg.name +} + +output "namespace_name" { + description = "The namespace name." + value = azurerm_servicebus_namespace.servicebus.name +} + +output "namespace_id" { + description = "The namespace ID." + value = azurerm_servicebus_namespace.servicebus.id + sensitive = true +} + +output "namespace_authorization_rules" { + description = "List of namespace authorization rules." + value = { + for auth in azurerm_servicebus_namespace_authorization_rule.sbnamespaceauth : + auth.name => { + listen = auth.listen + send = auth.send + manage = auth.manage + } + } + sensitive = true +} + +output "service_bus_namespace_default_primary_key" { + description = "The primary access key for the authorization rule RootManageSharedAccessKey which is created automatically by Azure." + value = azurerm_servicebus_namespace.servicebus.default_primary_key + sensitive = true +} + +output "service_bus_namespace_default_connection_string" { + description = "The primary connection string for the authorization rule RootManageSharedAccessKey which is created automatically by Azure." + value = azurerm_servicebus_namespace.servicebus.default_primary_connection_string + sensitive = true +} + + +output "topics" { + description = "All topics with the corresponding subscriptions" + value = { + for topic in azurerm_servicebus_topic.sptopic : + topic.name => { + id = topic.id + name = topic.name + authorization_rules = { + for auth in azurerm_servicebus_topic_authorization_rule.topicaauth : + auth.name => { + listen = auth.listen + send = auth.send + manage = auth.manage + } if topic.name == auth.topic_name + } + subscriptions = { + for subscription in azurerm_servicebus_subscription.subscription : + subscription.name => { + name = subscription.name + } if topic.name == subscription.topic_name + } + } + } +} diff --git a/examples/azure/terraform-azure-servicebus-example/variables.tf b/examples/azure/terraform-azure-servicebus-example/variables.tf new file mode 100644 index 000000000..fb065985f --- /dev/null +++ b/examples/azure/terraform-azure-servicebus-example/variables.tf @@ -0,0 +1,85 @@ +# --------------------------------------------------------------------------------------------------------------------- +# ENVIRONMENT VARIABLES +# Define these secrets as environment variables +# --------------------------------------------------------------------------------------------------------------------- + +# ARM_CLIENT_ID +# ARM_CLIENT_SECRET +# ARM_SUBSCRIPTION_ID +# ARM_TENANT_ID + +# --------------------------------------------------------------------------------------------------------------------- +# REQUIRED PARAMETERS +# You must provide a value for each of these parameters. +# --------------------------------------------------------------------------------------------------------------------- + +# --------------------------------------------------------------------------------------------------------------------- +# OPTIONAL PARAMETERS +# These parameters have reasonable defaults. +# --------------------------------------------------------------------------------------------------------------------- + +variable "location" { + description = "The supported azure location where the resource exists" + type = string + default = "West US2" +} + +variable "postfix" { + description = "string mitigate resource name collisions." + type = string + default = "servicebus" +} + +variable "namespace_name" { + description = "The name of the namespace." + type = string + default = "testservicebus101" +} + +variable "sku" { + description = "The SKU of the namespace. The options are: `Basic`, `Standard`, `Premium`." + type = string + default = "Standard" +} + +variable "tags" { + description = " A mapping of tags to assign to the resource." + type = map(string) + default = {} +} + +variable "namespace_authorization_rules" { + description = "List of namespace authorization rules." + type = list(object({ + policy_name = string + claims = object({ listen = bool, manage = bool, send = bool }) + })) + default = [] +} + +variable "topics" { + description = "topics list" + type = list(object({ + name = string + default_message_ttl = string //ISO 8601 format + enable_partitioning = bool + requires_duplicate_detection = bool + support_ordering = bool + authorization_rules = list(object({ + policy_name = string + claims = object({ listen = bool, manage = bool, send = bool }) + + })) + subscriptions = list(object({ + name = string + max_delivery_count = number + lock_duration = string //ISO 8601 format + forward_to = string //set with the topic name that will be used for forwarding. Otherwise, set to "" + dead_lettering_on_message_expiration = bool + filter_type = string // SqlFilter is the only supported type now. + sql_filter = string //Required when filter_type is set to SqlFilter + action = string + })) + })) + default = [] +} diff --git a/modules/azure/servicebus.go b/modules/azure/servicebus.go new file mode 100644 index 000000000..ca6eab3b2 --- /dev/null +++ b/modules/azure/servicebus.go @@ -0,0 +1,370 @@ +package azure + +import ( + "context" + "testing" + + "github.com/Azure/azure-sdk-for-go/services/servicebus/mgmt/2017-04-01/servicebus" + "github.com/stretchr/testify/require" +) + +func serviceBusNamespaceClientE(subscriptionID string) (*servicebus.NamespacesClient, error) { + authorizer, err := NewAuthorizer() + if err != nil { + return nil, err + } + + nsClient := servicebus.NewNamespacesClient(subscriptionID) + nsClient.Authorizer = *authorizer + return &nsClient, nil +} + +func serviceBusTopicClientE(subscriptionID string) (*servicebus.TopicsClient, error) { + authorizer, err := NewAuthorizer() + if err != nil { + return nil, err + } + + tClient := servicebus.NewTopicsClient(subscriptionID) + tClient.Authorizer = *authorizer + return &tClient, nil +} + +func serviceBusSubscriptionsClientE(subscriptionID string) (*servicebus.SubscriptionsClient, error) { + authorizer, err := NewAuthorizer() + if err != nil { + return nil, err + } + + sClient := servicebus.NewSubscriptionsClient(subscriptionID) + sClient.Authorizer = *authorizer + return &sClient, nil +} + +// ListServiceBusNamespaceE list all SB namespaces in all resource groups in the given subscription ID. +func ListServiceBusNamespaceE(subscriptionID string) ([]servicebus.SBNamespace, error) { + nsClient, err := serviceBusNamespaceClientE(subscriptionID) + if err != nil { + return nil, err + } + + iteratorSBNamespace, err := nsClient.ListComplete(context.Background()) + if err != nil { + return nil, err + } + + results := make([]servicebus.SBNamespace, 0) + for iteratorSBNamespace.NotDone() { + results = append(results, iteratorSBNamespace.Value()) + if err := iteratorSBNamespace.Next(); err != nil { + return nil, err + } + } + + return results, nil +} + +// ListServiceBusNamespace - list all SB namespaces in all resource groups in the given subscription ID. This function would fail the test if there is an error. +func ListServiceBusNamespace(t *testing.T, subscriptionID string) []servicebus.SBNamespace { + results, err := ListServiceBusNamespaceE(subscriptionID) + + require.NoError(t, err) + + return results +} + +// ListServiceBusNamespaceNamesE list names of all SB namespaces in all resource groups in the given subscription ID. +func ListServiceBusNamespaceNamesE(subscriptionID string) ([]string, error) { + sbNamespace, err := ListServiceBusNamespaceE(subscriptionID) + + if err != nil { + return nil, err + } + + results := BuildNamespaceNamesList(sbNamespace) + return results, nil +} + +// BuildNamespaceNamesList helper method to build namespace name list +func BuildNamespaceNamesList(sbNamespace []servicebus.SBNamespace) []string { + results := []string{} + for _, namespace := range sbNamespace { + results = append(results, *namespace.Name) + + } + + return results +} + +// BuildNamespaceIdsList helper method to build namespace id list +func BuildNamespaceIdsList(sbNamespace []servicebus.SBNamespace) []string { + results := []string{} + for _, namespace := range sbNamespace { + results = append(results, *namespace.ID) + + } + + return results +} + +// ListServiceBusNamespaceNames list names of all SB namespaces in all resource groups in the given subscription ID. This function would fail the test if there is an error. +func ListServiceBusNamespaceNames(t *testing.T, subscriptionID string) []string { + results, err := ListServiceBusNamespaceNamesE(subscriptionID) + + require.NoError(t, err) + + return results +} + +// ListServiceBusNamespaceIDsE list IDs of all SB namespaces in all resource groups in the given subscription ID. +func ListServiceBusNamespaceIDsE(subscriptionID string) ([]string, error) { + sbNamespace, err := ListServiceBusNamespaceE(subscriptionID) + + if err != nil { + return nil, err + } + + results := BuildNamespaceIdsList(sbNamespace) + return results, nil +} + +// ListServiceBusNamespaceIDs list IDs of all SB namespaces in all resource groups in the given subscription ID. This function would fail the test if there is an error. +func ListServiceBusNamespaceIDs(t *testing.T, subscriptionID string) []string { + results, err := ListServiceBusNamespaceIDsE(subscriptionID) + require.NoError(t, err) + + return results +} + +// ListServiceBusNamespaceByResourceGroupE list all SB namespaces in the given resource group. +func ListServiceBusNamespaceByResourceGroupE(subscriptionID string, resourceGroup string) ([]servicebus.SBNamespace, error) { + nsClient, err := serviceBusNamespaceClientE(subscriptionID) + if err != nil { + return nil, err + } + + iteratorSBNamespace, err := nsClient.ListByResourceGroupComplete(context.Background(), resourceGroup) + if err != nil { + return nil, err + } + + results := make([]servicebus.SBNamespace, 0) + + for iteratorSBNamespace.NotDone() { + results = append(results, iteratorSBNamespace.Value()) + if err := iteratorSBNamespace.Next(); err != nil { + return nil, err + } + } + + return results, nil +} + +// ListServiceBusNamespaceByResourceGroup list all SB namespaces in the given resource group. This function would fail the test if there is an error. +func ListServiceBusNamespaceByResourceGroup(t *testing.T, subscriptionID string, resourceGroup string) []servicebus.SBNamespace { + results, err := ListServiceBusNamespaceByResourceGroupE(subscriptionID, resourceGroup) + require.NoError(t, err) + + return results +} + +// ListServiceBusNamespaceNamesByResourceGroupE list names of all SB namespaces in the given resource group. This function would fail the test if there is an error. +func ListServiceBusNamespaceNamesByResourceGroupE(subscriptionID string, resourceGroup string) ([]string, error) { + sbNamespace, err := ListServiceBusNamespaceByResourceGroupE(subscriptionID, resourceGroup) + + if err != nil { + return nil, err + } + + results := BuildNamespaceNamesList(sbNamespace) + return results, nil +} + +// ListServiceBusNamespaceNamesByResourceGroup list names of all SB namespaces in the given resource group. +func ListServiceBusNamespaceNamesByResourceGroup(t *testing.T, subscriptionID string, resourceGroup string) []string { + results, err := ListServiceBusNamespaceNamesByResourceGroupE(subscriptionID, resourceGroup) + require.NoError(t, err) + + return results +} + +// ListServiceBusNamespaceIDsByResourceGroupE list IDs of all SB namespaces in the given resource group. +func ListServiceBusNamespaceIDsByResourceGroupE(subscriptionID string, resourceGroup string) ([]string, error) { + sbNamespace, err := ListServiceBusNamespaceByResourceGroupE(subscriptionID, resourceGroup) + + if err != nil { + return nil, err + } + + results := BuildNamespaceIdsList(sbNamespace) + return results, nil +} + +// ListServiceBusNamespaceIDsByResourceGroup list IDs of all SB namespaces in the given resource group. This function would fail the test if there is an error. +func ListServiceBusNamespaceIDsByResourceGroup(t *testing.T, subscriptionID string, resourceGroup string) []string { + results, err := ListServiceBusNamespaceIDsByResourceGroupE(subscriptionID, resourceGroup) + require.NoError(t, err) + + return results +} + +// ListNamespaceAuthRulesE - authenticate namespace client and enumerates all values to get list of authorization rules for the given namespace name, +// automatically crossing page boundaries as required. +func ListNamespaceAuthRulesE(subscriptionID string, namespace string, resourceGroup string) ([]string, error) { + nsClient, err := serviceBusNamespaceClientE(subscriptionID) + if err != nil { + return nil, err + } + iteratorNamespaceRules, err := nsClient.ListAuthorizationRulesComplete( + context.Background(), resourceGroup, namespace) + + if err != nil { + return nil, err + } + + results := []string{} + for iteratorNamespaceRules.NotDone() { + results = append(results, *(iteratorNamespaceRules.Value()).Name) + if err := iteratorNamespaceRules.Next(); err != nil { + return nil, err + } + } + return results, nil +} + +// ListNamespaceAuthRules - authenticate namespace client and enumerates all values to get list of authorization rules for the given namespace name, +// automatically crossing page boundaries as required. This function would fail the test if there is an error. +func ListNamespaceAuthRules(t *testing.T, subscriptionID string, namespace string, resourceGroup string) []string { + results, err := ListNamespaceAuthRulesE(subscriptionID, namespace, resourceGroup) + require.NoError(t, err) + + return results +} + +// ListNamespaceTopicsE - authenticate topic client and enumerates all values, automatically crossing page boundaries as required. +func ListNamespaceTopicsE(subscriptionID string, namespace string, resourceGroup string) ([]servicebus.SBTopic, error) { + tClient, err := serviceBusTopicClientE(subscriptionID) + if err != nil { + return nil, err + } + + iteratorTopics, err := tClient.ListByNamespaceComplete(context.Background(), resourceGroup, namespace, nil, nil) + if err != nil { + return nil, err + } + + results := make([]servicebus.SBTopic, 0) + + for iteratorTopics.NotDone() { + results = append(results, iteratorTopics.Value()) + if err := iteratorTopics.Next(); err != nil { + return nil, err + } + } + + return results, nil +} + +// ListNamespaceTopics - authenticate topic client and enumerates all values, automatically crossing page boundaries as required. This function would fail the test if there is an error. +func ListNamespaceTopics(t *testing.T, subscriptionID string, namespace string, resourceGroup string) []servicebus.SBTopic { + results, err := ListNamespaceTopicsE(subscriptionID, namespace, resourceGroup) + require.NoError(t, err) + + return results +} + +// ListTopicSubscriptionsE - authenticate subscriptions client and enumerates all values, automatically crossing page boundaries as required. +func ListTopicSubscriptionsE(subscriptionID string, namespace string, resourceGroup string, topicName string) ([]servicebus.SBSubscription, error) { + sClient, err := serviceBusSubscriptionsClientE(subscriptionID) + if err != nil { + return nil, err + } + iteratorSubscription, err := sClient.ListByTopicComplete(context.Background(), resourceGroup, namespace, topicName, nil, nil) + + if err != nil { + return nil, err + } + + results := make([]servicebus.SBSubscription, 0) + + for iteratorSubscription.NotDone() { + results = append(results, iteratorSubscription.Value()) + if err := iteratorSubscription.Next(); err != nil { + return nil, err + } + } + return results, nil +} + +// ListTopicSubscriptions - authenticate subscriptions client and enumerates all values, automatically crossing page boundaries as required. This function would fail the test if there is an error. +func ListTopicSubscriptions(t *testing.T, subscriptionID string, namespace string, resourceGroup string, topicName string) []servicebus.SBSubscription { + results, err := ListTopicSubscriptionsE(subscriptionID, namespace, resourceGroup, topicName) + require.NoError(t, err) + + return results +} + +// ListTopicSubscriptionsNameE - authenticate subscriptions client and enumerates all values to get list of subscriptions for the given topic name, +// automatically crossing page boundaries as required. +func ListTopicSubscriptionsNameE(subscriptionID string, namespace string, resourceGroup string, topicName string) ([]string, error) { + sClient, err := serviceBusSubscriptionsClientE(subscriptionID) + if err != nil { + return nil, err + } + iteratorSubscription, err := sClient.ListByTopicComplete(context.Background(), resourceGroup, namespace, topicName, nil, nil) + + if err != nil { + return nil, err + } + + results := []string{} + for iteratorSubscription.NotDone() { + results = append(results, *(iteratorSubscription.Value()).Name) + if err := iteratorSubscription.Next(); err != nil { + return nil, err + } + } + return results, nil +} + +// ListTopicSubscriptionsName - authenticate subscriptions client and enumerates all values to get list of subscriptions for the given topic name, +// automatically crossing page boundaries as required. This function would fail the test if there is an error. +func ListTopicSubscriptionsName(t *testing.T, subscriptionID string, namespace string, resourceGroup string, topicName string) []string { + results, err := ListTopicSubscriptionsNameE(subscriptionID, namespace, resourceGroup, topicName) + require.NoError(t, err) + + return results +} + +// ListTopicAuthRulesE - authenticate topic client and enumerates all values to get list of authorization rules for the given topic name, +// automatically crossing page boundaries as required. +func ListTopicAuthRulesE(subscriptionID string, namespace string, resourceGroup string, topicName string) ([]string, error) { + tClient, err := serviceBusTopicClientE(subscriptionID) + if err != nil { + return nil, err + } + iteratorTopicsRules, err := tClient.ListAuthorizationRulesComplete( + context.Background(), resourceGroup, namespace, topicName) + + if err != nil { + return nil, err + } + + results := []string{} + for iteratorTopicsRules.NotDone() { + results = append(results, *(iteratorTopicsRules.Value()).Name) + if err := iteratorTopicsRules.Next(); err != nil { + return nil, err + } + } + return results, nil +} + +// ListTopicAuthRules - authenticate topic client and enumerates all values to get list of authorization rules for the given topic name, +// automatically crossing page boundaries as required. This function would fail the test if there is an error. +func ListTopicAuthRules(t *testing.T, subscriptionID string, namespace string, resourceGroup string, topicName string) []string { + results, err := ListTopicAuthRulesE(subscriptionID, namespace, resourceGroup, topicName) + require.NoError(t, err) + + return results +} diff --git a/modules/azure/servicebus_test.go b/modules/azure/servicebus_test.go new file mode 100644 index 000000000..f96077dd4 --- /dev/null +++ b/modules/azure/servicebus_test.go @@ -0,0 +1,79 @@ +// +build azure + +// NOTE: We use build tags to differentiate azure testing because we currently do not have azure access setup for +// CircleCI. +package azure + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +/* +The below tests are currently stubbed out, with the expectation that they will throw errors. These tests can be extended. +*/ +func TestListServiceBusNamespaceNamesE(t *testing.T) { + t.Parallel() + + subscriptionID := "" + + _, err := ListServiceBusNamespaceNamesE(subscriptionID) + require.Error(t, err) +} + +func TestListServiceBusNamespaceIDsByResourceGroupE(t *testing.T) { + t.Parallel() + + subscriptionID := "" + resourceGroup := "" + + _, err := ListServiceBusNamespaceIDsByResourceGroupE(subscriptionID, resourceGroup) + require.Error(t, err) +} + +func TestListNamespaceAuthRulesE(t *testing.T) { + t.Parallel() + + subscriptionID := "" + namespace := "" + resourceGroup := "" + + _, err := ListNamespaceAuthRulesE(subscriptionID, namespace, resourceGroup) + require.Error(t, err) +} + +func TestListNamespaceTopicsE(t *testing.T) { + t.Parallel() + + subscriptionID := "" + namespace := "" + resourceGroup := "" + + _, err := ListNamespaceTopicsE(subscriptionID, namespace, resourceGroup) + require.Error(t, err) +} + +func TestListTopicAuthRulesE(t *testing.T) { + t.Parallel() + + subscriptionID := "" + namespace := "" + resourceGroup := "" + topicName := "" + + _, err := ListTopicAuthRulesE(subscriptionID, namespace, resourceGroup, topicName) + require.Error(t, err) +} + +func TestListTopicSubscriptionsNameE(t *testing.T) { + t.Parallel() + + subscriptionID := "" + namespace := "" + resourceGroup := "" + topicName := "" + + _, err := ListTopicSubscriptionsNameE(subscriptionID, namespace, resourceGroup, topicName) + require.Error(t, err) +} diff --git a/test/azure/terraform_azure_servicebus_example_test.go b/test/azure/terraform_azure_servicebus_example_test.go new file mode 100644 index 000000000..64dd12f53 --- /dev/null +++ b/test/azure/terraform_azure_servicebus_example_test.go @@ -0,0 +1,67 @@ +// +build azure + +// NOTE: We use build tags to differentiate azure testing because we currently do not have azure access setup for +// CircleCI. + +package test + +import ( + "os" + "strings" + "testing" + + "github.com/gruntwork-io/terratest/modules/azure" + "github.com/gruntwork-io/terratest/modules/random" + "github.com/gruntwork-io/terratest/modules/terraform" + "github.com/stretchr/testify/assert" +) + +func TestTerraformAzureServiceBusExample(t *testing.T) { + t.Parallel() + + uniquePostfix := strings.ToLower(random.UniqueId()) + + // website::tag::1:: Configure Terraform setting up a path to Terraform code. + terraformOptions := &terraform.Options{ + // The path to where our Terraform code is located + TerraformDir: "../../examples/azure/terraform-azure-servicebus-example", + Vars: map[string]interface{}{ + "postfix": uniquePostfix, + }, + } + + // website::tag::4:: At the end of the test, run `terraform destroy` to clean up any resources that were created + defer terraform.Destroy(t, terraformOptions) + + // website::tag::2:: Run `terraform init` and `terraform apply`. Fail the test if there are any errors. + terraform.InitAndApply(t, terraformOptions) + + // website::tag::3:: Run `terraform output` to get the values of output variables + expectedTopicSubscriptionsMap := terraform.OutputMapOfObjects(t, terraformOptions, "topics") + expectedNamespaceName := terraform.Output(t, terraformOptions, "namespace_name") + expectedResourceGroup := terraform.Output(t, terraformOptions, "resource_group") + + for topicName, topicsMap := range expectedTopicSubscriptionsMap { + actualsubscriptionNames := azure.ListTopicSubscriptionsName(t, + os.Getenv("ARM_SUBSCRIPTION_ID"), + expectedNamespaceName, + expectedResourceGroup, + topicName) + + subscriptionsMap := topicsMap.(map[string]interface{})["subscriptions"].(map[string]interface{}) + subscriptionNamesFromOutput := getMapKeylist(subscriptionsMap) + // each subscription from the output should also exist in Azure + assert.Equal(t, len(subscriptionNamesFromOutput), len(actualsubscriptionNames)) + for _, subscrptionName := range subscriptionNamesFromOutput { + assert.Contains(t, actualsubscriptionNames, subscrptionName) + } + } +} + +func getMapKeylist(mapList map[string]interface{}) []string { + names := make([]string, 0) + for key := range mapList { + names = append(names, key) + } + return names +}