From c9c94e5051979bfa8c5d397f2edfb56dfcf0beaa Mon Sep 17 00:00:00 2001
From: danielscholl <dascholl@microsoft.com>
Date: Sun, 2 Feb 2025 11:36:04 -0600
Subject: [PATCH 01/15] Initial test validation effort.

---
 .../providers/azure/resource-group/test.sh    | 218 ++++++++++++++
 .../azure/resource-group/testing/main.tf      |  35 ++-
 .../azure/resource-group/testing/unit_test.go |   5 +-
 .../providers/azure/storage-account/main.tf   |  14 +
 .../providers/azure/storage-account/test.sh   | 266 ++++++++++++++++++
 .../azure/storage-account/testing/main.tf     |  68 +++--
 .../storage-account/testing/unit_test.go      |  19 +-
 .../azure/storage-account/tests/tf_options.go |  11 +-
 .../unit/storage_deployment_unit_test.go      |  18 +-
 .../azure/storage-account/variables.tf        |   9 +-
 10 files changed, 618 insertions(+), 45 deletions(-)
 create mode 100755 infra/modules/providers/azure/resource-group/test.sh
 create mode 100755 infra/modules/providers/azure/storage-account/test.sh

diff --git a/infra/modules/providers/azure/resource-group/test.sh b/infra/modules/providers/azure/resource-group/test.sh
new file mode 100755
index 000000000..f5fd6a3cf
--- /dev/null
+++ b/infra/modules/providers/azure/resource-group/test.sh
@@ -0,0 +1,218 @@
+#!/bin/bash
+
+# Exit on error
+set -e
+
+###############################
+# Script Path Configuration
+###############################
+SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
+TESTING_DIR="${SCRIPT_DIR}/testing"
+
+###############################
+# Required Environment Variables
+###############################
+# ARM_SUBSCRIPTION_ID should be set in the environment
+# Example: export ARM_SUBSCRIPTION_ID="00000000-0000-0000-0000-000000000000"
+
+###############################
+# Optional Variables
+###############################
+# These can be overridden by setting them before running the script
+RESOURCE_GROUP_NAME=${RESOURCE_GROUP_NAME:-"osdu-test"}
+LOCATION=${LOCATION:-"eastus2"}
+
+###############################
+# Utility Functions
+###############################
+
+print_header() {
+    local title="$1"
+    printf "\n"
+    tput setaf 3
+    echo "=================================================================="
+    tput setaf 6
+    echo "                         ${title}                                 "
+    tput setaf 3
+    echo "=================================================================="
+    tput sgr0
+    printf "\n"
+}
+
+log() {
+    local _msg="$1"
+    local _color="${2:-5}"
+
+    if [[ -t 1 ]]; then
+        tput setaf $_color
+        echo "$_msg"
+        tput sgr0
+    else
+        echo "$_msg"
+    fi
+}
+
+print_separator() {
+    if [[ -t 1 ]]; then
+        echo ""
+        tput setaf 4  # Blue color for sub-headers
+        echo "▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼"
+        tput sgr0
+        echo ""
+    else
+        echo "\n▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼\n"
+    fi
+}
+
+###############################
+# Variable Validation
+###############################
+
+validate_variables() {
+    print_header "Variable Validation"
+
+    if [ -z "$ARM_SUBSCRIPTION_ID" ]; then
+        log "Error: ARM_SUBSCRIPTION_ID environment variable is not set" 1
+        log "Usage: export ARM_SUBSCRIPTION_ID='00000000-0000-0000-0000-000000000000' && $0" 1
+        exit 1
+    fi
+    log "Using Subscription: $ARM_SUBSCRIPTION_ID" 6
+    log "Using Resource Group: $RESOURCE_GROUP_NAME" 6
+    log "Using Location: $LOCATION" 6
+}
+
+###############################
+# Setup Functions
+###############################
+
+setup_azure() {
+    print_header "Azure Setup"
+
+    # Only verify subscription access
+    log "Verifying Azure subscription..." 5
+    az account show --subscription "$ARM_SUBSCRIPTION_ID" || {
+        log "Error: Could not access subscription $ARM_SUBSCRIPTION_ID" 1
+        exit 1
+    }
+    log "Azure subscription verified successfully" 2
+}
+
+create_tfvars_files() {
+    print_header "Terraform Configuration"
+
+    log "Creating testing.tfvars files..." 5
+    mkdir -p "${TESTING_DIR}"
+    cat > "${TESTING_DIR}/testing.tfvars" << EOF
+name = "$RESOURCE_GROUP_NAME"
+location = "$LOCATION"
+EOF
+    log "Configuration files created successfully" 2
+}
+
+###############################
+# Testing Functions
+###############################
+
+run_unit_tests() {
+    print_header "Unit Tests"
+    log "Running unit tests..." 5
+    echo ""
+    pushd "${TESTING_DIR}" > /dev/null
+    go test -v
+    popd > /dev/null
+    echo ""
+    log "Unit tests completed" 2
+}
+
+###############################
+# Terraform Functions
+###############################
+
+terraform_init_and_apply() {
+    print_header "Terraform Deployment"
+
+    log "Initializing Terraform..." 5
+    pushd "${TESTING_DIR}" > /dev/null
+
+    print_separator
+    terraform init
+    print_separator
+
+    log "Planning Terraform changes..." 5
+    print_separator
+    terraform plan --var-file=testing.tfvars
+    print_separator
+
+    log "Applying Terraform changes..." 5
+    print_separator
+    terraform apply --var-file=testing.tfvars -auto-approve
+    print_separator
+
+    log "Terraform deployment completed successfully" 2
+    popd > /dev/null
+}
+
+###############################
+# Cleanup Functions
+###############################
+
+cleanup_tfvars() {
+    log "Cleaning up testing.tfvars files..." 6
+    rm -f "${TESTING_DIR}/testing.tfvars"
+}
+
+cleanup_terraform() {
+    if [ -d "${TESTING_DIR}/.terraform" ]; then
+        pushd "${TESTING_DIR}" > /dev/null
+
+        log "Destroying Terraform resources..." 3
+        terraform destroy --var-file=testing.tfvars -auto-approve || true
+
+        log "Cleaning up Terraform files..." 6
+        rm -rf .terraform/
+        rm -f .terraform.lock.hcl
+        rm -f terraform.tfstate
+        rm -f terraform.tfstate.backup
+        rm -rf terraform.tfstate.d/
+
+        popd > /dev/null
+    fi
+}
+
+cleanup() {
+    print_header "Cleanup"
+    log "Starting cleanup..." 5
+
+    cleanup_terraform
+    cleanup_tfvars
+
+    log "Cleanup completed successfully" 2
+}
+
+###############################
+# Main Execution
+###############################
+
+main() {
+    print_header "Test Execution"
+    log "Starting test setup..." 5
+
+    # Trap cleanup on exit
+    trap cleanup EXIT
+
+    # Validate variables
+    validate_variables
+
+    # Setup
+    setup_azure
+    create_tfvars_files
+
+    # Run unit tests first (these don't require infrastructure)
+    run_unit_tests
+
+    # Now deploy and test infrastructure
+    terraform_init_and_apply
+}
+
+# Execute main function
+main
\ No newline at end of file
diff --git a/infra/modules/providers/azure/resource-group/testing/main.tf b/infra/modules/providers/azure/resource-group/testing/main.tf
index fdebf47e0..ad2163dc4 100644
--- a/infra/modules/providers/azure/resource-group/testing/main.tf
+++ b/infra/modules/providers/azure/resource-group/testing/main.tf
@@ -12,6 +12,15 @@
 //  See the License for the specific language governing permissions and
 //  limitations under the License.
 
+terraform {
+  required_providers {
+    azurerm = {
+      source  = "hashicorp/azurerm"
+      version = "=3.90.0"
+    }
+  }
+}
+
 provider "azurerm" {
   features {}
 }
@@ -19,10 +28,32 @@ provider "azurerm" {
 module "resource_group" {
   source = "../"
 
-  name     = "osdu-module"
-  location = "eastus2"
+  name     = var.name
+  location = var.location
 
   resource_tags = {
     environment = "test-environment"
   }
+}
+
+variable "name" {
+  type        = string
+  description = "The name of the resource group"
+}
+
+variable "location" {
+  type        = string
+  description = "The location of the resource group"
+}
+
+output "resource_group_name" {
+  value = module.resource_group.name
+}
+
+output "resource_group_location" {
+  value = module.resource_group.location
+}
+
+output "resource_group_id" {
+  value = module.resource_group.id
 }
\ No newline at end of file
diff --git a/infra/modules/providers/azure/resource-group/testing/unit_test.go b/infra/modules/providers/azure/resource-group/testing/unit_test.go
index b554f7dc6..5d3603365 100644
--- a/infra/modules/providers/azure/resource-group/testing/unit_test.go
+++ b/infra/modules/providers/azure/resource-group/testing/unit_test.go
@@ -30,6 +30,10 @@ var count = 2
 var tfOptions = &terraform.Options{
 	TerraformDir: "./",
 	Upgrade:      true,
+	Vars: map[string]interface{}{
+		"name":     name,
+		"location": location,
+	},
 }
 
 func asMap(t *testing.T, jsonString string) map[string]interface{} {
@@ -41,7 +45,6 @@ func asMap(t *testing.T, jsonString string) map[string]interface{} {
 }
 
 func TestTemplate(t *testing.T) {
-
 	expectedResult := asMap(t, `{
 		"location": "`+location+`"
 	}`)
diff --git a/infra/modules/providers/azure/storage-account/main.tf b/infra/modules/providers/azure/storage-account/main.tf
index 5f1bb1eb2..81583f4b5 100644
--- a/infra/modules/providers/azure/storage-account/main.tf
+++ b/infra/modules/providers/azure/storage-account/main.tf
@@ -12,6 +12,20 @@
 //  See the License for the specific language governing permissions and
 //  limitations under the License.
 
+
+terraform {
+  required_providers {
+    azurerm = {
+      source  = "hashicorp/azurerm"
+      version = "=3.90.0"
+    }
+  }
+}
+
+provider "azurerm" {
+  features {}
+}
+
 data "azurerm_resource_group" "main" {
   name = var.resource_group_name
 }
diff --git a/infra/modules/providers/azure/storage-account/test.sh b/infra/modules/providers/azure/storage-account/test.sh
new file mode 100755
index 000000000..a25a756bc
--- /dev/null
+++ b/infra/modules/providers/azure/storage-account/test.sh
@@ -0,0 +1,266 @@
+#!/bin/bash
+
+# Exit on error
+set -e
+
+###############################
+# Script Path Configuration
+###############################
+SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
+TESTING_DIR="${SCRIPT_DIR}/testing"
+UNIT_TEST_DIR="${SCRIPT_DIR}/tests/unit"
+INTEGRATION_TEST_DIR="${SCRIPT_DIR}/tests/integration"
+
+###############################
+# Required Environment Variables
+###############################
+# ARM_SUBSCRIPTION_ID should be set in the environment
+# Example: export ARM_SUBSCRIPTION_ID="00000000-0000-0000-0000-000000000000"
+
+###############################
+# Optional Variables
+###############################
+# These can be overridden by setting them before running the script
+RESOURCE_GROUP_NAME=${RESOURCE_GROUP_NAME:-"osdu-test"}
+LOCATION=${LOCATION:-"eastus2"}
+STORAGE_ACCOUNT_NAME=${STORAGE_ACCOUNT_NAME:-""}  # Will be auto-generated if not provided
+
+###############################
+# Utility Functions
+###############################
+
+print_header() {
+    local title="$1"
+    printf "\n"
+    tput setaf 3
+    echo "=================================================================="
+    tput setaf 6
+    echo "                         ${title}                                 "
+    tput setaf 3
+    echo "=================================================================="
+    tput sgr0
+    printf "\n"
+}
+
+log() {
+    local _msg="$1"
+    local _color="${2:-5}"
+
+    if [[ -t 1 ]]; then
+        tput setaf $_color
+        echo "$_msg"
+        tput sgr0
+    else
+        echo "$_msg"
+    fi
+}
+
+print_separator() {
+    if [[ -t 1 ]]; then
+        echo ""
+        tput setaf 4  # Blue color for sub-headers
+        echo "▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼"
+        tput sgr0
+        echo ""
+    else
+        echo "\n▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼\n"
+    fi
+}
+
+###############################
+# Variable Validation
+###############################
+
+validate_variables() {
+    print_header "Variable Validation"
+
+    if [ -z "$ARM_SUBSCRIPTION_ID" ]; then
+        log "Error: ARM_SUBSCRIPTION_ID environment variable is not set" 1
+        log "Usage: export ARM_SUBSCRIPTION_ID='00000000-0000-0000-0000-000000000000' && $0" 1
+        exit 1
+    fi
+
+    # Generate unique storage account name if not provided
+    if [ -z "$STORAGE_ACCOUNT_NAME" ]; then
+        UNIQUE=$(openssl rand -base64 20 | tr -dc 'a-z' | head -c 20; echo)
+        STORAGE_ACCOUNT_NAME="${UNIQUE}sa"
+    fi
+
+    log "Using Subscription: $ARM_SUBSCRIPTION_ID" 6
+    log "Using Resource Group: $RESOURCE_GROUP_NAME" 6
+    log "Using Location: $LOCATION" 6
+    log "Using Storage Account: $STORAGE_ACCOUNT_NAME" 6
+}
+
+###############################
+# Setup Functions
+###############################
+
+setup_azure() {
+    print_header "Azure Setup"
+
+    # Only verify subscription access
+    log "Verifying Azure subscription..." 5
+    az account show --subscription "$ARM_SUBSCRIPTION_ID" || {
+        log "Error: Could not access subscription $ARM_SUBSCRIPTION_ID" 1
+        exit 1
+    }
+    log "Azure subscription verified successfully" 2
+
+    # Create resource group if it doesn't exist
+    log "Creating resource group if it doesn't exist..." 5
+    az group create --name "$RESOURCE_GROUP_NAME" --location "$LOCATION" --subscription "$ARM_SUBSCRIPTION_ID" || {
+        log "Error: Could not create resource group $RESOURCE_GROUP_NAME" 1
+        exit 1
+    }
+    log "Resource group ready" 2
+}
+
+create_tfvars_files() {
+    print_header "Terraform Configuration"
+
+    log "Creating testing.tfvars files..." 5
+    for dir in "${SCRIPT_DIR}" "${UNIT_TEST_DIR}" "${INTEGRATION_TEST_DIR}" "${TESTING_DIR}"; do
+        mkdir -p "$dir"
+        cat > "${dir}/testing.tfvars" << EOF
+name = "$STORAGE_ACCOUNT_NAME"
+resource_group_name = "$RESOURCE_GROUP_NAME"
+EOF
+    done
+    log "Configuration files created successfully" 2
+}
+
+###############################
+# Testing Functions
+###############################
+
+run_basic_unit_tests() {
+    print_header "Basic Unit Tests"
+    log "Running basic unit tests..." 5
+    echo ""
+    pushd "${TESTING_DIR}" > /dev/null
+    go test -v
+    popd > /dev/null
+    echo ""
+    log "Basic unit tests completed" 2
+}
+
+run_extended_unit_tests() {
+    print_header "Extended Unit Tests"
+    log "Running extended unit tests..." 5
+    echo ""
+    pushd "${SCRIPT_DIR}/tests" > /dev/null
+    go test -v ./unit/...
+    popd > /dev/null
+    echo ""
+    log "Extended unit tests completed" 2
+}
+
+run_integration_tests() {
+    print_header "Integration Tests"
+    log "Running integration tests..." 5
+    echo ""
+    pushd "${SCRIPT_DIR}/tests" > /dev/null
+    go test -v ./integration/...
+    popd > /dev/null
+    echo ""
+    log "Integration tests completed" 2
+}
+
+###############################
+# Terraform Functions
+###############################
+
+terraform_init_and_apply() {
+    print_header "Terraform Deployment"
+
+    log "Initializing Terraform..." 5
+    pushd "${TESTING_DIR}" > /dev/null
+
+    print_separator
+    terraform init
+    print_separator
+
+    log "Planning Terraform changes..." 5
+    print_separator
+    terraform plan --var-file=testing.tfvars
+    print_separator
+
+    log "Applying Terraform changes..." 5
+    print_separator
+    terraform apply --var-file=testing.tfvars -auto-approve
+    print_separator
+
+    log "Terraform deployment completed successfully" 2
+    popd > /dev/null
+}
+
+###############################
+# Cleanup Functions
+###############################
+
+cleanup_tfvars() {
+    log "Cleaning up testing.tfvars files..." 6
+    rm -f "${SCRIPT_DIR}/testing.tfvars"
+    rm -f "${UNIT_TEST_DIR}/testing.tfvars"
+    rm -f "${INTEGRATION_TEST_DIR}/testing.tfvars"
+    rm -f "${TESTING_DIR}/testing.tfvars"
+}
+
+cleanup_terraform() {
+    if [ -d "${TESTING_DIR}/.terraform" ]; then
+        pushd "${TESTING_DIR}" > /dev/null
+
+        log "Destroying Terraform resources..." 3
+        terraform destroy --var-file=testing.tfvars -auto-approve || true
+
+        log "Cleaning up Terraform files..." 6
+        rm -rf .terraform/
+        rm -f .terraform.lock.hcl
+        rm -f terraform.tfstate
+        rm -f terraform.tfstate.backup
+        rm -rf terraform.tfstate.d/
+
+        popd > /dev/null
+    fi
+}
+
+cleanup() {
+    print_header "Cleanup"
+    log "Starting cleanup..." 5
+
+    cleanup_terraform
+    cleanup_tfvars
+
+    log "Cleanup completed successfully" 2
+}
+
+###############################
+# Main Execution
+###############################
+
+main() {
+    print_header "Test Execution"
+    log "Starting test setup..." 5
+
+    # Trap cleanup on exit
+    trap cleanup EXIT
+
+    # Validate variables
+    validate_variables
+
+    # Setup
+    setup_azure
+    create_tfvars_files
+
+    # Run all tests
+    run_basic_unit_tests      # Simple tests in testing/
+    run_extended_unit_tests   # More complex tests in tests/unit/
+    run_integration_tests     # Integration tests in tests/integration/
+
+    # Now deploy and test infrastructure
+    terraform_init_and_apply
+}
+
+# Execute main function
+main
\ No newline at end of file
diff --git a/infra/modules/providers/azure/storage-account/testing/main.tf b/infra/modules/providers/azure/storage-account/testing/main.tf
index ab8288f0f..9d280850c 100644
--- a/infra/modules/providers/azure/storage-account/testing/main.tf
+++ b/infra/modules/providers/azure/storage-account/testing/main.tf
@@ -1,32 +1,60 @@
-provider "azurerm" {
-  features {}
+terraform {
+  required_providers {
+    azurerm = {
+      source  = "hashicorp/azurerm"
+      version = "=3.90.0"
+    }
+  }
 }
 
-module "resource_group" {
-  source = "../../resource-group"
-
-  name     = "osdu-module"
-  location = "eastus2"
+provider "azurerm" {
+  features {}
 }
 
+# Create the storage account
 module "storage_account" {
-  source     = "../"
-  depends_on = [module.resource_group]
+  source = "../"
 
-  resource_group_name = module.resource_group.name
-  name                = substr("osdumodule${module.resource_group.random}", 0, 23)
+  resource_group_name = var.resource_group_name
+  name                = var.name
+  location            = var.location
   replication_type    = "GZRS"
-  container_names = [
-    "osdu-container"
-  ]
-  share_names = [
-    "osdu-share"
-  ]
-  queue_names = [
-    "osdu-queue"
-  ]
+  container_names     = ["osdu-container", "osdu-container-2"]
+  share_names         = ["osdu-share", "osdu-share-2"]
+  queue_names         = ["osdu-queue", "osdu-queue-2"]
 
   resource_tags = {
     environment = "test-environment"
   }
 }
+
+# Variables
+variable "name" {
+  type        = string
+  description = "The name of the storage account"
+}
+
+variable "resource_group_name" {
+  type        = string
+  description = "The name of the resource group"
+}
+
+variable "location" {
+  type        = string
+  description = "The location of the storage account"
+  default     = "eastus2"
+}
+
+# Outputs
+output "storage_account_id" {
+  value = module.storage_account.id
+}
+
+output "storage_account_name" {
+  value = module.storage_account.name
+}
+
+output "storage_account_primary_access_key" {
+  value     = module.storage_account.primary_access_key
+  sensitive = true
+}
diff --git a/infra/modules/providers/azure/storage-account/testing/unit_test.go b/infra/modules/providers/azure/storage-account/testing/unit_test.go
index b0bd22bc4..b0342c75f 100644
--- a/infra/modules/providers/azure/storage-account/testing/unit_test.go
+++ b/infra/modules/providers/azure/storage-account/testing/unit_test.go
@@ -10,11 +10,12 @@ import (
 )
 
 var name = "storage-"
-var count = 7
+var count = 7  // Just the storage account resources
 
 var tfOptions = &terraform.Options{
 	TerraformDir: "./",
 	Upgrade:      true,
+	VarFiles:     []string{"testing.tfvars"},
 }
 
 func asMap(t *testing.T, jsonString string) map[string]interface{} {
@@ -26,6 +27,14 @@ func asMap(t *testing.T, jsonString string) map[string]interface{} {
 }
 
 func TestTemplate(t *testing.T) {
+	uniqueID := random.UniqueId()
+	workspace := name + uniqueID
+
+	// Use the same resource group name that the test script creates
+	tfOptions.Vars = map[string]interface{}{
+		"name":                workspace + "-sa",
+		"resource_group_name": "osdu-test",  // Match the test script's resource group
+	}
 
 	expectedResult := asMap(t, `{
 		"account_kind" : "StorageV2",
@@ -50,14 +59,14 @@ func TestTemplate(t *testing.T) {
 	testFixture := infratests.UnitTestFixture{
 		GoTest:                t,
 		TfOptions:             tfOptions,
-		Workspace:             name + random.UniqueId(),
+		Workspace:             workspace,
 		PlanAssertions:        nil,
 		ExpectedResourceCount: count,
 		ExpectedResourceAttributeValues: infratests.ResourceDescription{
-			"module.storage_account.azurerm_storage_account.main":      expectedResult,
+			"module.storage_account.azurerm_storage_account.main": expectedResult,
 			"module.storage_account.azurerm_storage_container.main[0]": expectedContainer,
-			"module.storage_account.azurerm_storage_share.main[0]":     expectedShare,
-			"module.storage_account.azurerm_storage_queue.main[0]":     expectedQueue,
+			"module.storage_account.azurerm_storage_share.main[0]": expectedShare,
+			"module.storage_account.azurerm_storage_queue.main[0]": expectedQueue,
 		},
 	}
 
diff --git a/infra/modules/providers/azure/storage-account/tests/tf_options.go b/infra/modules/providers/azure/storage-account/tests/tf_options.go
index 26a5690bf..fe605376b 100644
--- a/infra/modules/providers/azure/storage-account/tests/tf_options.go
+++ b/infra/modules/providers/azure/storage-account/tests/tf_options.go
@@ -31,12 +31,17 @@ var ResourceGroupName = os.Getenv("RESOURCE_GROUP_NAME")
 
 // StorageTFOptions common terraform options used for unit and integration testing
 var StorageTFOptions = &terraform.Options{
-	TerraformDir: "../../",
+	TerraformDir: "../../testing",
 	Vars: map[string]interface{}{
 		"resource_group_name": ResourceGroupName,
 		"name":                StorageAccount,
-		"container_names": []interface{}{
-			ContainerName,
+		"replication_type":    "GZRS",
+		"location":            "eastus2",
+		"container_names":     []interface{}{ContainerName},
+		"share_names":         []interface{}{"osdu-share", "osdu-share-2"},
+		"queue_names":         []interface{}{"osdu-queue", "osdu-queue-2"},
+		"resource_tags": map[string]interface{}{
+			"environment": "test-environment",
 		},
 	},
 }
diff --git a/infra/modules/providers/azure/storage-account/tests/unit/storage_deployment_unit_test.go b/infra/modules/providers/azure/storage-account/tests/unit/storage_deployment_unit_test.go
index 7d0d0bcb4..87d4f3dbd 100644
--- a/infra/modules/providers/azure/storage-account/tests/unit/storage_deployment_unit_test.go
+++ b/infra/modules/providers/azure/storage-account/tests/unit/storage_deployment_unit_test.go
@@ -33,26 +33,20 @@ func asMap(t *testing.T, jsonString string) map[string]interface{} {
 }
 
 func TestStorageDeployment_Unit(t *testing.T) {
-
 	expectedResult := asMap(t, `{
-    "account_kind": "StorageV2",
-    "account_replication_type": "LRS",
-    "account_tier": "Standard",
-    "account_encryption_source": "Microsoft.Storage"
-  }`)
-
-	expectedContainerResult := asMap(t, `{
-	  "container_access_type": "private",
-	  "name": "`+tests.ContainerName+`"
+		"account_kind": "StorageV2",
+		"account_replication_type": "GZRS",
+		"account_tier": "Standard"
 	}`)
 
 	testFixture := infratests.UnitTestFixture{
 		GoTest:                t,
 		TfOptions:             tests.StorageTFOptions,
+		Workspace:             "default-unit-testing",
+		PlanAssertions:        nil,
 		ExpectedResourceCount: resourceCount,
 		ExpectedResourceAttributeValues: infratests.ResourceDescription{
-			"azurerm_storage_account.main":      expectedResult,
-			"azurerm_storage_container.main[0]": expectedContainerResult,
+			"azurerm_storage_account.main": expectedResult,
 		},
 	}
 
diff --git a/infra/modules/providers/azure/storage-account/variables.tf b/infra/modules/providers/azure/storage-account/variables.tf
index e165994f5..f8e3d1f63 100755
--- a/infra/modules/providers/azure/storage-account/variables.tf
+++ b/infra/modules/providers/azure/storage-account/variables.tf
@@ -15,7 +15,7 @@
 # Naming Items (required)
 
 variable "name" {
-  description = "The name of the storage account service."
+  description = "The name of the storage account"
   type        = string
 }
 
@@ -37,10 +37,15 @@ variable "queue_names" {
 }
 
 variable "resource_group_name" {
-  description = "The name of the resource group."
+  description = "The name of the resource group"
   type        = string
 }
 
+variable "location" {
+  type        = string
+  description = "The location/region where the storage account is created"
+}
+
 
 # Tier Items (optional)
 
-- 
GitLab


From 06907bb979c6992af474e3ccc52eb5a0c5c85260 Mon Sep 17 00:00:00 2001
From: danielscholl <dascholl@microsoft.com>
Date: Sun, 2 Feb 2025 13:05:42 -0600
Subject: [PATCH 02/15] Functioning Storage

---
 .../providers/azure/storage-account/test.sh   | 119 ++++++++++++++++--
 .../azure/storage-account/testing/main.tf     |  38 ++++++
 .../storage-account/testing/unit_test.go      |  54 +++++---
 .../tests/integration/storage_test.go         |   6 +-
 .../azure/storage-account/tests/tf_options.go |  21 ++--
 5 files changed, 199 insertions(+), 39 deletions(-)

diff --git a/infra/modules/providers/azure/storage-account/test.sh b/infra/modules/providers/azure/storage-account/test.sh
index a25a756bc..30755b574 100755
--- a/infra/modules/providers/azure/storage-account/test.sh
+++ b/infra/modules/providers/azure/storage-account/test.sh
@@ -21,14 +21,79 @@ INTEGRATION_TEST_DIR="${SCRIPT_DIR}/tests/integration"
 # Optional Variables
 ###############################
 # These can be overridden by setting them before running the script
-RESOURCE_GROUP_NAME=${RESOURCE_GROUP_NAME:-"osdu-test"}
-LOCATION=${LOCATION:-"eastus2"}
+RESOURCE_GROUP_PREFIX=${RESOURCE_GROUP_PREFIX:-"terraform-test"}
+DEFAULT_LOCATION="eastus2"
 STORAGE_ACCOUNT_NAME=${STORAGE_ACCOUNT_NAME:-""}  # Will be auto-generated if not provided
 
+###############################
+# Help Documentation
+###############################
+
+print_help() {
+    cat << EOF
+Storage Account Module Test Script
+================================
+
+This script runs unit tests and integration tests for the Azure Storage Account module.
+
+Required Environment Variables:
+-----------------------------
+ARM_SUBSCRIPTION_ID    Azure subscription ID to use for testing
+
+Usage:
+------
+$0 [resource_group_name] [location]
+$0 -h | --help
+
+Arguments:
+----------
+resource_group_name    (Optional) Name of resource group to create.
+                      Default: Auto-generated using prefix "terraform-test"
+
+location              (Optional) Azure region to deploy resources.
+                      Default: eastus2
+
+Options:
+--------
+-h, --help           Show this help message
+
+Examples:
+---------
+# Run with auto-generated names in default location
+$0
+
+# Run with specific resource group name
+$0 my-test-rg
+
+# Run with specific resource group and location
+$0 my-test-rg westus2
+
+Notes:
+------
+- If not specified, a unique resource group name will be generated
+- If not specified, a unique storage account name will be generated
+- All resources are automatically cleaned up after the test
+- The script uses the default Azure CLI subscription if not specified
+EOF
+}
+
 ###############################
 # Utility Functions
 ###############################
 
+generate_unique_name() {
+    local prefix="$1"
+    local suffix="$2"
+    local unique=$(openssl rand -base64 20 | tr -dc 'a-z0-9' | head -c 8)
+
+    if [ -n "$prefix" ]; then
+        echo "${prefix}-${unique}${suffix}"
+    else
+        # For storage accounts, create a name without dashes
+        echo "tftest${unique}${suffix}"
+    fi
+}
+
 print_header() {
     local title="$1"
     printf "\n"
@@ -80,11 +145,30 @@ validate_variables() {
         exit 1
     fi
 
+    # Always generate a new resource group name unless explicitly passed as argument
+    if [ -z "$1" ]; then
+        RESOURCE_GROUP_NAME=$(generate_unique_name "$RESOURCE_GROUP_PREFIX" "")
+    else
+        RESOURCE_GROUP_NAME="$1"
+    fi
+    # Export for Go tests
+    export RESOURCE_GROUP_NAME
+
+    # Use default location unless explicitly passed as second argument
+    if [ -z "$2" ]; then
+        LOCATION="$DEFAULT_LOCATION"
+    else
+        LOCATION="$2"
+    fi
+    # Export for Go tests
+    export LOCATION
+
     # Generate unique storage account name if not provided
     if [ -z "$STORAGE_ACCOUNT_NAME" ]; then
-        UNIQUE=$(openssl rand -base64 20 | tr -dc 'a-z' | head -c 20; echo)
-        STORAGE_ACCOUNT_NAME="${UNIQUE}sa"
+        STORAGE_ACCOUNT_NAME=$(generate_unique_name "" "sa")
     fi
+    # Export for Go tests
+    export STORAGE_ACCOUNT_NAME
 
     log "Using Subscription: $ARM_SUBSCRIPTION_ID" 6
     log "Using Resource Group: $RESOURCE_GROUP_NAME" 6
@@ -223,6 +307,11 @@ cleanup_terraform() {
 
         popd > /dev/null
     fi
+
+    log "Deleting resource group..." 3
+    az group delete --name "$RESOURCE_GROUP_NAME" --subscription "$ARM_SUBSCRIPTION_ID" --yes || {
+        log "Warning: Could not delete resource group $RESOURCE_GROUP_NAME" 3
+    }
 }
 
 cleanup() {
@@ -247,20 +336,30 @@ main() {
     trap cleanup EXIT
 
     # Validate variables
-    validate_variables
+    validate_variables "$1" "$2"
 
     # Setup
     setup_azure
     create_tfvars_files
 
-    # Run all tests
+    # Run unit tests first
     run_basic_unit_tests      # Simple tests in testing/
     run_extended_unit_tests   # More complex tests in tests/unit/
-    run_integration_tests     # Integration tests in tests/integration/
 
-    # Now deploy and test infrastructure
-    terraform_init_and_apply
+    # Now deploy infrastructure
+    terraform_init_and_apply  # Deploy infrastructure
+
+    # Run integration tests against deployed infrastructure
+    run_integration_tests     # Integration tests in tests/integration/
 }
 
+# Check for help flag
+case "$1" in
+    -h|--help)
+        print_help
+        exit 0
+        ;;
+esac
+
 # Execute main function
-main
\ No newline at end of file
+main "$@"
\ No newline at end of file
diff --git a/infra/modules/providers/azure/storage-account/testing/main.tf b/infra/modules/providers/azure/storage-account/testing/main.tf
index 9d280850c..1c5521735 100644
--- a/infra/modules/providers/azure/storage-account/testing/main.tf
+++ b/infra/modules/providers/azure/storage-account/testing/main.tf
@@ -58,3 +58,41 @@ output "storage_account_primary_access_key" {
   value     = module.storage_account.primary_access_key
   sensitive = true
 }
+
+output "containers" {
+  value = module.storage_account.containers
+}
+
+output "queues" {
+  value = module.storage_account.queues
+}
+
+output "shares" {
+  value = module.storage_account.shares
+}
+
+output "resource_group_name" {
+  value = module.storage_account.resource_group_name
+}
+
+output "tenant_id" {
+  value = module.storage_account.tenant_id
+}
+
+output "managed_identities_id" {
+  value = module.storage_account.managed_identities_id
+}
+
+output "properties" {
+  value     = module.storage_account.properties
+  sensitive = true
+}
+
+output "primary_blob_endpoint" {
+  value     = module.storage_account.primary_blob_endpoint
+  sensitive = true
+}
+
+output "primary_queue_endpoint" {
+  value = module.storage_account.primary_queue_endpoint
+}
diff --git a/infra/modules/providers/azure/storage-account/testing/unit_test.go b/infra/modules/providers/azure/storage-account/testing/unit_test.go
index b0342c75f..75e585674 100644
--- a/infra/modules/providers/azure/storage-account/testing/unit_test.go
+++ b/infra/modules/providers/azure/storage-account/testing/unit_test.go
@@ -2,6 +2,7 @@ package test
 
 import (
 	"encoding/json"
+	"os"
 	"testing"
 
 	"github.com/gruntwork-io/terratest/modules/random"
@@ -10,13 +11,7 @@ import (
 )
 
 var name = "storage-"
-var count = 7  // Just the storage account resources
-
-var tfOptions = &terraform.Options{
-	TerraformDir: "./",
-	Upgrade:      true,
-	VarFiles:     []string{"testing.tfvars"},
-}
+var count = 7
 
 func asMap(t *testing.T, jsonString string) map[string]interface{} {
 	var theMap map[string]interface{}
@@ -27,33 +22,54 @@ func asMap(t *testing.T, jsonString string) map[string]interface{} {
 }
 
 func TestTemplate(t *testing.T) {
+	// Get location from environment variable or use default
+	location := os.Getenv("LOCATION")
+	if location == "" {
+		location = "eastus2"
+	}
+
+	// Get resource group name from environment or generate it
+	resourceGroupName := os.Getenv("RESOURCE_GROUP_NAME")
+	if resourceGroupName == "" {
+		uniqueID := random.UniqueId()
+		resourceGroupName = "terraform-test-" + uniqueID
+	}
+
+	// Generate unique names for resources
 	uniqueID := random.UniqueId()
 	workspace := name + uniqueID
+	storageAcctName := "tftest" + uniqueID + "sa"
 
-	// Use the same resource group name that the test script creates
-	tfOptions.Vars = map[string]interface{}{
-		"name":                workspace + "-sa",
-		"resource_group_name": "osdu-test",  // Match the test script's resource group
+	tfOptions := &terraform.Options{
+		TerraformDir: "./",
+		Upgrade:      true,
+		Vars: map[string]interface{}{
+			"name":                storageAcctName,
+			"resource_group_name": resourceGroupName,
+			"location":           location,
+		},
 	}
 
 	expectedResult := asMap(t, `{
-		"account_kind" : "StorageV2",
+		"account_kind": "StorageV2",
 		"account_replication_type": "GZRS",
-		"account_tier": "Standard"
+		"account_tier": "Standard",
+		"enable_https_traffic_only": true,
+		"min_tls_version": "TLS1_2"
 	}`)
 
 	expectedContainer := asMap(t, `{
-		"name" : "osdu-container",
+		"name": "osdu-container",
 		"container_access_type": "private"
 	}`)
 
 	expectedShare := asMap(t, `{
-		"name" : "osdu-share",
+		"name": "osdu-share",
 		"quota": 50
 	}`)
 
 	expectedQueue := asMap(t, `{
-		"name" : "osdu-queue"
+		"name": "osdu-queue"
 	}`)
 
 	testFixture := infratests.UnitTestFixture{
@@ -63,10 +79,10 @@ func TestTemplate(t *testing.T) {
 		PlanAssertions:        nil,
 		ExpectedResourceCount: count,
 		ExpectedResourceAttributeValues: infratests.ResourceDescription{
-			"module.storage_account.azurerm_storage_account.main": expectedResult,
+			"module.storage_account.azurerm_storage_account.main":      expectedResult,
 			"module.storage_account.azurerm_storage_container.main[0]": expectedContainer,
-			"module.storage_account.azurerm_storage_share.main[0]": expectedShare,
-			"module.storage_account.azurerm_storage_queue.main[0]": expectedQueue,
+			"module.storage_account.azurerm_storage_share.main[0]":     expectedShare,
+			"module.storage_account.azurerm_storage_queue.main[0]":     expectedQueue,
 		},
 	}
 
diff --git a/infra/modules/providers/azure/storage-account/tests/integration/storage_test.go b/infra/modules/providers/azure/storage-account/tests/integration/storage_test.go
index 64992406b..7147cd5a9 100644
--- a/infra/modules/providers/azure/storage-account/tests/integration/storage_test.go
+++ b/infra/modules/providers/azure/storage-account/tests/integration/storage_test.go
@@ -22,7 +22,7 @@ import (
 	"github.com/microsoft/cobalt/test-harness/infratests"
 )
 
-var outputVariableCount = 7
+var outputVariableCount = 12
 
 func TestServiceDeployment(t *testing.T) {
 	if tests.ResourceGroupName == "" {
@@ -35,10 +35,10 @@ func TestServiceDeployment(t *testing.T) {
 
 	testFixture := infratests.IntegrationTestFixture{
 		GoTest:                t,
-		TfOptions:             tests.StorageTFOptions,
+		TfOptions:             tests.StorageIntegrationTFOptions,
 		ExpectedTfOutputCount: outputVariableCount,
 		TfOutputAssertions: []infratests.TerraformOutputValidation{
-			InspectStorageAccount("name", "containers", "resource_group_name"),
+			InspectStorageAccount("storage_account_name", "containers", "resource_group_name"),
 		},
 	}
 	infratests.RunIntegrationTests(&testFixture)
diff --git a/infra/modules/providers/azure/storage-account/tests/tf_options.go b/infra/modules/providers/azure/storage-account/tests/tf_options.go
index fe605376b..44dec69fa 100644
--- a/infra/modules/providers/azure/storage-account/tests/tf_options.go
+++ b/infra/modules/providers/azure/storage-account/tests/tf_options.go
@@ -29,19 +29,26 @@ var ContainerName = os.Getenv("CONTAINER_NAME")
 // ResourceGroupName - The Resource Group Name
 var ResourceGroupName = os.Getenv("RESOURCE_GROUP_NAME")
 
-// StorageTFOptions common terraform options used for unit and integration testing
+// StorageTFOptions common terraform options used for unit testing
 var StorageTFOptions = &terraform.Options{
-	TerraformDir: "../../testing",
+	TerraformDir: "../../",  // Point to module directory for unit tests
+	Vars: map[string]interface{}{
+		"resource_group_name": ResourceGroupName,
+		"name":                StorageAccount,
+		"replication_type":    "GZRS",
+		"location":            "eastus2",
+		"container_names":     []interface{}{ContainerName},
+	},
+}
+
+// StorageIntegrationTFOptions terraform options used for integration testing
+var StorageIntegrationTFOptions = &terraform.Options{
+	TerraformDir: "../../testing",  // Point to testing directory for integration tests
 	Vars: map[string]interface{}{
 		"resource_group_name": ResourceGroupName,
 		"name":                StorageAccount,
 		"replication_type":    "GZRS",
 		"location":            "eastus2",
 		"container_names":     []interface{}{ContainerName},
-		"share_names":         []interface{}{"osdu-share", "osdu-share-2"},
-		"queue_names":         []interface{}{"osdu-queue", "osdu-queue-2"},
-		"resource_tags": map[string]interface{}{
-			"environment": "test-environment",
-		},
 	},
 }
-- 
GitLab


From 0698c57b83435e000d1240ae93f1766980bbc2bb Mon Sep 17 00:00:00 2001
From: danielscholl <dascholl@microsoft.com>
Date: Sun, 2 Feb 2025 13:14:55 -0600
Subject: [PATCH 03/15] Script cleanup

---
 .../providers/azure/storage-account/test.sh   | 189 +++++++++---------
 1 file changed, 97 insertions(+), 92 deletions(-)

diff --git a/infra/modules/providers/azure/storage-account/test.sh b/infra/modules/providers/azure/storage-account/test.sh
index 30755b574..a8601ca80 100755
--- a/infra/modules/providers/azure/storage-account/test.sh
+++ b/infra/modules/providers/azure/storage-account/test.sh
@@ -14,8 +14,7 @@ INTEGRATION_TEST_DIR="${SCRIPT_DIR}/tests/integration"
 ###############################
 # Required Environment Variables
 ###############################
-# ARM_SUBSCRIPTION_ID should be set in the environment
-# Example: export ARM_SUBSCRIPTION_ID="00000000-0000-0000-0000-000000000000"
+: "${ARM_SUBSCRIPTION_ID:?'ARM_SUBSCRIPTION_ID environment variable is required'}"
 
 ###############################
 # Optional Variables
@@ -82,28 +81,37 @@ EOF
 ###############################
 
 generate_unique_name() {
-    local prefix="$1"
-    local suffix="$2"
-    local unique=$(openssl rand -base64 20 | tr -dc 'a-z0-9' | head -c 8)
+    local prefix="${1:-}"
+    local suffix="${2:-}"
+    local unique
 
-    if [ -n "$prefix" ]; then
-        echo "${prefix}-${unique}${suffix}"
+    # More portable way to generate random string
+    if command -v openssl >/dev/null 2>&1; then
+        unique=$(openssl rand -hex 4 | tr '[:upper:]' '[:lower:]')
     else
-        # For storage accounts, create a name without dashes
-        echo "tftest${unique}${suffix}"
+        # Fallback to built-in $RANDOM if openssl is not available
+        unique=$(printf "%08x" $((RANDOM + RANDOM + RANDOM + RANDOM)))
     fi
+
+    [[ -n "$prefix" ]] && echo "${prefix}-${unique}${suffix}" || echo "tftest${unique}${suffix}"
 }
 
 print_header() {
     local title="$1"
     printf "\n"
-    tput setaf 3
-    echo "=================================================================="
-    tput setaf 6
-    echo "                         ${title}                                 "
-    tput setaf 3
-    echo "=================================================================="
-    tput sgr0
+    if [ -t 1 ] && command -v tput >/dev/null 2>&1; then
+        tput setaf 3 2>/dev/null || true
+        printf "%s\n" "=================================================================="
+        tput setaf 6 2>/dev/null || true
+        printf "%s\n" "                         ${title}                                 "
+        tput setaf 3 2>/dev/null || true
+        printf "%s\n" "=================================================================="
+        tput sgr0 2>/dev/null || true
+    else
+        printf "%s\n" "=================================================================="
+        printf "%s\n" "                         ${title}                                 "
+        printf "%s\n" "=================================================================="
+    fi
     printf "\n"
 }
 
@@ -111,64 +119,59 @@ log() {
     local _msg="$1"
     local _color="${2:-5}"
 
-    if [[ -t 1 ]]; then
-        tput setaf $_color
-        echo "$_msg"
-        tput sgr0
+    if [ -t 1 ] && command -v tput >/dev/null 2>&1; then
+        tput setaf "$_color" 2>/dev/null || true
+        printf "%s\n" "$_msg"
+        tput sgr0 2>/dev/null || true
     else
-        echo "$_msg"
+        printf "%s\n" "$_msg"
     fi
 }
 
 print_separator() {
-    if [[ -t 1 ]]; then
-        echo ""
-        tput setaf 4  # Blue color for sub-headers
-        echo "▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼"
-        tput sgr0
-        echo ""
+    printf "\n"
+    if [ -t 1 ] && command -v tput >/dev/null 2>&1; then
+        tput setaf 4 2>/dev/null || true
+        printf "%s\n" "▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼"
+        tput sgr0 2>/dev/null || true
     else
-        echo "\n▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼\n"
+        printf "%s\n" "=================================================="
     fi
+    printf "\n"
 }
 
 ###############################
-# Variable Validation
+# Configuration Setup
 ###############################
 
-validate_variables() {
-    print_header "Variable Validation"
-
-    if [ -z "$ARM_SUBSCRIPTION_ID" ]; then
-        log "Error: ARM_SUBSCRIPTION_ID environment variable is not set" 1
-        log "Usage: export ARM_SUBSCRIPTION_ID='00000000-0000-0000-0000-000000000000' && $0" 1
-        exit 1
-    fi
+setup_configuration() {
+    # Set location from args or default
+    LOCATION=${2:-$DEFAULT_LOCATION}
 
-    # Always generate a new resource group name unless explicitly passed as argument
+    # Generate resource group name if not provided
     if [ -z "$1" ]; then
         RESOURCE_GROUP_NAME=$(generate_unique_name "$RESOURCE_GROUP_PREFIX" "")
     else
         RESOURCE_GROUP_NAME="$1"
     fi
-    # Export for Go tests
-    export RESOURCE_GROUP_NAME
 
-    # Use default location unless explicitly passed as second argument
-    if [ -z "$2" ]; then
-        LOCATION="$DEFAULT_LOCATION"
-    else
-        LOCATION="$2"
-    fi
-    # Export for Go tests
-    export LOCATION
-
-    # Generate unique storage account name if not provided
+    # Generate storage account name if not provided
     if [ -z "$STORAGE_ACCOUNT_NAME" ]; then
         STORAGE_ACCOUNT_NAME=$(generate_unique_name "" "sa")
     fi
-    # Export for Go tests
+
+    # Export variables for Go tests
+    export RESOURCE_GROUP_NAME
+    export LOCATION
     export STORAGE_ACCOUNT_NAME
+}
+
+###############################
+# Variable Validation
+###############################
+
+validate_variables() {
+    print_header "Variable Validation"
 
     log "Using Subscription: $ARM_SUBSCRIPTION_ID" 6
     log "Using Resource Group: $RESOURCE_GROUP_NAME" 6
@@ -183,7 +186,6 @@ validate_variables() {
 setup_azure() {
     print_header "Azure Setup"
 
-    # Only verify subscription access
     log "Verifying Azure subscription..." 5
     az account show --subscription "$ARM_SUBSCRIPTION_ID" || {
         log "Error: Could not access subscription $ARM_SUBSCRIPTION_ID" 1
@@ -191,9 +193,12 @@ setup_azure() {
     }
     log "Azure subscription verified successfully" 2
 
-    # Create resource group if it doesn't exist
-    log "Creating resource group if it doesn't exist..." 5
-    az group create --name "$RESOURCE_GROUP_NAME" --location "$LOCATION" --subscription "$ARM_SUBSCRIPTION_ID" || {
+    log "Creating resource group..." 5
+    az group create \
+        --name "$RESOURCE_GROUP_NAME" \
+        --location "$LOCATION" \
+        --subscription "$ARM_SUBSCRIPTION_ID" \
+        --output json || {
         log "Error: Could not create resource group $RESOURCE_GROUP_NAME" 1
         exit 1
     }
@@ -203,13 +208,11 @@ setup_azure() {
 create_tfvars_files() {
     print_header "Terraform Configuration"
 
+    local tfvars_content="name = \"$STORAGE_ACCOUNT_NAME\"\nresource_group_name = \"$RESOURCE_GROUP_NAME\""
+
     log "Creating testing.tfvars files..." 5
-    for dir in "${SCRIPT_DIR}" "${UNIT_TEST_DIR}" "${INTEGRATION_TEST_DIR}" "${TESTING_DIR}"; do
-        mkdir -p "$dir"
-        cat > "${dir}/testing.tfvars" << EOF
-name = "$STORAGE_ACCOUNT_NAME"
-resource_group_name = "$RESOURCE_GROUP_NAME"
-EOF
+    for dir in "$SCRIPT_DIR" "$UNIT_TEST_DIR" "$INTEGRATION_TEST_DIR" "$TESTING_DIR"; do
+        [[ -d "$dir" ]] && echo -e "$tfvars_content" > "$dir/testing.tfvars"
     done
     log "Configuration files created successfully" 2
 }
@@ -218,37 +221,36 @@ EOF
 # Testing Functions
 ###############################
 
-run_basic_unit_tests() {
-    print_header "Basic Unit Tests"
-    log "Running basic unit tests..." 5
+run_test() {
+    local test_dir="$1"
+    local test_name="$2"
+
+    print_header "$test_name"
+    log "Running $test_name..." 5
     echo ""
-    pushd "${TESTING_DIR}" > /dev/null
-    go test -v
-    popd > /dev/null
+
+    pushd "$test_dir" > /dev/null || exit 1
+    if ! go test -v; then
+        log "Error: $test_name failed" 1
+        popd > /dev/null || exit 1
+        exit 1
+    fi
+    popd > /dev/null || exit 1
+
     echo ""
-    log "Basic unit tests completed" 2
+    log "$test_name completed" 2
+}
+
+run_basic_unit_tests() {
+    run_test "$TESTING_DIR" "Basic Unit Tests"
 }
 
 run_extended_unit_tests() {
-    print_header "Extended Unit Tests"
-    log "Running extended unit tests..." 5
-    echo ""
-    pushd "${SCRIPT_DIR}/tests" > /dev/null
-    go test -v ./unit/...
-    popd > /dev/null
-    echo ""
-    log "Extended unit tests completed" 2
+    run_test "$SCRIPT_DIR/tests" "Extended Unit Tests" "./unit/..."
 }
 
 run_integration_tests() {
-    print_header "Integration Tests"
-    log "Running integration tests..." 5
-    echo ""
-    pushd "${SCRIPT_DIR}/tests" > /dev/null
-    go test -v ./integration/...
-    popd > /dev/null
-    echo ""
-    log "Integration tests completed" 2
+    run_test "$SCRIPT_DIR/tests" "Integration Tests" "./integration/..."
 }
 
 ###############################
@@ -259,7 +261,7 @@ terraform_init_and_apply() {
     print_header "Terraform Deployment"
 
     log "Initializing Terraform..." 5
-    pushd "${TESTING_DIR}" > /dev/null
+    pushd "$TESTING_DIR" > /dev/null
 
     print_separator
     terraform init
@@ -285,15 +287,15 @@ terraform_init_and_apply() {
 
 cleanup_tfvars() {
     log "Cleaning up testing.tfvars files..." 6
-    rm -f "${SCRIPT_DIR}/testing.tfvars"
-    rm -f "${UNIT_TEST_DIR}/testing.tfvars"
-    rm -f "${INTEGRATION_TEST_DIR}/testing.tfvars"
-    rm -f "${TESTING_DIR}/testing.tfvars"
+    rm -f "$SCRIPT_DIR/testing.tfvars"
+    rm -f "$UNIT_TEST_DIR/testing.tfvars"
+    rm -f "$INTEGRATION_TEST_DIR/testing.tfvars"
+    rm -f "$TESTING_DIR/testing.tfvars"
 }
 
 cleanup_terraform() {
-    if [ -d "${TESTING_DIR}/.terraform" ]; then
-        pushd "${TESTING_DIR}" > /dev/null
+    if [ -d "$TESTING_DIR/.terraform" ]; then
+        pushd "$TESTING_DIR" > /dev/null
 
         log "Destroying Terraform resources..." 3
         terraform destroy --var-file=testing.tfvars -auto-approve || true
@@ -335,8 +337,11 @@ main() {
     # Trap cleanup on exit
     trap cleanup EXIT
 
+    # Setup configuration
+    setup_configuration "$@"
+
     # Validate variables
-    validate_variables "$1" "$2"
+    validate_variables
 
     # Setup
     setup_azure
-- 
GitLab


From a3102081c45fb39e7b20be2fb01cbf34c8895ae6 Mon Sep 17 00:00:00 2001
From: danielscholl <dascholl@microsoft.com>
Date: Sun, 2 Feb 2025 14:43:34 -0600
Subject: [PATCH 04/15] Implemented common pattern and test script inheritance.

---
 .../providers/azure/resource-group/test.sh    | 213 ++------
 .../azure/resource-group/testing/unit_test.go |  38 +-
 .../providers/azure/storage-account/test.sh   | 326 ++----------
 .../modules/providers/azure/test-functions.sh | 493 ++++++++++++++++++
 4 files changed, 594 insertions(+), 476 deletions(-)
 create mode 100644 infra/modules/providers/azure/test-functions.sh

diff --git a/infra/modules/providers/azure/resource-group/test.sh b/infra/modules/providers/azure/resource-group/test.sh
index f5fd6a3cf..c09a13c2b 100755
--- a/infra/modules/providers/azure/resource-group/test.sh
+++ b/infra/modules/providers/azure/resource-group/test.sh
@@ -4,215 +4,86 @@
 set -e
 
 ###############################
-# Script Path Configuration
+# Source Common Functions
 ###############################
-SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
-TESTING_DIR="${SCRIPT_DIR}/testing"
+COMMON_LIB="../test-functions.sh"
+if [ ! -f "$COMMON_LIB" ]; then
+    echo "Error: Common library not found at $COMMON_LIB"
+    exit 1
+fi
+source "$COMMON_LIB"
 
-###############################
-# Required Environment Variables
-###############################
-# ARM_SUBSCRIPTION_ID should be set in the environment
-# Example: export ARM_SUBSCRIPTION_ID="00000000-0000-0000-0000-000000000000"
-
-###############################
-# Optional Variables
-###############################
-# These can be overridden by setting them before running the script
-RESOURCE_GROUP_NAME=${RESOURCE_GROUP_NAME:-"osdu-test"}
-LOCATION=${LOCATION:-"eastus2"}
 
 ###############################
-# Utility Functions
+# Script Configuration
 ###############################
+SCRIPT_DIR=$(get_script_dir)
+setup_test_directories "$SCRIPT_DIR"
 
-print_header() {
-    local title="$1"
-    printf "\n"
-    tput setaf 3
-    echo "=================================================================="
-    tput setaf 6
-    echo "                         ${title}                                 "
-    tput setaf 3
-    echo "=================================================================="
-    tput sgr0
-    printf "\n"
-}
-
-log() {
-    local _msg="$1"
-    local _color="${2:-5}"
-
-    if [[ -t 1 ]]; then
-        tput setaf $_color
-        echo "$_msg"
-        tput sgr0
-    else
-        echo "$_msg"
-    fi
-}
-
-print_separator() {
-    if [[ -t 1 ]]; then
-        echo ""
-        tput setaf 4  # Blue color for sub-headers
-        echo "▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼"
-        tput sgr0
-        echo ""
-    else
-        echo "\n▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼\n"
-    fi
-}
 
 ###############################
-# Variable Validation
+# Required Environment Variables
 ###############################
+validate_azure_credentials
 
-validate_variables() {
-    print_header "Variable Validation"
-
-    if [ -z "$ARM_SUBSCRIPTION_ID" ]; then
-        log "Error: ARM_SUBSCRIPTION_ID environment variable is not set" 1
-        log "Usage: export ARM_SUBSCRIPTION_ID='00000000-0000-0000-0000-000000000000' && $0" 1
-        exit 1
-    fi
-    log "Using Subscription: $ARM_SUBSCRIPTION_ID" 6
-    log "Using Resource Group: $RESOURCE_GROUP_NAME" 6
-    log "Using Location: $LOCATION" 6
-}
 
 ###############################
-# Setup Functions
+# Optional Variables
 ###############################
+# These can be overridden by setting them before running the script
+RESOURCE_GROUP_PREFIX=${RESOURCE_GROUP_PREFIX:-"terraform-test"}
+DEFAULT_LOCATION="eastus2"
 
-setup_azure() {
-    print_header "Azure Setup"
-
-    # Only verify subscription access
-    log "Verifying Azure subscription..." 5
-    az account show --subscription "$ARM_SUBSCRIPTION_ID" || {
-        log "Error: Could not access subscription $ARM_SUBSCRIPTION_ID" 1
-        exit 1
-    }
-    log "Azure subscription verified successfully" 2
-}
-
-create_tfvars_files() {
-    print_header "Terraform Configuration"
-
-    log "Creating testing.tfvars files..." 5
-    mkdir -p "${TESTING_DIR}"
-    cat > "${TESTING_DIR}/testing.tfvars" << EOF
-name = "$RESOURCE_GROUP_NAME"
-location = "$LOCATION"
-EOF
-    log "Configuration files created successfully" 2
-}
 
 ###############################
-# Testing Functions
+# Help Documentation
 ###############################
-
-run_unit_tests() {
-    print_header "Unit Tests"
-    log "Running unit tests..." 5
-    echo ""
-    pushd "${TESTING_DIR}" > /dev/null
-    go test -v
-    popd > /dev/null
-    echo ""
-    log "Unit tests completed" 2
+print_help() {
+    print_common_help "Resource Group"
 }
 
-###############################
-# Terraform Functions
-###############################
-
-terraform_init_and_apply() {
-    print_header "Terraform Deployment"
-
-    log "Initializing Terraform..." 5
-    pushd "${TESTING_DIR}" > /dev/null
-
-    print_separator
-    terraform init
-    print_separator
-
-    log "Planning Terraform changes..." 5
-    print_separator
-    terraform plan --var-file=testing.tfvars
-    print_separator
-
-    log "Applying Terraform changes..." 5
-    print_separator
-    terraform apply --var-file=testing.tfvars -auto-approve
-    print_separator
-
-    log "Terraform deployment completed successfully" 2
-    popd > /dev/null
-}
 
 ###############################
-# Cleanup Functions
+# Required Module Functions
 ###############################
-
-cleanup_tfvars() {
-    log "Cleaning up testing.tfvars files..." 6
-    rm -f "${TESTING_DIR}/testing.tfvars"
+setup_configuration() {
+    # Setup base configuration
+    setup_base_configuration "$RESOURCE_GROUP_PREFIX" "$DEFAULT_LOCATION" "$@"
 }
 
-cleanup_terraform() {
-    if [ -d "${TESTING_DIR}/.terraform" ]; then
-        pushd "${TESTING_DIR}" > /dev/null
-
-        log "Destroying Terraform resources..." 3
-        terraform destroy --var-file=testing.tfvars -auto-approve || true
-
-        log "Cleaning up Terraform files..." 6
-        rm -rf .terraform/
-        rm -f .terraform.lock.hcl
-        rm -f terraform.tfstate
-        rm -f terraform.tfstate.backup
-        rm -rf terraform.tfstate.d/
-
-        popd > /dev/null
-    fi
-}
-
-cleanup() {
-    print_header "Cleanup"
-    log "Starting cleanup..." 5
-
-    cleanup_terraform
-    cleanup_tfvars
-
-    log "Cleanup completed successfully" 2
+create_tfvars_files() {
+    local tfvars_content="name = \"$RESOURCE_GROUP_NAME\"\nlocation = \"$LOCATION\""
+    create_base_tfvars_files "$tfvars_content"
 }
 
 ###############################
 # Main Execution
 ###############################
-
 main() {
-    print_header "Test Execution"
-    log "Starting test setup..." 5
-
     # Trap cleanup on exit
-    trap cleanup EXIT
+    trap 'cleanup; cleanup_resource_group "$RESOURCE_GROUP_NAME" "$ARM_SUBSCRIPTION_ID"' EXIT
+
+    # Setup configuration
+    setup_configuration "$@"
 
     # Validate variables
-    validate_variables
+    validate_base_variables
 
     # Setup
     setup_azure
     create_tfvars_files
 
-    # Run unit tests first (these don't require infrastructure)
-    run_unit_tests
-
-    # Now deploy and test infrastructure
-    terraform_init_and_apply
+    # Run all tests
+    run_standard_test_sequence
 }
 
+# Check for help flag
+case "$1" in
+    -h|--help)
+        print_help
+        exit 0
+        ;;
+esac
+
 # Execute main function
-main
\ No newline at end of file
+main "$@"
\ No newline at end of file
diff --git a/infra/modules/providers/azure/resource-group/testing/unit_test.go b/infra/modules/providers/azure/resource-group/testing/unit_test.go
index 5d3603365..a749b0048 100644
--- a/infra/modules/providers/azure/resource-group/testing/unit_test.go
+++ b/infra/modules/providers/azure/resource-group/testing/unit_test.go
@@ -16,6 +16,7 @@ package test
 
 import (
 	"encoding/json"
+	"os"
 	"testing"
 
 	"github.com/gruntwork-io/terratest/modules/random"
@@ -24,18 +25,8 @@ import (
 )
 
 var name = "resourcegroup-"
-var location = "eastus2"
 var count = 2
 
-var tfOptions = &terraform.Options{
-	TerraformDir: "./",
-	Upgrade:      true,
-	Vars: map[string]interface{}{
-		"name":     name,
-		"location": location,
-	},
-}
-
 func asMap(t *testing.T, jsonString string) map[string]interface{} {
 	var theMap map[string]interface{}
 	if err := json.Unmarshal([]byte(jsonString), &theMap); err != nil {
@@ -45,6 +36,31 @@ func asMap(t *testing.T, jsonString string) map[string]interface{} {
 }
 
 func TestTemplate(t *testing.T) {
+	t.Parallel()
+
+	// Get location from environment variable or use default
+	location := os.Getenv("LOCATION")
+	if location == "" {
+		location = "eastus2"
+	}
+
+	// Generate unique names for resources
+	uniqueID := random.UniqueId()
+	workspace := name + uniqueID
+	resourceGroupName := os.Getenv("RESOURCE_GROUP_NAME")
+	if resourceGroupName == "" {
+		resourceGroupName = "terraform-test-" + uniqueID
+	}
+
+	tfOptions := &terraform.Options{
+		TerraformDir: "./",
+		Upgrade:      true,
+		Vars: map[string]interface{}{
+			"name":     resourceGroupName,
+			"location": location,
+		},
+	}
+
 	expectedResult := asMap(t, `{
 		"location": "`+location+`"
 	}`)
@@ -52,7 +68,7 @@ func TestTemplate(t *testing.T) {
 	testFixture := infratests.UnitTestFixture{
 		GoTest:                t,
 		TfOptions:             tfOptions,
-		Workspace:             name + random.UniqueId(),
+		Workspace:             workspace,
 		PlanAssertions:        nil,
 		ExpectedResourceCount: count,
 		ExpectedResourceAttributeValues: infratests.ResourceDescription{
diff --git a/infra/modules/providers/azure/storage-account/test.sh b/infra/modules/providers/azure/storage-account/test.sh
index a8601ca80..8544f4864 100755
--- a/infra/modules/providers/azure/storage-account/test.sh
+++ b/infra/modules/providers/azure/storage-account/test.sh
@@ -4,17 +4,28 @@
 set -e
 
 ###############################
-# Script Path Configuration
+# Source Common Functions
 ###############################
-SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
-TESTING_DIR="${SCRIPT_DIR}/testing"
-UNIT_TEST_DIR="${SCRIPT_DIR}/tests/unit"
-INTEGRATION_TEST_DIR="${SCRIPT_DIR}/tests/integration"
+COMMON_LIB="../test-functions.sh"
+if [ ! -f "$COMMON_LIB" ]; then
+    echo "Error: Common library not found at $COMMON_LIB"
+    exit 1
+fi
+source "$COMMON_LIB"
+
+
+###############################
+# Script Configuration
+###############################
+SCRIPT_DIR=$(get_script_dir)
+setup_test_directories "$SCRIPT_DIR"
+
 
 ###############################
 # Required Environment Variables
 ###############################
-: "${ARM_SUBSCRIPTION_ID:?'ARM_SUBSCRIPTION_ID environment variable is required'}"
+validate_azure_credentials
+
 
 ###############################
 # Optional Variables
@@ -24,318 +35,52 @@ RESOURCE_GROUP_PREFIX=${RESOURCE_GROUP_PREFIX:-"terraform-test"}
 DEFAULT_LOCATION="eastus2"
 STORAGE_ACCOUNT_NAME=${STORAGE_ACCOUNT_NAME:-""}  # Will be auto-generated if not provided
 
+
 ###############################
 # Help Documentation
 ###############################
-
 print_help() {
-    cat << EOF
-Storage Account Module Test Script
-================================
-
-This script runs unit tests and integration tests for the Azure Storage Account module.
-
-Required Environment Variables:
------------------------------
-ARM_SUBSCRIPTION_ID    Azure subscription ID to use for testing
-
-Usage:
-------
-$0 [resource_group_name] [location]
-$0 -h | --help
-
-Arguments:
-----------
-resource_group_name    (Optional) Name of resource group to create.
-                      Default: Auto-generated using prefix "terraform-test"
-
-location              (Optional) Azure region to deploy resources.
-                      Default: eastus2
-
-Options:
---------
--h, --help           Show this help message
-
-Examples:
----------
-# Run with auto-generated names in default location
-$0
-
-# Run with specific resource group name
-$0 my-test-rg
-
-# Run with specific resource group and location
-$0 my-test-rg westus2
-
-Notes:
-------
-- If not specified, a unique resource group name will be generated
-- If not specified, a unique storage account name will be generated
-- All resources are automatically cleaned up after the test
-- The script uses the default Azure CLI subscription if not specified
-EOF
-}
-
-###############################
-# Utility Functions
-###############################
-
-generate_unique_name() {
-    local prefix="${1:-}"
-    local suffix="${2:-}"
-    local unique
-
-    # More portable way to generate random string
-    if command -v openssl >/dev/null 2>&1; then
-        unique=$(openssl rand -hex 4 | tr '[:upper:]' '[:lower:]')
-    else
-        # Fallback to built-in $RANDOM if openssl is not available
-        unique=$(printf "%08x" $((RANDOM + RANDOM + RANDOM + RANDOM)))
-    fi
-
-    [[ -n "$prefix" ]] && echo "${prefix}-${unique}${suffix}" || echo "tftest${unique}${suffix}"
-}
-
-print_header() {
-    local title="$1"
-    printf "\n"
-    if [ -t 1 ] && command -v tput >/dev/null 2>&1; then
-        tput setaf 3 2>/dev/null || true
-        printf "%s\n" "=================================================================="
-        tput setaf 6 2>/dev/null || true
-        printf "%s\n" "                         ${title}                                 "
-        tput setaf 3 2>/dev/null || true
-        printf "%s\n" "=================================================================="
-        tput sgr0 2>/dev/null || true
-    else
-        printf "%s\n" "=================================================================="
-        printf "%s\n" "                         ${title}                                 "
-        printf "%s\n" "=================================================================="
-    fi
-    printf "\n"
-}
-
-log() {
-    local _msg="$1"
-    local _color="${2:-5}"
-
-    if [ -t 1 ] && command -v tput >/dev/null 2>&1; then
-        tput setaf "$_color" 2>/dev/null || true
-        printf "%s\n" "$_msg"
-        tput sgr0 2>/dev/null || true
-    else
-        printf "%s\n" "$_msg"
-    fi
+    print_common_help "Storage Account" "\n- If not specified, a unique storage account name will be generated"
 }
 
-print_separator() {
-    printf "\n"
-    if [ -t 1 ] && command -v tput >/dev/null 2>&1; then
-        tput setaf 4 2>/dev/null || true
-        printf "%s\n" "▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼"
-        tput sgr0 2>/dev/null || true
-    else
-        printf "%s\n" "=================================================="
-    fi
-    printf "\n"
-}
 
 ###############################
-# Configuration Setup
+# Required Module Functions
 ###############################
-
 setup_configuration() {
-    # Set location from args or default
-    LOCATION=${2:-$DEFAULT_LOCATION}
-
-    # Generate resource group name if not provided
-    if [ -z "$1" ]; then
-        RESOURCE_GROUP_NAME=$(generate_unique_name "$RESOURCE_GROUP_PREFIX" "")
-    else
-        RESOURCE_GROUP_NAME="$1"
-    fi
+    # Setup base configuration first
+    setup_base_configuration "$RESOURCE_GROUP_PREFIX" "$DEFAULT_LOCATION" "$@"
 
     # Generate storage account name if not provided
     if [ -z "$STORAGE_ACCOUNT_NAME" ]; then
         STORAGE_ACCOUNT_NAME=$(generate_unique_name "" "sa")
     fi
 
-    # Export variables for Go tests
-    export RESOURCE_GROUP_NAME
-    export LOCATION
+    # Export additional variables for Go tests
     export STORAGE_ACCOUNT_NAME
 }
 
-###############################
-# Variable Validation
-###############################
-
-validate_variables() {
-    print_header "Variable Validation"
-
-    log "Using Subscription: $ARM_SUBSCRIPTION_ID" 6
-    log "Using Resource Group: $RESOURCE_GROUP_NAME" 6
-    log "Using Location: $LOCATION" 6
-    log "Using Storage Account: $STORAGE_ACCOUNT_NAME" 6
-}
-
-###############################
-# Setup Functions
-###############################
-
-setup_azure() {
-    print_header "Azure Setup"
-
-    log "Verifying Azure subscription..." 5
-    az account show --subscription "$ARM_SUBSCRIPTION_ID" || {
-        log "Error: Could not access subscription $ARM_SUBSCRIPTION_ID" 1
-        exit 1
-    }
-    log "Azure subscription verified successfully" 2
-
-    log "Creating resource group..." 5
-    az group create \
-        --name "$RESOURCE_GROUP_NAME" \
-        --location "$LOCATION" \
-        --subscription "$ARM_SUBSCRIPTION_ID" \
-        --output json || {
-        log "Error: Could not create resource group $RESOURCE_GROUP_NAME" 1
-        exit 1
-    }
-    log "Resource group ready" 2
-}
-
 create_tfvars_files() {
-    print_header "Terraform Configuration"
-
     local tfvars_content="name = \"$STORAGE_ACCOUNT_NAME\"\nresource_group_name = \"$RESOURCE_GROUP_NAME\""
-
-    log "Creating testing.tfvars files..." 5
-    for dir in "$SCRIPT_DIR" "$UNIT_TEST_DIR" "$INTEGRATION_TEST_DIR" "$TESTING_DIR"; do
-        [[ -d "$dir" ]] && echo -e "$tfvars_content" > "$dir/testing.tfvars"
-    done
-    log "Configuration files created successfully" 2
-}
-
-###############################
-# Testing Functions
-###############################
-
-run_test() {
-    local test_dir="$1"
-    local test_name="$2"
-
-    print_header "$test_name"
-    log "Running $test_name..." 5
-    echo ""
-
-    pushd "$test_dir" > /dev/null || exit 1
-    if ! go test -v; then
-        log "Error: $test_name failed" 1
-        popd > /dev/null || exit 1
-        exit 1
-    fi
-    popd > /dev/null || exit 1
-
-    echo ""
-    log "$test_name completed" 2
-}
-
-run_basic_unit_tests() {
-    run_test "$TESTING_DIR" "Basic Unit Tests"
+    create_base_tfvars_files "$tfvars_content"
 }
 
-run_extended_unit_tests() {
-    run_test "$SCRIPT_DIR/tests" "Extended Unit Tests" "./unit/..."
-}
-
-run_integration_tests() {
-    run_test "$SCRIPT_DIR/tests" "Integration Tests" "./integration/..."
-}
-
-###############################
-# Terraform Functions
-###############################
-
-terraform_init_and_apply() {
-    print_header "Terraform Deployment"
-
-    log "Initializing Terraform..." 5
-    pushd "$TESTING_DIR" > /dev/null
-
-    print_separator
-    terraform init
-    print_separator
-
-    log "Planning Terraform changes..." 5
-    print_separator
-    terraform plan --var-file=testing.tfvars
-    print_separator
-
-    log "Applying Terraform changes..." 5
-    print_separator
-    terraform apply --var-file=testing.tfvars -auto-approve
-    print_separator
-
-    log "Terraform deployment completed successfully" 2
-    popd > /dev/null
-}
 
 ###############################
-# Cleanup Functions
+# Optional Module Functions
 ###############################
-
-cleanup_tfvars() {
-    log "Cleaning up testing.tfvars files..." 6
-    rm -f "$SCRIPT_DIR/testing.tfvars"
-    rm -f "$UNIT_TEST_DIR/testing.tfvars"
-    rm -f "$INTEGRATION_TEST_DIR/testing.tfvars"
-    rm -f "$TESTING_DIR/testing.tfvars"
-}
-
-cleanup_terraform() {
-    if [ -d "$TESTING_DIR/.terraform" ]; then
-        pushd "$TESTING_DIR" > /dev/null
-
-        log "Destroying Terraform resources..." 3
-        terraform destroy --var-file=testing.tfvars -auto-approve || true
-
-        log "Cleaning up Terraform files..." 6
-        rm -rf .terraform/
-        rm -f .terraform.lock.hcl
-        rm -f terraform.tfstate
-        rm -f terraform.tfstate.backup
-        rm -rf terraform.tfstate.d/
-
-        popd > /dev/null
-    fi
-
-    log "Deleting resource group..." 3
-    az group delete --name "$RESOURCE_GROUP_NAME" --subscription "$ARM_SUBSCRIPTION_ID" --yes || {
-        log "Warning: Could not delete resource group $RESOURCE_GROUP_NAME" 3
-    }
+validate_variables() {
+    validate_base_variables
+    log "Using Storage Account: $STORAGE_ACCOUNT_NAME" 6
 }
 
-cleanup() {
-    print_header "Cleanup"
-    log "Starting cleanup..." 5
-
-    cleanup_terraform
-    cleanup_tfvars
-
-    log "Cleanup completed successfully" 2
-}
 
 ###############################
 # Main Execution
 ###############################
-
 main() {
-    print_header "Test Execution"
-    log "Starting test setup..." 5
-
     # Trap cleanup on exit
-    trap cleanup EXIT
+    trap 'cleanup; cleanup_resource_group "$RESOURCE_GROUP_NAME" "$ARM_SUBSCRIPTION_ID"' EXIT
 
     # Setup configuration
     setup_configuration "$@"
@@ -344,18 +89,11 @@ main() {
     validate_variables
 
     # Setup
-    setup_azure
+    setup_azure_with_rg
     create_tfvars_files
 
-    # Run unit tests first
-    run_basic_unit_tests      # Simple tests in testing/
-    run_extended_unit_tests   # More complex tests in tests/unit/
-
-    # Now deploy infrastructure
-    terraform_init_and_apply  # Deploy infrastructure
-
-    # Run integration tests against deployed infrastructure
-    run_integration_tests     # Integration tests in tests/integration/
+    # Run all tests
+    run_standard_test_sequence
 }
 
 # Check for help flag
diff --git a/infra/modules/providers/azure/test-functions.sh b/infra/modules/providers/azure/test-functions.sh
new file mode 100644
index 000000000..9ad75e58e
--- /dev/null
+++ b/infra/modules/providers/azure/test-functions.sh
@@ -0,0 +1,493 @@
+#!/bin/bash
+
+###############################
+# Common Test Functions Library
+###############################
+# This library provides a base testing framework for Azure Terraform modules.
+# It follows an object-oriented pattern where this file acts as a base "class"
+# and each module's test.sh implements module-specific functionality.
+#
+# Usage:
+# 1. Source this file in your module's test.sh
+# 2. Implement the required functions (see Required Module Functions section)
+# 3. Use the common functions for standard operations
+#
+# Example module test.sh:
+# ```bash
+# #!/bin/bash
+# source "../test-functions.sh"
+#
+# setup_configuration() {
+#     setup_base_configuration "$RESOURCE_GROUP_PREFIX" "$DEFAULT_LOCATION" "$@"
+#     # Add module-specific configuration
+# }
+#
+# create_tfvars_files() {
+#     local tfvars_content="..."
+#     create_base_tfvars_files "$tfvars_content"
+# }
+#
+# main() {
+#     trap 'cleanup; cleanup_resource_group "$RESOURCE_GROUP_NAME" "$ARM_SUBSCRIPTION_ID"' EXIT
+#     setup_configuration "$@"
+#     validate_variables
+#     setup_azure
+#     create_tfvars_files
+#     run_standard_test_sequence
+# }
+# ```
+
+# Exit on error if sourced directly
+[[ "${BASH_SOURCE[0]}" == "${0}" ]] && set -e
+
+###############################
+# Directory Configuration
+###############################
+get_script_dir() {
+    echo "$( cd -- "$( dirname -- "${BASH_SOURCE[1]}" )" &> /dev/null && pwd )"
+}
+
+setup_test_directories() {
+    local SCRIPT_DIR="$1"
+    TESTING_DIR="${SCRIPT_DIR}/testing"
+    UNIT_TEST_DIR="${SCRIPT_DIR}/tests/unit"
+    INTEGRATION_TEST_DIR="${SCRIPT_DIR}/tests/integration"
+
+    # Export for use in tests
+    export TESTING_DIR UNIT_TEST_DIR INTEGRATION_TEST_DIR
+}
+
+
+###############################
+# Required Environment Variables
+###############################
+validate_azure_credentials() {
+    : "${ARM_SUBSCRIPTION_ID:?'ARM_SUBSCRIPTION_ID environment variable is required'}"
+}
+
+
+###############################
+# Utility Functions
+###############################
+generate_unique_name() {
+    local prefix="${1:-}"
+    local suffix="${2:-}"
+    local unique
+
+    # More portable way to generate random string
+    if command -v openssl >/dev/null 2>&1; then
+        unique=$(openssl rand -hex 4 | tr '[:upper:]' '[:lower:]')
+    else
+        # Fallback to built-in $RANDOM if openssl is not available
+        unique=$(printf "%08x" $((RANDOM + RANDOM + RANDOM + RANDOM)))
+    fi
+
+    [[ -n "$prefix" ]] && echo "${prefix}-${unique}${suffix}" || echo "tftest${unique}${suffix}"
+}
+
+print_header() {
+    local title="$1"
+    printf "\n"
+    if [ -t 1 ] && command -v tput >/dev/null 2>&1; then
+        tput setaf 3 2>/dev/null || true
+        printf "%s\n" "=================================================================="
+        tput setaf 6 2>/dev/null || true
+        printf "%s\n" "                         ${title}                                 "
+        tput setaf 3 2>/dev/null || true
+        printf "%s\n" "=================================================================="
+        tput sgr0 2>/dev/null || true
+    else
+        printf "%s\n" "=================================================================="
+        printf "%s\n" "                         ${title}                                 "
+        printf "%s\n" "=================================================================="
+    fi
+    printf "\n"
+}
+
+log() {
+    local _msg="$1"
+    local _color="${2:-5}"
+
+    if [ -t 1 ] && command -v tput >/dev/null 2>&1; then
+        tput setaf "$_color" 2>/dev/null || true
+        printf "%s\n" "$_msg"
+        tput sgr0 2>/dev/null || true
+    else
+        printf "%s\n" "$_msg"
+    fi
+}
+
+print_separator() {
+    printf "\n"
+    if [ -t 1 ] && command -v tput >/dev/null 2>&1; then
+        tput setaf 4 2>/dev/null || true
+        printf "%s\n" "▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼"
+        tput sgr0 2>/dev/null || true
+    else
+        printf "%s\n" "=================================================="
+    fi
+    printf "\n"
+}
+
+print_common_help() {
+    local module_name="$1"
+    local additional_notes="${2:-}"
+    local script_name=$(basename "${BASH_SOURCE[2]}")
+
+    cat << EOF
+${module_name} Module Test Script
+================================
+
+This script runs unit tests and integration tests for the Azure ${module_name} module.
+
+Required Environment Variables:
+-----------------------------
+ARM_SUBSCRIPTION_ID    Azure subscription ID to use for testing
+
+Usage:
+------
+${script_name} [resource_group_name] [location]
+${script_name} -h | --help
+
+Arguments:
+----------
+resource_group_name    (Optional) Name of resource group to create.
+                      Default: Auto-generated using prefix "terraform-test"
+
+location              (Optional) Azure region to deploy resources.
+                      Default: eastus2
+
+Options:
+--------
+-h, --help           Show this help message
+
+Examples:
+---------
+# Run with auto-generated names in default location
+${script_name}
+
+# Run with specific resource group name
+${script_name} my-test-rg
+
+# Run with specific resource group and location
+${script_name} my-test-rg westus2
+
+Notes:
+------
+- If not specified, a unique resource group name will be generated${additional_notes}
+- All resources are automatically cleaned up after the test
+- The script uses the default Azure CLI subscription if not specified
+EOF
+}
+
+
+###############################
+# Azure Functions
+###############################
+setup_azure() {
+    print_header "Azure Setup"
+
+    log "Verifying Azure subscription..." 5
+    az account show --subscription "$ARM_SUBSCRIPTION_ID" || {
+        log "Error: Could not access subscription $ARM_SUBSCRIPTION_ID" 1
+        exit 1
+    }
+    log "Azure subscription verified successfully" 2
+}
+
+
+###############################
+# Common Configuration Functions
+###############################
+setup_base_configuration() {
+    local prefix="$1"
+    local default_location="$2"
+    local args=("${@:3}")  # Get remaining args
+
+    # Set location from args or default
+    LOCATION=${args[1]:-$default_location}
+
+    # Generate resource group name if not provided
+    if [ -z "${args[0]}" ]; then
+        RESOURCE_GROUP_NAME=$(generate_unique_name "$prefix" "")
+    else
+        RESOURCE_GROUP_NAME="${args[0]}"
+    fi
+
+    # Export common variables for Go tests
+    export RESOURCE_GROUP_NAME
+    export LOCATION
+}
+
+validate_base_variables() {
+    print_header "Variable Validation"
+
+    log "Using Subscription: $ARM_SUBSCRIPTION_ID" 6
+    log "Using Resource Group: $RESOURCE_GROUP_NAME" 6
+    log "Using Location: $LOCATION" 6
+}
+
+setup_azure_with_rg() {
+    print_header "Azure Setup"
+
+    log "Verifying Azure subscription..." 5
+    az account show --subscription "$ARM_SUBSCRIPTION_ID" || {
+        log "Error: Could not access subscription $ARM_SUBSCRIPTION_ID" 1
+        exit 1
+    }
+    log "Azure subscription verified successfully" 2
+
+    log "Creating resource group..." 5
+    az group create \
+        --name "$RESOURCE_GROUP_NAME" \
+        --location "$LOCATION" \
+        --subscription "$ARM_SUBSCRIPTION_ID" \
+        --output json || {
+        log "Error: Could not create resource group $RESOURCE_GROUP_NAME" 1
+        exit 1
+    }
+    log "Resource group ready" 2
+}
+
+create_base_tfvars_files() {
+    local tfvars_content="$1"
+
+    print_header "Terraform Configuration"
+
+    log "Creating testing.tfvars files..." 5
+    for dir in "$SCRIPT_DIR" "$UNIT_TEST_DIR" "$INTEGRATION_TEST_DIR" "$TESTING_DIR"; do
+        [[ -d "$dir" ]] && echo -e "$tfvars_content" > "$dir/testing.tfvars"
+    done
+    log "Configuration files created successfully" 2
+}
+
+
+###############################
+# Required Module Functions
+###############################
+# Each module must implement the following functions:
+#
+# setup_configuration()
+# - Purpose: Set up module-specific configuration
+# - Requirements:
+#   - Call setup_base_configuration
+#   - Set any additional module-specific variables
+#   - Export any variables needed for tests
+#
+# create_tfvars_files()
+# - Purpose: Create module-specific tfvars content
+# - Requirements:
+#   - Create appropriate tfvars content
+#   - Call create_base_tfvars_files with the content
+#
+# Optional overrides:
+# - validate_variables()
+#   - Add module-specific variable validation
+#   - Call validate_base_variables first
+# - Any additional module-specific functions
+
+###############################
+# Module Implementation Validation
+###############################
+validate_module_implementation() {
+    local required_functions=("setup_configuration" "create_tfvars_files")
+    local missing_functions=()
+
+    for func in "${required_functions[@]}"; do
+        if ! declare -f "$func" > /dev/null; then
+            missing_functions+=("$func")
+        fi
+    done
+
+    if [ ${#missing_functions[@]} -ne 0 ]; then
+        log "Error: Module must implement the following functions:" 1
+        printf '%s\n' "${missing_functions[@]}" >&2
+        exit 1
+    fi
+}
+
+
+###############################
+# Standard Test Lifecycle
+###############################
+# The standard test sequence is:
+# 1. Setup
+#    - Configure variables
+#    - Validate environment
+#    - Create resource group
+# 2. Test
+#    - Run basic unit tests
+#    - Run extended unit tests
+#    - Deploy infrastructure
+#    - Run integration tests
+# 3. Cleanup
+#    - Destroy infrastructure
+#    - Remove resource group
+#    - Clean up files
+run_standard_test_sequence() {
+    # Validate module implementation
+    validate_module_implementation
+
+    print_header "Test Execution"
+    log "Starting test setup..." 5
+
+    # Run unit tests first
+    run_basic_unit_tests      # Simple tests in testing/
+    run_extended_unit_tests   # More complex tests in tests/unit/
+
+    # Now deploy infrastructure
+    terraform_init_and_apply  # Deploy infrastructure
+
+    # Run integration tests against deployed infrastructure
+    run_integration_tests     # Integration tests in tests/integration/
+}
+
+
+###############################
+# Testing Functions
+###############################
+run_test() {
+    local test_dir="$1"
+    local test_name="$2"
+    local test_path="${3:-}"  # Optional path for extended/integration tests
+
+    # Skip if directory doesn't exist
+    if [ ! -d "$test_dir" ]; then
+        log "Skipping $test_name - directory not found: $test_dir" 3
+        return 0
+    fi
+
+    print_header "$test_name"
+    log "Running $test_name..." 5
+    echo ""
+
+    pushd "$test_dir" > /dev/null || exit 1
+    if [ -n "$test_path" ]; then
+        # Use proper Go test path pattern
+        if ! ls ./"$test_path"/*_test.go >/dev/null 2>&1; then
+            log "No test files found in $test_path" 3
+            popd > /dev/null || exit 1
+            return 0
+        fi
+        if ! go test -v "./$test_path/..."; then
+            log "Error: $test_name failed" 1
+            popd > /dev/null || exit 1
+            exit 1
+        fi
+    else
+        if ! go test -v ./...; then
+            log "Error: $test_name failed" 1
+            popd > /dev/null || exit 1
+            exit 1
+        fi
+    fi
+    popd > /dev/null || exit 1
+
+    echo ""
+    log "$test_name completed" 2
+}
+
+run_basic_unit_tests() {
+    run_test "$TESTING_DIR" "Basic Unit Tests"
+}
+
+run_extended_unit_tests() {
+    # Only run if the extended unit tests directory exists
+    if [ -d "$UNIT_TEST_DIR" ]; then
+        run_test "$SCRIPT_DIR/tests" "Extended Unit Tests" "unit"
+    else
+        log "Skipping Extended Unit Tests - no extended tests found" 3
+    fi
+}
+
+run_integration_tests() {
+    # Only run if the integration test directory exists
+    if [ -d "$INTEGRATION_TEST_DIR" ]; then
+        run_test "$SCRIPT_DIR/tests" "Integration Tests" "integration"
+    else
+        log "Skipping Integration Tests - no integration tests found" 3
+    fi
+}
+
+
+###############################
+# Terraform Functions
+###############################
+terraform_init_and_apply() {
+    print_header "Terraform Deployment"
+
+    log "Initializing Terraform..." 5
+    pushd "$TESTING_DIR" > /dev/null
+
+    print_separator
+    terraform init
+    print_separator
+
+    log "Planning Terraform changes..." 5
+    print_separator
+    terraform plan --var-file=testing.tfvars
+    print_separator
+
+    log "Applying Terraform changes..." 5
+    print_separator
+    terraform apply --var-file=testing.tfvars -auto-approve
+    print_separator
+
+    log "Terraform deployment completed successfully" 2
+    popd > /dev/null
+}
+
+
+###############################
+# Cleanup Functions
+###############################
+cleanup_tfvars() {
+    log "Cleaning up testing.tfvars files..." 6
+    rm -f "$SCRIPT_DIR/testing.tfvars"
+    rm -f "$UNIT_TEST_DIR/testing.tfvars"
+    rm -f "$INTEGRATION_TEST_DIR/testing.tfvars"
+    rm -f "$TESTING_DIR/testing.tfvars"
+}
+
+cleanup_terraform() {
+    if [ -d "$TESTING_DIR/.terraform" ]; then
+        pushd "$TESTING_DIR" > /dev/null
+
+        log "Destroying Terraform resources..." 3
+        terraform destroy --var-file=testing.tfvars -auto-approve || true
+
+        log "Cleaning up Terraform files..." 6
+        rm -rf .terraform/
+        rm -f .terraform.lock.hcl
+        rm -f terraform.tfstate
+        rm -f terraform.tfstate.backup
+        rm -rf terraform.tfstate.d/
+
+        popd > /dev/null
+    fi
+}
+
+cleanup_resource_group() {
+    local resource_group_name="$1"
+    local subscription_id="$2"
+
+    # Check if resource group exists before trying to delete
+    if az group exists --name "$resource_group_name" --subscription "$subscription_id" >/dev/null 2>&1; then
+        log "Deleting resource group $resource_group_name..." 3
+        az group delete --name "$resource_group_name" --subscription "$subscription_id" --yes || {
+            log "Warning: Could not delete resource group $resource_group_name" 3
+        }
+    else
+        log "Resource group $resource_group_name already deleted" 6
+    fi
+}
+
+cleanup() {
+    print_header "Cleanup"
+    log "Starting cleanup..." 5
+
+    cleanup_terraform
+    cleanup_tfvars
+
+    log "Cleanup completed successfully" 2
+}
\ No newline at end of file
-- 
GitLab


From 2dbea4677f13b7f0e745bb0b619d522f444711e7 Mon Sep 17 00:00:00 2001
From: danielscholl <dascholl@microsoft.com>
Date: Sun, 2 Feb 2025 16:00:20 -0600
Subject: [PATCH 05/15] Implemented log-analytics tests.

---
 .../.cursor/rules/terraform-module.mdc        | 249 ++++++++++++++++++
 infra/modules/magefile.go                     |  71 +++++
 .../providers/azure/aks/testing/unit_test.go  |  20 +-
 .../providers/azure/log-analytics/test.sh     | 108 ++++++++
 .../storage-account/testing/unit_test.go      |   2 +-
 .../azure/storage-account/tests/tf_options.go |   4 +-
 .../providers/azure/terraform-module.mdc      |   1 +
 .../modules/providers/azure/test-functions.sh |   5 +-
 8 files changed, 446 insertions(+), 14 deletions(-)
 create mode 100644 infra/modules/.cursor/rules/terraform-module.mdc
 create mode 100755 infra/modules/providers/azure/log-analytics/test.sh
 create mode 100644 infra/modules/providers/azure/terraform-module.mdc

diff --git a/infra/modules/.cursor/rules/terraform-module.mdc b/infra/modules/.cursor/rules/terraform-module.mdc
new file mode 100644
index 000000000..de8ea8499
--- /dev/null
+++ b/infra/modules/.cursor/rules/terraform-module.mdc
@@ -0,0 +1,249 @@
+---
+description: This rule defines how osdu rules are created.
+globs: 
+---
+# Terraform Module Development Guidelines
+
+This document outlines the standards and patterns for developing Terraform modules in our infrastructure codebase.
+
+## Module Structure
+
+```
+module-name/
+├── README.md           # Module documentation
+├── main.tf            # Main module configuration
+├── variables.tf       # Input variable definitions
+├── outputs.tf         # Output definitions
+├── test.sh           # Test execution script
+├── testing/          # Basic test configuration
+│   ├── main.tf       # Test implementation
+│   └── unit_test.go  # Basic unit tests
+└── tests/            # Extended test suite
+    ├── .env.testing.template  # Environment variables template
+    ├── tf_options.go          # Common test configuration
+    ├── unit/                  # Extended unit tests
+    │   └── *_test.go
+    └── integration/           # Integration tests
+        └── *_test.go
+```
+
+## Code Organization
+
+### 1. Main Configuration (main.tf)
+- Start with required provider configuration
+- Include copyright header
+- Group resources logically
+- Use data sources for existing resources
+- Implement resource configurations
+- Use dynamic blocks for optional features
+
+```hcl
+terraform {
+  required_providers {
+    azurerm = {
+      source  = "hashicorp/azurerm"
+      version = "=3.90.0"  # Pin to specific version
+    }
+  }
+}
+
+provider "azurerm" {
+  features {}
+}
+
+data "azurerm_resource_group" "main" {
+  name = var.resource_group_name
+}
+
+resource "azurerm_example" "main" {
+  name                = var.name
+  resource_group_name = data.azurerm_resource_group.main.name
+  location            = data.azurerm_resource_group.main.location
+
+  dynamic "optional_block" {
+    for_each = var.optional_feature_enabled ? [1] : []
+    content {
+      // Configuration
+    }
+  }
+}
+```
+
+### 2. Variables (variables.tf)
+- Group variables by purpose
+- Include clear descriptions
+- Provide type constraints
+- Set defaults where appropriate
+- Mark sensitive variables
+
+```hcl
+variable "name" {
+  description = "The name of the resource"
+  type        = string
+}
+
+variable "resource_tags" {
+  description = "Map of tags to apply to resources"
+  type        = map(string)
+  default     = {}
+}
+```
+
+### 3. Outputs (outputs.tf)
+- Include essential resource information
+- Mark sensitive outputs
+- Group related outputs
+- Use maps for collections
+- Include resource IDs and names
+
+```hcl
+output "id" {
+  description = "The ID of the created resource"
+  value       = azurerm_example.main.id
+}
+
+output "properties" {
+  description = "Properties of the deployed resource"
+  value = {
+    id   = azurerm_example.main.id
+    name = azurerm_example.main.name
+  }
+  sensitive = true
+}
+```
+
+## Testing Framework
+
+### 1. Test Script (test.sh)
+- Source common test functions
+- Implement required module functions
+- Setup configuration
+- Create tfvars files
+- Execute test sequence
+
+```bash
+#!/bin/bash
+source "../test-functions.sh"
+
+setup_configuration() {
+    setup_base_configuration "$RESOURCE_GROUP_PREFIX" "$DEFAULT_LOCATION" "$@"
+    # Add module-specific configuration
+}
+
+create_tfvars_files() {
+    local tfvars_content="..."
+    create_base_tfvars_files "$tfvars_content"
+}
+
+main() {
+    trap 'cleanup' EXIT
+    setup_configuration "$@"
+    validate_variables
+    setup_azure
+    create_tfvars_files
+    run_standard_test_sequence
+}
+```
+
+### 2. Unit Tests
+- Basic tests in testing/unit_test.go
+- Extended tests in tests/unit/
+- Validate resource attributes
+- Check resource counts
+- Verify configurations
+
+```go
+func TestTemplate(t *testing.T) {
+    testFixture := infratests.UnitTestFixture{
+        GoTest:                t,
+        TfOptions:             tfOptions,
+        ExpectedResourceCount: count,
+        ExpectedResourceAttributeValues: infratests.ResourceDescription{
+            "module.example.azurerm_example.main": expectedResult,
+        },
+    }
+    infratests.RunUnitTests(&testFixture)
+}
+```
+
+### 3. Integration Tests
+- Implement in tests/integration/
+- Test actual resource creation
+- Verify resource properties
+- Clean up resources after tests
+
+## Documentation
+
+### 1. README.md
+- Module description
+- Usage examples
+- Input variables table
+- Output variables table
+- License information
+
+### 2. Code Comments
+- Include copyright header
+- Document non-obvious logic
+- Explain variable purposes
+- Detail resource configurations
+
+## Best Practices
+
+1. **Resource Naming**
+- Use consistent resource names
+- Prefix resources appropriately
+- Follow Azure naming conventions
+
+2. **Security**
+- Enable HTTPS by default
+- Use latest TLS versions
+- Implement proper access controls
+- Mark sensitive outputs
+
+3. **Resource Management**
+- Implement proper cleanup
+- Use resource locks where needed
+- Handle dependencies correctly
+
+4. **Testing**
+- Implement both unit and integration tests
+- Use meaningful test names
+- Clean up test resources
+- Validate all configurations
+
+## Continuous Integration
+
+1. **Pre-commit Checks**
+- Run terraform fmt
+- Validate configurations
+- Check for sensitive data
+
+2. **Automated Testing**
+- Execute unit tests
+- Run integration tests
+- Verify outputs
+
+3. **Documentation Updates**
+- Keep README current
+- Update examples
+- Document changes
+
+## License and Copyright
+
+All terraform and go files must include the Apache 2.0 license header:
+
+```hcl
+//  Copyright © Microsoft Corporation
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+```
\ No newline at end of file
diff --git a/infra/modules/magefile.go b/infra/modules/magefile.go
index 2ff7b4c76..89ef8cb08 100644
--- a/infra/modules/magefile.go
+++ b/infra/modules/magefile.go
@@ -27,6 +27,7 @@ func TestModules() error {
 	return FindAndRunTests("testing")
 }
 
+
 // Validate both Terraform code and Go code.
 func Check() {
 	mg.Deps(LintTF)
@@ -97,6 +98,11 @@ func verifyRunsQuietly(instructionsToFix string, cmd string, args ...string) err
 
 // FindAndRunTests finds all tests with a given path suffix and runs them using `go test`
 func FindAndRunTests(pathSuffix string) error {
+	// Set default resource group name if not set
+	if os.Getenv("RESOURCE_GROUP_NAME") == "" {
+		os.Setenv("RESOURCE_GROUP_NAME", "osdu-testing")
+	}
+
 	goModules, err := sh.Output("go", "list", "./...")
 	if err != nil {
 		return err
@@ -118,3 +124,68 @@ func FindAndRunTests(pathSuffix string) error {
 	cmdArgs = append(cmdArgs, "-v", "-timeout", "7200s")
 	return sh.RunV("go", cmdArgs...)
 }
+
+// ModuleTest runs the test.sh script for a specific module
+func Test(module string) error {
+	fmt.Printf("INFO: Running test script for module: %s\n", module)
+
+	// Check required environment variables
+	if os.Getenv("ARM_SUBSCRIPTION_ID") == "" {
+		return fmt.Errorf("ERROR: ARM_SUBSCRIPTION_ID environment variable is required")
+	}
+
+	// Ensure we're in the right directory context
+	moduleDir := filepath.Join("providers", "azure", module)
+	scriptPath := filepath.Join(moduleDir, "test.sh")
+
+	if _, err := os.Stat(scriptPath); os.IsNotExist(err) {
+		return fmt.Errorf("test.sh script not found for module '%s' at path: %s", module, scriptPath)
+	}
+
+	// Make the script executable
+	if err := os.Chmod(scriptPath, 0755); err != nil {
+		return fmt.Errorf("failed to make script executable: %v", err)
+	}
+
+	// Set default environment variables if not already set
+	if os.Getenv("RESOURCE_GROUP_NAME") == "" {
+		os.Setenv("RESOURCE_GROUP_NAME", "osdu-testing")
+	}
+	if os.Getenv("LOCATION") == "" {
+		os.Setenv("LOCATION", "eastus2")
+	}
+
+	// Run the script from its directory with debug output
+	fmt.Printf("INFO: Running script from directory: %s\n", moduleDir)
+	fmt.Printf("INFO: Using RESOURCE_GROUP_NAME: %s\n", os.Getenv("RESOURCE_GROUP_NAME"))
+	fmt.Printf("INFO: Using LOCATION: %s\n", os.Getenv("LOCATION"))
+
+	// Change to the module directory before running the script
+	currentDir, err := os.Getwd()
+	if err != nil {
+		return fmt.Errorf("failed to get current directory: %v", err)
+	}
+
+	if err := os.Chdir(moduleDir); err != nil {
+		return fmt.Errorf("failed to change to module directory: %v", err)
+	}
+
+	// Change back to original directory when done
+	defer os.Chdir(currentDir)
+
+	// Set environment variables for the script
+	env := map[string]string{
+		"SCRIPT_DIR":          moduleDir,
+		"ARM_SUBSCRIPTION_ID": os.Getenv("ARM_SUBSCRIPTION_ID"),
+		"RESOURCE_GROUP_NAME": os.Getenv("RESOURCE_GROUP_NAME"),
+		"LOCATION":           os.Getenv("LOCATION"),
+	}
+
+	// Set the environment variables
+	for k, v := range env {
+		os.Setenv(k, v)
+	}
+
+	// Use RunV to show all output
+	return sh.RunV("./test.sh")
+}
diff --git a/infra/modules/providers/azure/aks/testing/unit_test.go b/infra/modules/providers/azure/aks/testing/unit_test.go
index 438be6c71..878905156 100644
--- a/infra/modules/providers/azure/aks/testing/unit_test.go
+++ b/infra/modules/providers/azure/aks/testing/unit_test.go
@@ -1,16 +1,16 @@
-//  Copyright © Microsoft Corporation
+// Copyright © Microsoft Corporation
 //
-//  Licensed under the Apache License, Version 2.0 (the "License");
-//  you may not use this file except in compliance with the License.
-//  You may obtain a copy of the License at
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
 //
-//       http://www.apache.org/licenses/LICENSE-2.0
+//	http://www.apache.org/licenses/LICENSE-2.0
 //
-//  Unless required by applicable law or agreed to in writing, software
-//  distributed under the License is distributed on an "AS IS" BASIS,
-//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-//  See the License for the specific language governing permissions and
-//  limitations under the License.
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
 package test
 
 import (
diff --git a/infra/modules/providers/azure/log-analytics/test.sh b/infra/modules/providers/azure/log-analytics/test.sh
new file mode 100755
index 000000000..ced5db769
--- /dev/null
+++ b/infra/modules/providers/azure/log-analytics/test.sh
@@ -0,0 +1,108 @@
+#!/bin/bash
+
+# Exit on error
+set -e
+
+###############################
+# Source Common Functions
+###############################
+COMMON_LIB="../test-functions.sh"
+if [ ! -f "$COMMON_LIB" ]; then
+    echo "Error: Common library not found at $COMMON_LIB"
+    exit 1
+fi
+source "$COMMON_LIB"
+
+
+###############################
+# Script Configuration
+###############################
+SCRIPT_DIR=$(get_script_dir)
+setup_test_directories "$SCRIPT_DIR"
+
+
+###############################
+# Required Environment Variables
+###############################
+validate_azure_credentials
+
+
+###############################
+# Optional Variables
+###############################
+# These can be overridden by setting them before running the script
+RESOURCE_GROUP_PREFIX=${RESOURCE_GROUP_PREFIX:-"terraform-test"}
+DEFAULT_LOCATION="eastus2"
+LOG_ANALYTICS_NAME=${LOG_ANALYTICS_NAME:-""}  # Will be auto-generated if not provided
+
+
+###############################
+# Help Documentation
+###############################
+print_help() {
+    print_common_help "Log Analytics" "\n- If not specified, a unique log analytics workspace name will be generated"
+}
+
+
+###############################
+# Required Module Functions
+###############################
+setup_configuration() {
+    # Setup base configuration first
+    setup_base_configuration "$RESOURCE_GROUP_PREFIX" "$DEFAULT_LOCATION" "$@"
+
+    # Generate log analytics name if not provided
+    if [ -z "$LOG_ANALYTICS_NAME" ]; then
+        LOG_ANALYTICS_NAME=$(generate_unique_name "" "logs")
+    fi
+
+    # Export additional variables for Go tests
+    export LOG_ANALYTICS_NAME
+}
+
+create_tfvars_files() {
+    local tfvars_content="name = \"$LOG_ANALYTICS_NAME\"\nresource_group_name = \"$RESOURCE_GROUP_NAME\"\n\nsolutions = [\n  {\n    solution_name = \"ContainerInsights\"\n    publisher = \"Microsoft\"\n    product = \"OMSGallery/ContainerInsights\"\n  }\n]\n\nresource_tags = {\n  osdu = \"module\"\n}"
+    create_base_tfvars_files "$tfvars_content"
+}
+
+
+###############################
+# Optional Module Functions
+###############################
+validate_variables() {
+    validate_base_variables
+    log "Using Log Analytics Workspace: $LOG_ANALYTICS_NAME" 6
+}
+
+
+###############################
+# Main Execution
+###############################
+main() {
+    # Trap cleanup on exit
+    trap 'cleanup; cleanup_resource_group "$RESOURCE_GROUP_NAME" "$ARM_SUBSCRIPTION_ID"' EXIT
+
+    # Setup configuration
+    setup_configuration "$@"
+
+    # Validate variables
+    validate_variables
+
+    # Setup
+    setup_azure_with_rg
+    create_tfvars_files
+
+    # Run all tests
+    run_standard_test_sequence
+}
+
+# Check for help flag
+case "$1" in
+    -h|--help)
+        print_help
+        exit 0
+        ;;
+esac
+
+# Execute main function
+main "$@"
\ No newline at end of file
diff --git a/infra/modules/providers/azure/storage-account/testing/unit_test.go b/infra/modules/providers/azure/storage-account/testing/unit_test.go
index 75e585674..50e377b35 100644
--- a/infra/modules/providers/azure/storage-account/testing/unit_test.go
+++ b/infra/modules/providers/azure/storage-account/testing/unit_test.go
@@ -46,7 +46,7 @@ func TestTemplate(t *testing.T) {
 		Vars: map[string]interface{}{
 			"name":                storageAcctName,
 			"resource_group_name": resourceGroupName,
-			"location":           location,
+			"location":            location,
 		},
 	}
 
diff --git a/infra/modules/providers/azure/storage-account/tests/tf_options.go b/infra/modules/providers/azure/storage-account/tests/tf_options.go
index 44dec69fa..370f857eb 100644
--- a/infra/modules/providers/azure/storage-account/tests/tf_options.go
+++ b/infra/modules/providers/azure/storage-account/tests/tf_options.go
@@ -31,7 +31,7 @@ var ResourceGroupName = os.Getenv("RESOURCE_GROUP_NAME")
 
 // StorageTFOptions common terraform options used for unit testing
 var StorageTFOptions = &terraform.Options{
-	TerraformDir: "../../",  // Point to module directory for unit tests
+	TerraformDir: "../../", // Point to module directory for unit tests
 	Vars: map[string]interface{}{
 		"resource_group_name": ResourceGroupName,
 		"name":                StorageAccount,
@@ -43,7 +43,7 @@ var StorageTFOptions = &terraform.Options{
 
 // StorageIntegrationTFOptions terraform options used for integration testing
 var StorageIntegrationTFOptions = &terraform.Options{
-	TerraformDir: "../../testing",  // Point to testing directory for integration tests
+	TerraformDir: "../../testing", // Point to testing directory for integration tests
 	Vars: map[string]interface{}{
 		"resource_group_name": ResourceGroupName,
 		"name":                StorageAccount,
diff --git a/infra/modules/providers/azure/terraform-module.mdc b/infra/modules/providers/azure/terraform-module.mdc
new file mode 100644
index 000000000..0519ecba6
--- /dev/null
+++ b/infra/modules/providers/azure/terraform-module.mdc
@@ -0,0 +1 @@
+ 
\ No newline at end of file
diff --git a/infra/modules/providers/azure/test-functions.sh b/infra/modules/providers/azure/test-functions.sh
index 9ad75e58e..544592d73 100644
--- a/infra/modules/providers/azure/test-functions.sh
+++ b/infra/modules/providers/azure/test-functions.sh
@@ -199,9 +199,12 @@ setup_azure() {
 ###############################
 # Common Configuration Functions
 ###############################
+# Default Azure location for all tests
+DEFAULT_LOCATION="eastus2"
+
 setup_base_configuration() {
     local prefix="$1"
-    local default_location="$2"
+    local default_location="${2:-$DEFAULT_LOCATION}"  # Use provided location or DEFAULT_LOCATION
     local args=("${@:3}")  # Get remaining args
 
     # Set location from args or default
-- 
GitLab


From b2c6e384f607aac920d109aa59b0db44f2e1d6a5 Mon Sep 17 00:00:00 2001
From: danielscholl <dascholl@microsoft.com>
Date: Sun, 2 Feb 2025 18:46:49 -0600
Subject: [PATCH 06/15] Updated rules

---
 .../providers/azure/terraform-module.mdc      | 297 +++++++++++++++++-
 1 file changed, 296 insertions(+), 1 deletion(-)

diff --git a/infra/modules/providers/azure/terraform-module.mdc b/infra/modules/providers/azure/terraform-module.mdc
index 0519ecba6..97b4e1052 100644
--- a/infra/modules/providers/azure/terraform-module.mdc
+++ b/infra/modules/providers/azure/terraform-module.mdc
@@ -1 +1,296 @@
- 
\ No newline at end of file
+# Terraform Module Development Guidelines
+
+This document outlines the standards and patterns for developing Terraform modules in our infrastructure codebase.
+
+## Module Structure
+
+```
+module-name/
+├── README.md           # Module documentation
+├── main.tf            # Main module configuration
+├── variables.tf       # Input variable definitions
+├── outputs.tf         # Output definitions
+├── test.sh           # Test execution script
+├── testing/          # Basic test configuration
+│   ├── main.tf       # Test implementation
+│   └── unit_test.go  # Basic unit tests
+└── tests/            # Extended test suite
+    ├── .env.testing.template  # Environment variables template
+    ├── tf_options.go          # Common test configuration
+    ├── unit/                  # Extended unit tests
+    │   └── *_test.go
+    └── integration/           # Integration tests
+        └── *_test.go
+```
+
+## Code Organization
+
+### 1. Main Configuration (main.tf)
+- Start with required provider configuration
+- Include copyright header
+- Group resources logically
+- Use data sources for existing resources
+- Implement resource configurations
+- Use dynamic blocks for optional features
+
+```hcl
+terraform {
+  required_providers {
+    azurerm = {
+      source  = "hashicorp/azurerm"
+      version = "=3.90.0"  # Pin to specific version
+    }
+  }
+}
+
+provider "azurerm" {
+  features {}
+}
+
+data "azurerm_resource_group" "main" {
+  name = var.resource_group_name
+}
+
+resource "azurerm_example" "main" {
+  name                = var.name
+  resource_group_name = data.azurerm_resource_group.main.name
+  location            = data.azurerm_resource_group.main.location
+
+  dynamic "optional_block" {
+    for_each = var.optional_feature_enabled ? [1] : []
+    content {
+      // Configuration
+    }
+  }
+}
+```
+
+### 2. Variables (variables.tf)
+- Group variables by purpose
+- Include clear descriptions
+- Provide type constraints
+- Set defaults where appropriate
+- Mark sensitive variables
+
+```hcl
+variable "name" {
+  description = "The name of the resource"
+  type        = string
+}
+
+variable "resource_tags" {
+  description = "Map of tags to apply to resources"
+  type        = map(string)
+  default     = {}
+}
+```
+
+### 3. Outputs (outputs.tf)
+- Include essential resource information
+- Mark sensitive outputs
+- Group related outputs
+- Use maps for collections
+- Include resource IDs and names
+
+```hcl
+output "id" {
+  description = "The ID of the created resource"
+  value       = azurerm_example.main.id
+}
+
+output "properties" {
+  description = "Properties of the deployed resource"
+  value = {
+    id   = azurerm_example.main.id
+    name = azurerm_example.main.name
+  }
+  sensitive = true
+}
+```
+
+## Testing Framework
+
+### 1. Common Test Functions Library (test-functions.sh)
+The common test functions library provides essential functionality for all module tests. Key functions include:
+
+```bash
+# Base Configuration Functions
+setup_base_configuration()     # Sets up basic test configuration
+validate_base_variables()      # Validates required environment variables
+setup_azure()                 # Basic Azure setup without resource group
+setup_azure_with_rg()         # Azure setup including resource group creation
+
+# Resource Management
+generate_unique_name()        # Generates unique resource names
+cleanup()                     # Cleans up test artifacts
+cleanup_resource_group()      # Removes Azure resource group
+
+# Test Utilities
+get_script_dir()             # Gets the current script directory
+setup_test_directories()     # Sets up test directory structure
+log()                        # Formatted logging with colors
+print_separator()            # Prints visual separator in output
+print_common_help()          # Prints standardized help message
+
+# Test Execution
+run_standard_test_sequence() # Executes the standard test suite
+```
+
+### 2. Test Script Implementation (test.sh)
+Each module must implement these required components:
+
+1. **Required Variables**
+```bash
+COMMON_LIB="../test-functions.sh"    # Path to common functions
+SCRIPT_DIR                          # Current script directory
+RESOURCE_GROUP_PREFIX               # Prefix for resource group names
+DEFAULT_LOCATION                    # Default Azure region
+RESOURCE_NAME                       # Module-specific resource name
+```
+
+2. **Required Functions**
+```bash
+setup_configuration() {
+    # Must implement:
+    # 1. Call setup_base_configuration
+    # 2. Generate resource names if needed
+    # 3. Export variables for Go tests
+}
+
+create_tfvars_files() {
+    # Must implement:
+    # 1. Define tfvars content
+    # 2. Call create_base_tfvars_files
+}
+
+validate_variables() {
+    # Should implement:
+    # 1. Call validate_base_variables
+    # 2. Validate module-specific variables
+}
+
+print_help() {
+    # Should implement:
+    # 1. Call print_common_help
+    # 2. Add module-specific help info
+}
+```
+
+3. **Standard Error Handling**
+```bash
+# Required error handling patterns
+set -e                        # Exit on any error
+trap 'cleanup' EXIT          # Ensure cleanup on exit
+validate_azure_credentials   # Check Azure authentication
+
+# Error checking examples
+if [ ! -f "$COMMON_LIB" ]; then
+    echo "Error: Common library not found"
+    exit 1
+fi
+
+if [ -z "$REQUIRED_VAR" ]; then
+    log "Error: Required variable not set" 1
+    exit 1
+fi
+```
+
+### 3. Testing Directory Structure
+Explanation of required test files and their purposes:
+
+```
+module-name/
+├── testing/                      # Basic test configuration
+│   ├── main.tf                  # Basic test implementation
+│   │   # Required sections:
+│   │   # - Provider configuration
+│   │   # - Resource group module
+│   │   # - Module under test
+│   │   # - Required variables
+│   │
+│   └── unit_test.go            # Basic unit tests
+│       # Required tests:
+│       # - Resource count validation
+│       # - Basic attribute validation
+│       # - Required tag validation
+│
+└── tests/                       # Extended test suite
+    ├── tf_options.go           # Test configuration
+    │   # Required configuration:
+    │   # - TF_VAR environment variables
+    │   # - Terraform options
+    │   # - Test fixtures
+    │
+    ├── unit/                   # Extended unit tests
+    │   └── *_test.go          # Specific resource tests
+    │       # Should include:
+    │       # - Detailed attribute validation
+    │       # - Configuration variants
+    │       # - Error cases
+    │
+    └── integration/            # Integration tests
+        └── *_test.go          # Live resource tests
+            # Should include:
+            # - Resource creation verification
+            # - Resource update testing
+            # - Resource deletion testing
+```
+
+### 4. Common Test Patterns
+
+1. **Resource Name Generation**
+```bash
+# Standard pattern for resource names
+generate_unique_name() {
+    local prefix="$1"
+    local resource_type="$2"
+    echo "${prefix}${resource_type}${RANDOM}"
+}
+
+# Usage example
+STORAGE_ACCOUNT_NAME=$(generate_unique_name "" "sa")
+LOG_ANALYTICS_NAME=$(generate_unique_name "" "logs")
+```
+
+2. **Variable Validation**
+```bash
+validate_variables() {
+    validate_base_variables
+
+    # Resource name validation
+    if [[ ! "$RESOURCE_NAME" =~ ^[a-z0-9]+$ ]]; then
+        log "Error: Resource name must be lowercase alphanumeric" 1
+        exit 1
+    fi
+
+    # Location validation
+    if [[ ! "$LOCATION" =~ ^[a-z]+[a-z0-9]+$ ]]; then
+        log "Error: Invalid location format" 1
+        exit 1
+    fi
+}
+```
+
+3. **Terraform Variable File Creation**
+```bash
+create_tfvars_files() {
+    # Standard format for tfvars content
+    local tfvars_content="
+name                = \"$RESOURCE_NAME\"
+resource_group_name = \"$RESOURCE_GROUP_NAME\"
+location            = \"$LOCATION\"
+
+# Optional configurations
+tags = {
+    environment = \"testing\"
+    module     = \"example\"
+}
+
+# Resource-specific configurations
+specific_setting = \"value\"
+"
+    create_base_tfvars_files "$tfvars_content"
+}
+```
+
+// ... rest of the file remains unchanged ... 
\ No newline at end of file
-- 
GitLab


From c15aa90d403cdbe736df7c8655e1dc75f8e9b2fe Mon Sep 17 00:00:00 2001
From: "danielscholl (aider)" <dascholl@microsoft.com>
Date: Sun, 2 Feb 2025 19:19:09 -0600
Subject: [PATCH 07/15] feat: Create test script for app-insights Terraform
 module

---
 .../providers/azure/app-insights/test.sh      | 93 +++++++++++++++++++
 1 file changed, 93 insertions(+)
 create mode 100644 infra/modules/providers/azure/app-insights/test.sh

diff --git a/infra/modules/providers/azure/app-insights/test.sh b/infra/modules/providers/azure/app-insights/test.sh
new file mode 100644
index 000000000..41bc31d42
--- /dev/null
+++ b/infra/modules/providers/azure/app-insights/test.sh
@@ -0,0 +1,93 @@
+#!/bin/bash
+
+# Exit on error
+set -e
+
+###############################
+# Source Common Functions
+###############################
+COMMON_LIB="../../test-functions.sh"
+if [ ! -f "$COMMON_LIB" ]; then
+    echo "Error: Common library not found at $COMMON_LIB"
+    exit 1
+fi
+source "$COMMON_LIB"
+
+###############################
+# Script Configuration
+###############################
+SCRIPT_DIR=$(get_script_dir)
+setup_test_directories "$SCRIPT_DIR"
+
+###############################
+# Required Environment Variables
+###############################
+validate_azure_credentials
+
+###############################
+# Optional Variables
+###############################
+# These can be overridden by setting them before running the script
+RESOURCE_GROUP_PREFIX=${RESOURCE_GROUP_PREFIX:-"app-insights-test"}
+DEFAULT_LOCATION="eastus2"
+
+###############################
+# Help Documentation
+###############################
+print_help() {
+    print_common_help "App Insights"
+}
+
+###############################
+# Required Module Functions
+###############################
+setup_configuration() {
+    # Setup base configuration
+    setup_base_configuration "$RESOURCE_GROUP_PREFIX" "$DEFAULT_LOCATION" "$@"
+    export APP_INSIGHTS_NAME="${RESOURCE_GROUP_NAME}-app-insights"
+}
+
+create_tfvars_files() {
+    local tfvars_content="
+appinsights_name                 = \"${APP_INSIGHTS_NAME}\"
+service_plan_resource_group_name = \"${RESOURCE_GROUP_NAME}\"
+appinsights_application_type     = \"java\"
+resource_tags = {
+  environment = \"testing\"
+  module      = \"app-insights\"
+}
+"
+    create_base_tfvars_files "$tfvars_content"
+}
+
+###############################
+# Main Execution
+###############################
+main() {
+    # Trap cleanup on exit
+    trap 'cleanup; cleanup_resource_group "$RESOURCE_GROUP_NAME" "$ARM_SUBSCRIPTION_ID"' EXIT
+
+    # Setup configuration
+    setup_configuration "$@"
+
+    # Validate variables
+    validate_base_variables
+
+    # Setup
+    setup_azure_with_rg
+    create_tfvars_files
+
+    # Run all tests
+    run_standard_test_sequence
+}
+
+# Check for help flag
+case "$1" in
+    -h|--help)
+        print_help
+        exit 0
+        ;;
+esac
+
+# Execute main function
+main "$@"
-- 
GitLab


From 51b77f0f3bdaacb059c3a2cd0d601deda0607c46 Mon Sep 17 00:00:00 2001
From: danielscholl <dascholl@microsoft.com>
Date: Sun, 2 Feb 2025 19:20:39 -0600
Subject: [PATCH 08/15] chore: Update test.sh file permissions to executable

---
 infra/modules/providers/azure/app-insights/test.sh | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 mode change 100644 => 100755 infra/modules/providers/azure/app-insights/test.sh

diff --git a/infra/modules/providers/azure/app-insights/test.sh b/infra/modules/providers/azure/app-insights/test.sh
old mode 100644
new mode 100755
-- 
GitLab


From 7eeb4bab0d4412f76b6547c1a360c0f69b64a83c Mon Sep 17 00:00:00 2001
From: danielscholl <dascholl@microsoft.com>
Date: Sun, 2 Feb 2025 19:26:21 -0600
Subject: [PATCH 09/15] Reset code

---
 .../.cursor/rules/terraform-module.mdc        | 209 ++++++++++---
 .../providers/azure/app-insights/test.sh      |  93 ------
 .../providers/azure/terraform-module.mdc      | 296 ------------------
 3 files changed, 167 insertions(+), 431 deletions(-)
 delete mode 100755 infra/modules/providers/azure/app-insights/test.sh
 delete mode 100644 infra/modules/providers/azure/terraform-module.mdc

diff --git a/infra/modules/.cursor/rules/terraform-module.mdc b/infra/modules/.cursor/rules/terraform-module.mdc
index de8ea8499..97fab95d1 100644
--- a/infra/modules/.cursor/rules/terraform-module.mdc
+++ b/infra/modules/.cursor/rules/terraform-module.mdc
@@ -114,63 +114,188 @@ output "properties" {
 
 ## Testing Framework
 
-### 1. Test Script (test.sh)
-- Source common test functions
-- Implement required module functions
-- Setup configuration
-- Create tfvars files
-- Execute test sequence
+### 1. Common Test Functions Library (test-functions.sh)
+The common test functions library provides essential functionality for all module tests. Key functions include:
 
 ```bash
-#!/bin/bash
-source "../test-functions.sh"
+# Base Configuration Functions
+setup_base_configuration()     # Sets up basic test configuration
+validate_base_variables()      # Validates required environment variables
+setup_azure()                 # Basic Azure setup without resource group
+setup_azure_with_rg()         # Azure setup including resource group creation
+
+# Resource Management
+generate_unique_name()        # Generates unique resource names
+cleanup()                     # Cleans up test artifacts
+cleanup_resource_group()      # Removes Azure resource group
+
+# Test Utilities
+get_script_dir()             # Gets the current script directory
+setup_test_directories()     # Sets up test directory structure
+log()                        # Formatted logging with colors
+print_separator()            # Prints visual separator in output
+print_common_help()          # Prints standardized help message
+
+# Test Execution
+run_standard_test_sequence() # Executes the standard test suite
+```
+
+### 2. Test Script Implementation (test.sh)
+Each module must implement these required components:
+
+1. **Required Variables**
+```bash
+COMMON_LIB="../test-functions.sh"    # Path to common functions
+SCRIPT_DIR                          # Current script directory
+RESOURCE_GROUP_PREFIX               # Prefix for resource group names
+DEFAULT_LOCATION                    # Default Azure region
+RESOURCE_NAME                       # Module-specific resource name
+```
 
+2. **Required Functions**
+```bash
 setup_configuration() {
-    setup_base_configuration "$RESOURCE_GROUP_PREFIX" "$DEFAULT_LOCATION" "$@"
-    # Add module-specific configuration
+    # Must implement:
+    # 1. Call setup_base_configuration
+    # 2. Generate resource names if needed
+    # 3. Export variables for Go tests
 }
 
 create_tfvars_files() {
-    local tfvars_content="..."
-    create_base_tfvars_files "$tfvars_content"
+    # Must implement:
+    # 1. Define tfvars content
+    # 2. Call create_base_tfvars_files
+}
+
+validate_variables() {
+    # Should implement:
+    # 1. Call validate_base_variables
+    # 2. Validate module-specific variables
 }
 
-main() {
-    trap 'cleanup' EXIT
-    setup_configuration "$@"
-    validate_variables
-    setup_azure
-    create_tfvars_files
-    run_standard_test_sequence
+print_help() {
+    # Should implement:
+    # 1. Call print_common_help
+    # 2. Add module-specific help info
 }
 ```
 
-### 2. Unit Tests
-- Basic tests in testing/unit_test.go
-- Extended tests in tests/unit/
-- Validate resource attributes
-- Check resource counts
-- Verify configurations
-
-```go
-func TestTemplate(t *testing.T) {
-    testFixture := infratests.UnitTestFixture{
-        GoTest:                t,
-        TfOptions:             tfOptions,
-        ExpectedResourceCount: count,
-        ExpectedResourceAttributeValues: infratests.ResourceDescription{
-            "module.example.azurerm_example.main": expectedResult,
-        },
-    }
-    infratests.RunUnitTests(&testFixture)
+3. **Standard Error Handling**
+```bash
+# Required error handling patterns
+set -e                        # Exit on any error
+trap 'cleanup' EXIT          # Ensure cleanup on exit
+validate_azure_credentials   # Check Azure authentication
+
+# Error checking examples
+if [ ! -f "$COMMON_LIB" ]; then
+    echo "Error: Common library not found"
+    exit 1
+fi
+
+if [ -z "$REQUIRED_VAR" ]; then
+    log "Error: Required variable not set" 1
+    exit 1
+fi
+```
+
+### 3. Testing Directory Structure
+Explanation of required test files and their purposes:
+
+```
+module-name/
+├── testing/                      # Basic test configuration
+│   ├── main.tf                  # Basic test implementation
+│   │   # Required sections:
+│   │   # - Provider configuration
+│   │   # - Resource group module
+│   │   # - Module under test
+│   │   # - Required variables
+│   │
+│   └── unit_test.go            # Basic unit tests
+│       # Required tests:
+│       # - Resource count validation
+│       # - Basic attribute validation
+│       # - Required tag validation
+│
+└── tests/                       # Extended test suite
+    ├── tf_options.go           # Test configuration
+    │   # Required configuration:
+    │   # - TF_VAR environment variables
+    │   # - Terraform options
+    │   # - Test fixtures
+    │
+    ├── unit/                   # Extended unit tests
+    │   └── *_test.go          # Specific resource tests
+    │       # Should include:
+    │       # - Detailed attribute validation
+    │       # - Configuration variants
+    │       # - Error cases
+    │
+    └── integration/            # Integration tests
+        └── *_test.go          # Live resource tests
+            # Should include:
+            # - Resource creation verification
+            # - Resource update testing
+            # - Resource deletion testing
+```
+
+### 4. Common Test Patterns
+
+1. **Resource Name Generation**
+```bash
+# Standard pattern for resource names
+generate_unique_name() {
+    local prefix="$1"
+    local resource_type="$2"
+    echo "${prefix}${resource_type}${RANDOM}"
+}
+
+# Usage example
+STORAGE_ACCOUNT_NAME=$(generate_unique_name "" "sa")
+LOG_ANALYTICS_NAME=$(generate_unique_name "" "logs")
+```
+
+2. **Variable Validation**
+```bash
+validate_variables() {
+    validate_base_variables
+
+    # Resource name validation
+    if [[ ! "$RESOURCE_NAME" =~ ^[a-z0-9]+$ ]]; then
+        log "Error: Resource name must be lowercase alphanumeric" 1
+        exit 1
+    fi
+
+    # Location validation
+    if [[ ! "$LOCATION" =~ ^[a-z]+[a-z0-9]+$ ]]; then
+        log "Error: Invalid location format" 1
+        exit 1
+    fi
 }
 ```
 
-### 3. Integration Tests
-- Implement in tests/integration/
-- Test actual resource creation
-- Verify resource properties
-- Clean up resources after tests
+3. **Terraform Variable File Creation**
+```bash
+create_tfvars_files() {
+    # Standard format for tfvars content
+    local tfvars_content="
+name                = \"$RESOURCE_NAME\"
+resource_group_name = \"$RESOURCE_GROUP_NAME\"
+location            = \"$LOCATION\"
+
+# Optional configurations
+tags = {
+    environment = \"testing\"
+    module     = \"example\"
+}
+
+# Resource-specific configurations
+specific_setting = \"value\"
+"
+    create_base_tfvars_files "$tfvars_content"
+}
+```
 
 ## Documentation
 
diff --git a/infra/modules/providers/azure/app-insights/test.sh b/infra/modules/providers/azure/app-insights/test.sh
deleted file mode 100755
index 41bc31d42..000000000
--- a/infra/modules/providers/azure/app-insights/test.sh
+++ /dev/null
@@ -1,93 +0,0 @@
-#!/bin/bash
-
-# Exit on error
-set -e
-
-###############################
-# Source Common Functions
-###############################
-COMMON_LIB="../../test-functions.sh"
-if [ ! -f "$COMMON_LIB" ]; then
-    echo "Error: Common library not found at $COMMON_LIB"
-    exit 1
-fi
-source "$COMMON_LIB"
-
-###############################
-# Script Configuration
-###############################
-SCRIPT_DIR=$(get_script_dir)
-setup_test_directories "$SCRIPT_DIR"
-
-###############################
-# Required Environment Variables
-###############################
-validate_azure_credentials
-
-###############################
-# Optional Variables
-###############################
-# These can be overridden by setting them before running the script
-RESOURCE_GROUP_PREFIX=${RESOURCE_GROUP_PREFIX:-"app-insights-test"}
-DEFAULT_LOCATION="eastus2"
-
-###############################
-# Help Documentation
-###############################
-print_help() {
-    print_common_help "App Insights"
-}
-
-###############################
-# Required Module Functions
-###############################
-setup_configuration() {
-    # Setup base configuration
-    setup_base_configuration "$RESOURCE_GROUP_PREFIX" "$DEFAULT_LOCATION" "$@"
-    export APP_INSIGHTS_NAME="${RESOURCE_GROUP_NAME}-app-insights"
-}
-
-create_tfvars_files() {
-    local tfvars_content="
-appinsights_name                 = \"${APP_INSIGHTS_NAME}\"
-service_plan_resource_group_name = \"${RESOURCE_GROUP_NAME}\"
-appinsights_application_type     = \"java\"
-resource_tags = {
-  environment = \"testing\"
-  module      = \"app-insights\"
-}
-"
-    create_base_tfvars_files "$tfvars_content"
-}
-
-###############################
-# Main Execution
-###############################
-main() {
-    # Trap cleanup on exit
-    trap 'cleanup; cleanup_resource_group "$RESOURCE_GROUP_NAME" "$ARM_SUBSCRIPTION_ID"' EXIT
-
-    # Setup configuration
-    setup_configuration "$@"
-
-    # Validate variables
-    validate_base_variables
-
-    # Setup
-    setup_azure_with_rg
-    create_tfvars_files
-
-    # Run all tests
-    run_standard_test_sequence
-}
-
-# Check for help flag
-case "$1" in
-    -h|--help)
-        print_help
-        exit 0
-        ;;
-esac
-
-# Execute main function
-main "$@"
diff --git a/infra/modules/providers/azure/terraform-module.mdc b/infra/modules/providers/azure/terraform-module.mdc
deleted file mode 100644
index 97b4e1052..000000000
--- a/infra/modules/providers/azure/terraform-module.mdc
+++ /dev/null
@@ -1,296 +0,0 @@
-# Terraform Module Development Guidelines
-
-This document outlines the standards and patterns for developing Terraform modules in our infrastructure codebase.
-
-## Module Structure
-
-```
-module-name/
-├── README.md           # Module documentation
-├── main.tf            # Main module configuration
-├── variables.tf       # Input variable definitions
-├── outputs.tf         # Output definitions
-├── test.sh           # Test execution script
-├── testing/          # Basic test configuration
-│   ├── main.tf       # Test implementation
-│   └── unit_test.go  # Basic unit tests
-└── tests/            # Extended test suite
-    ├── .env.testing.template  # Environment variables template
-    ├── tf_options.go          # Common test configuration
-    ├── unit/                  # Extended unit tests
-    │   └── *_test.go
-    └── integration/           # Integration tests
-        └── *_test.go
-```
-
-## Code Organization
-
-### 1. Main Configuration (main.tf)
-- Start with required provider configuration
-- Include copyright header
-- Group resources logically
-- Use data sources for existing resources
-- Implement resource configurations
-- Use dynamic blocks for optional features
-
-```hcl
-terraform {
-  required_providers {
-    azurerm = {
-      source  = "hashicorp/azurerm"
-      version = "=3.90.0"  # Pin to specific version
-    }
-  }
-}
-
-provider "azurerm" {
-  features {}
-}
-
-data "azurerm_resource_group" "main" {
-  name = var.resource_group_name
-}
-
-resource "azurerm_example" "main" {
-  name                = var.name
-  resource_group_name = data.azurerm_resource_group.main.name
-  location            = data.azurerm_resource_group.main.location
-
-  dynamic "optional_block" {
-    for_each = var.optional_feature_enabled ? [1] : []
-    content {
-      // Configuration
-    }
-  }
-}
-```
-
-### 2. Variables (variables.tf)
-- Group variables by purpose
-- Include clear descriptions
-- Provide type constraints
-- Set defaults where appropriate
-- Mark sensitive variables
-
-```hcl
-variable "name" {
-  description = "The name of the resource"
-  type        = string
-}
-
-variable "resource_tags" {
-  description = "Map of tags to apply to resources"
-  type        = map(string)
-  default     = {}
-}
-```
-
-### 3. Outputs (outputs.tf)
-- Include essential resource information
-- Mark sensitive outputs
-- Group related outputs
-- Use maps for collections
-- Include resource IDs and names
-
-```hcl
-output "id" {
-  description = "The ID of the created resource"
-  value       = azurerm_example.main.id
-}
-
-output "properties" {
-  description = "Properties of the deployed resource"
-  value = {
-    id   = azurerm_example.main.id
-    name = azurerm_example.main.name
-  }
-  sensitive = true
-}
-```
-
-## Testing Framework
-
-### 1. Common Test Functions Library (test-functions.sh)
-The common test functions library provides essential functionality for all module tests. Key functions include:
-
-```bash
-# Base Configuration Functions
-setup_base_configuration()     # Sets up basic test configuration
-validate_base_variables()      # Validates required environment variables
-setup_azure()                 # Basic Azure setup without resource group
-setup_azure_with_rg()         # Azure setup including resource group creation
-
-# Resource Management
-generate_unique_name()        # Generates unique resource names
-cleanup()                     # Cleans up test artifacts
-cleanup_resource_group()      # Removes Azure resource group
-
-# Test Utilities
-get_script_dir()             # Gets the current script directory
-setup_test_directories()     # Sets up test directory structure
-log()                        # Formatted logging with colors
-print_separator()            # Prints visual separator in output
-print_common_help()          # Prints standardized help message
-
-# Test Execution
-run_standard_test_sequence() # Executes the standard test suite
-```
-
-### 2. Test Script Implementation (test.sh)
-Each module must implement these required components:
-
-1. **Required Variables**
-```bash
-COMMON_LIB="../test-functions.sh"    # Path to common functions
-SCRIPT_DIR                          # Current script directory
-RESOURCE_GROUP_PREFIX               # Prefix for resource group names
-DEFAULT_LOCATION                    # Default Azure region
-RESOURCE_NAME                       # Module-specific resource name
-```
-
-2. **Required Functions**
-```bash
-setup_configuration() {
-    # Must implement:
-    # 1. Call setup_base_configuration
-    # 2. Generate resource names if needed
-    # 3. Export variables for Go tests
-}
-
-create_tfvars_files() {
-    # Must implement:
-    # 1. Define tfvars content
-    # 2. Call create_base_tfvars_files
-}
-
-validate_variables() {
-    # Should implement:
-    # 1. Call validate_base_variables
-    # 2. Validate module-specific variables
-}
-
-print_help() {
-    # Should implement:
-    # 1. Call print_common_help
-    # 2. Add module-specific help info
-}
-```
-
-3. **Standard Error Handling**
-```bash
-# Required error handling patterns
-set -e                        # Exit on any error
-trap 'cleanup' EXIT          # Ensure cleanup on exit
-validate_azure_credentials   # Check Azure authentication
-
-# Error checking examples
-if [ ! -f "$COMMON_LIB" ]; then
-    echo "Error: Common library not found"
-    exit 1
-fi
-
-if [ -z "$REQUIRED_VAR" ]; then
-    log "Error: Required variable not set" 1
-    exit 1
-fi
-```
-
-### 3. Testing Directory Structure
-Explanation of required test files and their purposes:
-
-```
-module-name/
-├── testing/                      # Basic test configuration
-│   ├── main.tf                  # Basic test implementation
-│   │   # Required sections:
-│   │   # - Provider configuration
-│   │   # - Resource group module
-│   │   # - Module under test
-│   │   # - Required variables
-│   │
-│   └── unit_test.go            # Basic unit tests
-│       # Required tests:
-│       # - Resource count validation
-│       # - Basic attribute validation
-│       # - Required tag validation
-│
-└── tests/                       # Extended test suite
-    ├── tf_options.go           # Test configuration
-    │   # Required configuration:
-    │   # - TF_VAR environment variables
-    │   # - Terraform options
-    │   # - Test fixtures
-    │
-    ├── unit/                   # Extended unit tests
-    │   └── *_test.go          # Specific resource tests
-    │       # Should include:
-    │       # - Detailed attribute validation
-    │       # - Configuration variants
-    │       # - Error cases
-    │
-    └── integration/            # Integration tests
-        └── *_test.go          # Live resource tests
-            # Should include:
-            # - Resource creation verification
-            # - Resource update testing
-            # - Resource deletion testing
-```
-
-### 4. Common Test Patterns
-
-1. **Resource Name Generation**
-```bash
-# Standard pattern for resource names
-generate_unique_name() {
-    local prefix="$1"
-    local resource_type="$2"
-    echo "${prefix}${resource_type}${RANDOM}"
-}
-
-# Usage example
-STORAGE_ACCOUNT_NAME=$(generate_unique_name "" "sa")
-LOG_ANALYTICS_NAME=$(generate_unique_name "" "logs")
-```
-
-2. **Variable Validation**
-```bash
-validate_variables() {
-    validate_base_variables
-
-    # Resource name validation
-    if [[ ! "$RESOURCE_NAME" =~ ^[a-z0-9]+$ ]]; then
-        log "Error: Resource name must be lowercase alphanumeric" 1
-        exit 1
-    fi
-
-    # Location validation
-    if [[ ! "$LOCATION" =~ ^[a-z]+[a-z0-9]+$ ]]; then
-        log "Error: Invalid location format" 1
-        exit 1
-    fi
-}
-```
-
-3. **Terraform Variable File Creation**
-```bash
-create_tfvars_files() {
-    # Standard format for tfvars content
-    local tfvars_content="
-name                = \"$RESOURCE_NAME\"
-resource_group_name = \"$RESOURCE_GROUP_NAME\"
-location            = \"$LOCATION\"
-
-# Optional configurations
-tags = {
-    environment = \"testing\"
-    module     = \"example\"
-}
-
-# Resource-specific configurations
-specific_setting = \"value\"
-"
-    create_base_tfvars_files "$tfvars_content"
-}
-```
-
-// ... rest of the file remains unchanged ... 
\ No newline at end of file
-- 
GitLab


From 291f57874aaad63a1e678b20a29726b5bf924a97 Mon Sep 17 00:00:00 2001
From: danielscholl <dascholl@microsoft.com>
Date: Sun, 2 Feb 2025 19:56:17 -0600
Subject: [PATCH 10/15] Updated rules

---
 .../.cursor/rules/terraform-module.mdc        | 23 ++-----------------
 1 file changed, 2 insertions(+), 21 deletions(-)

diff --git a/infra/modules/.cursor/rules/terraform-module.mdc b/infra/modules/.cursor/rules/terraform-module.mdc
index 97fab95d1..69654a5af 100644
--- a/infra/modules/.cursor/rules/terraform-module.mdc
+++ b/infra/modules/.cursor/rules/terraform-module.mdc
@@ -117,27 +117,8 @@ output "properties" {
 ### 1. Common Test Functions Library (test-functions.sh)
 The common test functions library provides essential functionality for all module tests. Key functions include:
 
-```bash
-# Base Configuration Functions
-setup_base_configuration()     # Sets up basic test configuration
-validate_base_variables()      # Validates required environment variables
-setup_azure()                 # Basic Azure setup without resource group
-setup_azure_with_rg()         # Azure setup including resource group creation
-
-# Resource Management
-generate_unique_name()        # Generates unique resource names
-cleanup()                     # Cleans up test artifacts
-cleanup_resource_group()      # Removes Azure resource group
-
-# Test Utilities
-get_script_dir()             # Gets the current script directory
-setup_test_directories()     # Sets up test directory structure
-log()                        # Formatted logging with colors
-print_separator()            # Prints visual separator in output
-print_common_help()          # Prints standardized help message
-
-# Test Execution
-run_standard_test_sequence() # Executes the standard test suite
+Note: The `test-functions.sh` script should be sourced into test scripts using the relative path `../test-functions.sh`.
+
 ```
 
 ### 2. Test Script Implementation (test.sh)
-- 
GitLab


From ed902228e3c57fd06c81fdcfbbbb972ffb857c8e Mon Sep 17 00:00:00 2001
From: "danielscholl (aider)" <dascholl@microsoft.com>
Date: Sun, 2 Feb 2025 19:59:41 -0600
Subject: [PATCH 11/15] feat: Add executable test script for app-insights
 module following guidelines

---
 .../providers/azure/app-insights/test.sh      | 89 +++++++++++++++++++
 1 file changed, 89 insertions(+)
 create mode 100644 infra/modules/providers/azure/app-insights/test.sh

diff --git a/infra/modules/providers/azure/app-insights/test.sh b/infra/modules/providers/azure/app-insights/test.sh
new file mode 100644
index 000000000..7b6a2ff66
--- /dev/null
+++ b/infra/modules/providers/azure/app-insights/test.sh
@@ -0,0 +1,89 @@
+#!/bin/bash
+
+# Exit on error
+set -e
+
+###############################
+# Source Common Functions
+###############################
+COMMON_LIB="../test-functions.sh"
+if [ ! -f "$COMMON_LIB" ]; then
+    echo "Error: Common library not found at $COMMON_LIB"
+    exit 1
+fi
+source "$COMMON_LIB"
+
+
+###############################
+# Script Configuration
+###############################
+SCRIPT_DIR=$(get_script_dir)
+setup_test_directories "$SCRIPT_DIR"
+
+
+###############################
+# Required Environment Variables
+###############################
+validate_azure_credentials
+
+
+###############################
+# Optional Variables
+###############################
+# These can be overridden by setting them before running the script
+RESOURCE_GROUP_PREFIX=${RESOURCE_GROUP_PREFIX:-"terraform-test"}
+DEFAULT_LOCATION="eastus2"
+
+
+###############################
+# Help Documentation
+###############################
+print_help() {
+    print_common_help "App Insights"
+}
+
+
+###############################
+# Required Module Functions
+###############################
+setup_configuration() {
+    # Setup base configuration
+    setup_base_configuration "$RESOURCE_GROUP_PREFIX" "$DEFAULT_LOCATION" "$@"
+}
+
+create_tfvars_files() {
+    local tfvars_content="appinsights_name = \"${RESOURCE_GROUP_NAME}-app-insights\"\nlocation = \"$LOCATION\"\nservice_plan_resource_group_name = \"$RESOURCE_GROUP_NAME\""
+    create_base_tfvars_files "$tfvars_content"
+}
+
+###############################
+# Main Execution
+###############################
+main() {
+    # Trap cleanup on exit
+    trap 'cleanup; cleanup_resource_group "$RESOURCE_GROUP_NAME" "$ARM_SUBSCRIPTION_ID"' EXIT
+
+    # Setup configuration
+    setup_configuration "$@"
+
+    # Validate variables
+    validate_base_variables
+
+    # Setup
+    setup_azure
+    create_tfvars_files
+
+    # Run all tests
+    run_standard_test_sequence
+}
+
+# Check for help flag
+case "$1" in
+    -h|--help)
+        print_help
+        exit 0
+        ;;
+esac
+
+# Execute main function
+main "$@"
-- 
GitLab


From 95f3cfc03a75899b54bb33fbd7fce584ea71ff50 Mon Sep 17 00:00:00 2001
From: danielscholl <dascholl@microsoft.com>
Date: Sun, 2 Feb 2025 20:03:01 -0600
Subject: [PATCH 12/15] chore: Update file permissions for test.sh in
 app-insights module

---
 infra/modules/providers/azure/app-insights/test.sh | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 mode change 100644 => 100755 infra/modules/providers/azure/app-insights/test.sh

diff --git a/infra/modules/providers/azure/app-insights/test.sh b/infra/modules/providers/azure/app-insights/test.sh
old mode 100644
new mode 100755
-- 
GitLab


From cca2184d7d4adc155775849afe5b0feb419821aa Mon Sep 17 00:00:00 2001
From: danielscholl <dascholl@microsoft.com>
Date: Mon, 3 Feb 2025 14:21:38 -0600
Subject: [PATCH 13/15] Fixed lint errors.

---
 infra/modules/magefile.go | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/infra/modules/magefile.go b/infra/modules/magefile.go
index 89ef8cb08..ee1a48271 100644
--- a/infra/modules/magefile.go
+++ b/infra/modules/magefile.go
@@ -27,7 +27,6 @@ func TestModules() error {
 	return FindAndRunTests("testing")
 }
 
-
 // Validate both Terraform code and Go code.
 func Check() {
 	mg.Deps(LintTF)
@@ -178,7 +177,7 @@ func Test(module string) error {
 		"SCRIPT_DIR":          moduleDir,
 		"ARM_SUBSCRIPTION_ID": os.Getenv("ARM_SUBSCRIPTION_ID"),
 		"RESOURCE_GROUP_NAME": os.Getenv("RESOURCE_GROUP_NAME"),
-		"LOCATION":           os.Getenv("LOCATION"),
+		"LOCATION":            os.Getenv("LOCATION"),
 	}
 
 	// Set the environment variables
-- 
GitLab


From ea247c80d6bfa3b82832dd39bbc5956d1f32d334 Mon Sep 17 00:00:00 2001
From: danielscholl <dascholl@microsoft.com>
Date: Mon, 3 Feb 2025 17:16:31 -0600
Subject: [PATCH 14/15] Fixed the initial module tests so they all pass.

---
 .../providers/azure/app-insights/test.sh      | 82 +++++++++++++++++--
 .../azure/app-insights/testing/main.tf        | 10 +++
 .../azure/app-insights/testing/unit_test.go   |  2 +-
 .../azure/storage-account/tests/tf_options.go | 10 ++-
 4 files changed, 96 insertions(+), 8 deletions(-)

diff --git a/infra/modules/providers/azure/app-insights/test.sh b/infra/modules/providers/azure/app-insights/test.sh
index 7b6a2ff66..c1a76e265 100755
--- a/infra/modules/providers/azure/app-insights/test.sh
+++ b/infra/modules/providers/azure/app-insights/test.sh
@@ -33,13 +33,18 @@ validate_azure_credentials
 # These can be overridden by setting them before running the script
 RESOURCE_GROUP_PREFIX=${RESOURCE_GROUP_PREFIX:-"terraform-test"}
 DEFAULT_LOCATION="eastus2"
+APP_INSIGHTS_NAME=${APP_INSIGHTS_NAME:-""}  # Will be auto-generated if not provided
+APP_INSIGHTS_TYPE=${APP_INSIGHTS_TYPE:-"web"}  # Default to web application type
+
+# Workspace ID should be a full resource ID
+WORKSPACE_ID=${WORKSPACE_ID:-""}  # Will be auto-generated if not provided
 
 
 ###############################
 # Help Documentation
 ###############################
 print_help() {
-    print_common_help "App Insights"
+    print_common_help "App Insights" "\n- If not specified, a unique App Insights name will be generated\n- Default application type is 'web'\n- A Log Analytics workspace will be created for testing"
 }
 
 
@@ -47,15 +52,80 @@ print_help() {
 # Required Module Functions
 ###############################
 setup_configuration() {
-    # Setup base configuration
+    # Setup base configuration first
     setup_base_configuration "$RESOURCE_GROUP_PREFIX" "$DEFAULT_LOCATION" "$@"
+
+    # Generate App Insights name if not provided
+    if [ -z "$APP_INSIGHTS_NAME" ]; then
+        APP_INSIGHTS_NAME=$(generate_unique_name "" "ai")
+    fi
+
+    # Generate workspace ID if not provided
+    if [ -z "$WORKSPACE_ID" ]; then
+        local workspace_name=$(generate_unique_name "" "log")
+        WORKSPACE_ID="/subscriptions/$ARM_SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP_NAME/providers/Microsoft.OperationalInsights/workspaces/$workspace_name"
+    fi
+
+    # Export additional variables for Go tests
+    export APP_INSIGHTS_NAME
+    export WORKSPACE_ID
+    export APP_INSIGHTS_TYPE
 }
 
 create_tfvars_files() {
-    local tfvars_content="appinsights_name = \"${RESOURCE_GROUP_NAME}-app-insights\"\nlocation = \"$LOCATION\"\nservice_plan_resource_group_name = \"$RESOURCE_GROUP_NAME\""
+    local tfvars_content="
+appinsights_name = \"$APP_INSIGHTS_NAME\"
+service_plan_resource_group_name = \"$RESOURCE_GROUP_NAME\"
+appinsights_application_type = \"$APP_INSIGHTS_TYPE\"
+workspace_id = \"$WORKSPACE_ID\"
+
+resource_tags = {
+    environment = \"testing\"
+    module     = \"app-insights\"
+}"
     create_base_tfvars_files "$tfvars_content"
 }
 
+
+###############################
+# Optional Module Functions
+###############################
+validate_variables() {
+    validate_base_variables
+
+    # Validate App Insights specific variables
+    if [[ ! "$APP_INSIGHTS_NAME" =~ ^[a-zA-Z0-9-]+$ ]]; then
+        log "Error: App Insights name must be alphanumeric with hyphens" 1
+        exit 1
+    fi
+
+    # Validate application type
+    local valid_types=("ios" "java" "MobileCenter" "Node.JS" "other" "phone" "store" "web")
+    local type_valid=false
+    for valid_type in "${valid_types[@]}"; do
+        if [ "$APP_INSIGHTS_TYPE" == "$valid_type" ]; then
+            type_valid=true
+            break
+        fi
+    done
+
+    if [ "$type_valid" != true ]; then
+        log "Error: Invalid application type. Must be one of: ${valid_types[*]}" 1
+        exit 1
+    fi
+
+    # Validate workspace ID format
+    if [[ ! "$WORKSPACE_ID" =~ ^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft.OperationalInsights/workspaces/[^/]+$ ]]; then
+        log "Error: Invalid workspace ID format. Expected format: /subscriptions/{subscription_id}/resourceGroups/{resource_group}/providers/Microsoft.OperationalInsights/workspaces/{workspace_name}" 1
+        exit 1
+    fi
+
+    log "Using App Insights: $APP_INSIGHTS_NAME" 6
+    log "Using Application Type: $APP_INSIGHTS_TYPE" 6
+    log "Using Workspace ID: $WORKSPACE_ID" 6
+}
+
+
 ###############################
 # Main Execution
 ###############################
@@ -67,10 +137,10 @@ main() {
     setup_configuration "$@"
 
     # Validate variables
-    validate_base_variables
+    validate_variables
 
     # Setup
-    setup_azure
+    setup_azure_with_rg
     create_tfvars_files
 
     # Run all tests
@@ -86,4 +156,4 @@ case "$1" in
 esac
 
 # Execute main function
-main "$@"
+main "$@"
\ No newline at end of file
diff --git a/infra/modules/providers/azure/app-insights/testing/main.tf b/infra/modules/providers/azure/app-insights/testing/main.tf
index 8c024156b..4a025f1e0 100644
--- a/infra/modules/providers/azure/app-insights/testing/main.tf
+++ b/infra/modules/providers/azure/app-insights/testing/main.tf
@@ -23,6 +23,15 @@ module "resource_group" {
   location = "eastus2"
 }
 
+# Create Log Analytics workspace for App Insights
+resource "azurerm_log_analytics_workspace" "test" {
+  name                = "osdu-module-workspace-${module.resource_group.random}"
+  resource_group_name = module.resource_group.name
+  location           = module.resource_group.location
+  sku               = "PerGB2018"
+  retention_in_days = 30
+}
+
 module "app-insights" {
   source     = "../"
   depends_on = [module.resource_group]
@@ -30,6 +39,7 @@ module "app-insights" {
   appinsights_name                 = "osdu-module-app-insights-${module.resource_group.random}"
   service_plan_resource_group_name = module.resource_group.name
   appinsights_application_type     = "java"
+  workspace_id                     = azurerm_log_analytics_workspace.test.id
 
   resource_tags = {
     osdu = "module"
diff --git a/infra/modules/providers/azure/app-insights/testing/unit_test.go b/infra/modules/providers/azure/app-insights/testing/unit_test.go
index df35af7e4..dc9c0b9c3 100644
--- a/infra/modules/providers/azure/app-insights/testing/unit_test.go
+++ b/infra/modules/providers/azure/app-insights/testing/unit_test.go
@@ -12,7 +12,7 @@ import (
 
 var workspace = "osdu-services-" + strings.ToLower(random.UniqueId())
 var location = "eastus"
-var count = 4
+var count = 5
 
 var tfOptions = &terraform.Options{
 	TerraformDir: "./",
diff --git a/infra/modules/providers/azure/storage-account/tests/tf_options.go b/infra/modules/providers/azure/storage-account/tests/tf_options.go
index 370f857eb..a3479f52f 100644
--- a/infra/modules/providers/azure/storage-account/tests/tf_options.go
+++ b/infra/modules/providers/azure/storage-account/tests/tf_options.go
@@ -24,11 +24,19 @@ import (
 var StorageAccount = os.Getenv("STORAGE_ACCOUNT_NAME")
 
 // ContainerName - The Container Name
-var ContainerName = os.Getenv("CONTAINER_NAME")
+var ContainerName = getContainerName()
 
 // ResourceGroupName - The Resource Group Name
 var ResourceGroupName = os.Getenv("RESOURCE_GROUP_NAME")
 
+// getContainerName returns the container name from env var or a default value
+func getContainerName() string {
+	if name := os.Getenv("CONTAINER_NAME"); name != "" {
+		return name
+	}
+	return "test-container"
+}
+
 // StorageTFOptions common terraform options used for unit testing
 var StorageTFOptions = &terraform.Options{
 	TerraformDir: "../../", // Point to module directory for unit tests
-- 
GitLab


From feffa91d089be2c81da1ba01a4ab45d256fb5912 Mon Sep 17 00:00:00 2001
From: danielscholl <dascholl@microsoft.com>
Date: Mon, 3 Feb 2025 18:30:10 -0600
Subject: [PATCH 15/15] Lint Checked

---
 infra/modules/providers/azure/app-insights/testing/main.tf | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/infra/modules/providers/azure/app-insights/testing/main.tf b/infra/modules/providers/azure/app-insights/testing/main.tf
index 4a025f1e0..65b7257b6 100644
--- a/infra/modules/providers/azure/app-insights/testing/main.tf
+++ b/infra/modules/providers/azure/app-insights/testing/main.tf
@@ -27,9 +27,9 @@ module "resource_group" {
 resource "azurerm_log_analytics_workspace" "test" {
   name                = "osdu-module-workspace-${module.resource_group.random}"
   resource_group_name = module.resource_group.name
-  location           = module.resource_group.location
-  sku               = "PerGB2018"
-  retention_in_days = 30
+  location            = module.resource_group.location
+  sku                 = "PerGB2018"
+  retention_in_days   = 30
 }
 
 module "app-insights" {
-- 
GitLab