feat: add comprehensive CRUD tests for probe, label, monitor status, and incident severity resources

This commit is contained in:
Nawaz Dhandala
2026-01-19 17:21:10 +00:00
parent 120d36f3dd
commit d7f329fcff
13 changed files with 627 additions and 3 deletions

8
.gitignore vendored
View File

@@ -130,3 +130,11 @@ Dashboard/public/sw.js
.claude/settings.local.json
Common/.claude/settings.local.json
E2E/Terraform/e2e-tests/test-env.sh
# Terraform state and plan files
*.tfplan
tfplan
terraform.tfstate
terraform.tfstate.backup
.terraform/
.terraform.lock.hcl

View File

@@ -41,11 +41,16 @@ echo "=== Step 6: Setting up test account ==="
cd "$TEST_DIR"
"$SCRIPT_DIR/setup-test-account.sh"
# Step 7: Run tests
# Step 7: Run basic tests
echo ""
echo "=== Step 7: Running Terraform E2E Tests ==="
"$SCRIPT_DIR/run-tests.sh"
# Step 8: Run CRUD tests (create, update, API validation, destroy)
echo ""
echo "=== Step 8: Running Terraform CRUD Tests ==="
"$SCRIPT_DIR/run-crud-tests.sh"
echo ""
echo "=========================================="
echo "E2E Tests Completed Successfully!"

View File

@@ -0,0 +1,323 @@
#!/bin/bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TEST_DIR="$(dirname "$SCRIPT_DIR")"
PROVIDER_DIR="$TEST_DIR/../../../Terraform/terraform-provider-oneuptime"
# Load test environment
source "$TEST_DIR/test-env.sh"
echo "=== Running Terraform CRUD E2E Tests ==="
echo "OneUptime URL: $ONEUPTIME_URL"
echo "Project ID: $ONEUPTIME_PROJECT_ID"
# Build and install provider locally
echo ""
echo "=== Building Terraform Provider ==="
cd "$PROVIDER_DIR"
go mod tidy
go build -o terraform-provider-oneuptime
# Install provider
OS=$(go env GOOS)
ARCH=$(go env GOARCH)
INSTALL_DIR="$HOME/.terraform.d/plugins/registry.terraform.io/oneuptime/oneuptime/1.0.0/${OS}_${ARCH}"
mkdir -p "$INSTALL_DIR"
cp terraform-provider-oneuptime "$INSTALL_DIR/"
echo "Provider installed to: $INSTALL_DIR"
# Helper function to validate resource via API
validate_api() {
local endpoint="$1"
local resource_id="$2"
local expected_field="$3"
local expected_value="$4"
echo " Validating via API: GET $endpoint/$resource_id"
local response=$(curl -sf -X POST "${ONEUPTIME_URL}/api${endpoint}/${resource_id}/get-item" \
-H "Content-Type: application/json" \
-H "Apikey: $TF_VAR_api_key" \
-H "projectid: $TF_VAR_project_id" \
-d "{\"select\": {\"${expected_field}\": true}}" 2>&1)
if [ $? -ne 0 ]; then
echo " API validation FAILED: Could not fetch resource"
return 1
fi
# Extract the value - handle both direct string and wrapper object formats
local actual_value=$(echo "$response" | jq -r ".data.${expected_field} // .${expected_field}" 2>/dev/null)
# Handle wrapper object format (e.g., {"_type":"...", "value":"..."})
if echo "$actual_value" | jq -e '.value' > /dev/null 2>&1; then
actual_value=$(echo "$actual_value" | jq -r '.value')
fi
if [ "$actual_value" = "$expected_value" ]; then
echo " API validation PASSED: $expected_field = '$expected_value'"
return 0
else
echo " API validation FAILED: Expected $expected_field='$expected_value', got '$actual_value'"
return 1
fi
}
PASSED=()
FAILED=()
#######################################
# Test 1: Label CRUD
#######################################
echo ""
echo "=========================================="
echo "CRUD Test: Label"
echo "=========================================="
test_path="$TEST_DIR/tests/09-label-crud"
cd "$test_path"
rm -f tfplan terraform.tfstate terraform.tfstate.backup
# Step 1: Create
echo " [1/6] Creating label..."
if ! terraform plan -out=tfplan \
-var="label_name=terraform-crud-label" \
-var="label_description=Initial description" \
-var="label_color=#FF0000" 2>&1; then
echo " FAILED: Plan failed"
FAILED+=("09-label-crud (create plan)")
else
if ! terraform apply -auto-approve tfplan 2>&1; then
echo " FAILED: Apply failed"
FAILED+=("09-label-crud (create apply)")
else
LABEL_ID=$(terraform output -raw label_id)
echo " Created label ID: $LABEL_ID"
# Step 2: Validate via API after create
echo " [2/6] Validating creation via API..."
if validate_api "/label" "$LABEL_ID" "name" "terraform-crud-label"; then
# Step 3: Update
echo " [3/6] Updating label..."
if ! terraform plan -out=tfplan \
-var="label_name=terraform-crud-label-updated" \
-var="label_description=Updated description" \
-var="label_color=#00FF00" 2>&1; then
echo " FAILED: Update plan failed"
FAILED+=("09-label-crud (update plan)")
else
if ! terraform apply -auto-approve tfplan 2>&1; then
echo " FAILED: Update apply failed"
FAILED+=("09-label-crud (update apply)")
else
echo " Label updated successfully"
# Step 4: Validate via API after update
echo " [4/6] Validating update via API..."
if validate_api "/label" "$LABEL_ID" "name" "terraform-crud-label-updated"; then
# Step 5: Verify color was updated
echo " [5/6] Validating color update via API..."
if validate_api "/label" "$LABEL_ID" "color" "#00FF00"; then
PASSED+=("09-label-crud")
else
FAILED+=("09-label-crud (color validation)")
fi
else
FAILED+=("09-label-crud (update validation)")
fi
fi
fi
else
FAILED+=("09-label-crud (create validation)")
fi
# Step 6: Destroy
echo " [6/6] Destroying label..."
terraform destroy -auto-approve \
-var="label_name=terraform-crud-label-updated" \
-var="label_description=Updated description" \
-var="label_color=#00FF00" 2>&1 || true
fi
fi
rm -f tfplan terraform.tfstate terraform.tfstate.backup
#######################################
# Test 2: Monitor Status CRUD
#######################################
echo ""
echo "=========================================="
echo "CRUD Test: Monitor Status"
echo "=========================================="
test_path="$TEST_DIR/tests/10-monitor-status-crud"
cd "$test_path"
rm -f tfplan terraform.tfstate terraform.tfstate.backup
# Step 1: Create
echo " [1/6] Creating monitor status..."
if ! terraform plan -out=tfplan \
-var="status_name=terraform-crud-status" \
-var="status_description=Initial status description" \
-var="status_color=#00FF00" \
-var="status_priority=100" 2>&1; then
echo " FAILED: Plan failed"
FAILED+=("10-monitor-status-crud (create plan)")
else
if ! terraform apply -auto-approve tfplan 2>&1; then
echo " FAILED: Apply failed"
FAILED+=("10-monitor-status-crud (create apply)")
else
STATUS_ID=$(terraform output -raw monitor_status_id)
echo " Created monitor status ID: $STATUS_ID"
# Step 2: Validate via API after create
echo " [2/6] Validating creation via API..."
if validate_api "/monitor-status" "$STATUS_ID" "name" "terraform-crud-status"; then
# Step 3: Update (note: priority cannot be updated per API restriction)
echo " [3/6] Updating monitor status..."
if ! terraform plan -out=tfplan \
-var="status_name=terraform-crud-status-updated" \
-var="status_description=Updated status description" \
-var="status_color=#0000FF" \
-var="status_priority=100" 2>&1; then
echo " FAILED: Update plan failed"
FAILED+=("10-monitor-status-crud (update plan)")
else
if ! terraform apply -auto-approve tfplan 2>&1; then
echo " FAILED: Update apply failed"
FAILED+=("10-monitor-status-crud (update apply)")
else
echo " Monitor status updated successfully"
# Step 4: Validate via API after update
echo " [4/6] Validating update via API..."
if validate_api "/monitor-status" "$STATUS_ID" "name" "terraform-crud-status-updated"; then
# Step 5: Verify color was updated
echo " [5/6] Validating color update via API..."
if validate_api "/monitor-status" "$STATUS_ID" "color" "#0000FF"; then
PASSED+=("10-monitor-status-crud")
else
FAILED+=("10-monitor-status-crud (color validation)")
fi
else
FAILED+=("10-monitor-status-crud (update validation)")
fi
fi
fi
else
FAILED+=("10-monitor-status-crud (create validation)")
fi
# Step 6: Destroy
echo " [6/6] Destroying monitor status..."
terraform destroy -auto-approve \
-var="status_name=terraform-crud-status-updated" \
-var="status_description=Updated status description" \
-var="status_color=#0000FF" \
-var="status_priority=100" 2>&1 || true
fi
fi
rm -f tfplan terraform.tfstate terraform.tfstate.backup
#######################################
# Test 3: Incident Severity CRUD
#######################################
echo ""
echo "=========================================="
echo "CRUD Test: Incident Severity"
echo "=========================================="
test_path="$TEST_DIR/tests/11-incident-severity-crud"
cd "$test_path"
rm -f tfplan terraform.tfstate terraform.tfstate.backup
# Step 1: Create
echo " [1/6] Creating incident severity..."
if ! terraform plan -out=tfplan \
-var="severity_name=terraform-crud-severity" \
-var="severity_description=Initial severity description" \
-var="severity_color=#FFA500" \
-var="severity_order=100" 2>&1; then
echo " FAILED: Plan failed"
FAILED+=("11-incident-severity-crud (create plan)")
else
if ! terraform apply -auto-approve tfplan 2>&1; then
echo " FAILED: Apply failed"
FAILED+=("11-incident-severity-crud (create apply)")
else
SEVERITY_ID=$(terraform output -raw incident_severity_id)
echo " Created incident severity ID: $SEVERITY_ID"
# Step 2: Validate via API after create
echo " [2/6] Validating creation via API..."
if validate_api "/incident-severity" "$SEVERITY_ID" "name" "terraform-crud-severity"; then
# Step 3: Update (note: order cannot be updated per API restriction)
echo " [3/6] Updating incident severity..."
if ! terraform plan -out=tfplan \
-var="severity_name=terraform-crud-severity-updated" \
-var="severity_description=Updated severity description" \
-var="severity_color=#FF00FF" \
-var="severity_order=100" 2>&1; then
echo " FAILED: Update plan failed"
FAILED+=("11-incident-severity-crud (update plan)")
else
if ! terraform apply -auto-approve tfplan 2>&1; then
echo " FAILED: Update apply failed"
FAILED+=("11-incident-severity-crud (update apply)")
else
echo " Incident severity updated successfully"
# Step 4: Validate via API after update
echo " [4/6] Validating update via API..."
if validate_api "/incident-severity" "$SEVERITY_ID" "name" "terraform-crud-severity-updated"; then
# Step 5: Verify color was updated
echo " [5/6] Validating color update via API..."
if validate_api "/incident-severity" "$SEVERITY_ID" "color" "#FF00FF"; then
PASSED+=("11-incident-severity-crud")
else
FAILED+=("11-incident-severity-crud (color validation)")
fi
else
FAILED+=("11-incident-severity-crud (update validation)")
fi
fi
fi
else
FAILED+=("11-incident-severity-crud (create validation)")
fi
# Step 6: Destroy
echo " [6/6] Destroying incident severity..."
terraform destroy -auto-approve \
-var="severity_name=terraform-crud-severity-updated" \
-var="severity_description=Updated severity description" \
-var="severity_color=#FF00FF" \
-var="severity_order=100" 2>&1 || true
fi
fi
rm -f tfplan terraform.tfstate terraform.tfstate.backup
# Summary
echo ""
echo "=========================================="
echo "CRUD Test Summary"
echo "=========================================="
echo "Passed: ${#PASSED[@]}"
for t in "${PASSED[@]}"; do echo " - $t"; done
if [ ${#FAILED[@]} -gt 0 ]; then
echo "Failed: ${#FAILED[@]}"
for t in "${FAILED[@]}"; do echo " - $t"; done
exit 1
fi
echo ""
echo "All CRUD tests passed!"

View File

@@ -47,6 +47,7 @@ TEST_DIRS=(
"05-status-page"
"06-alert-severity"
"07-alert-state"
"08-probe"
)
PASSED=()

View File

@@ -0,0 +1,30 @@
terraform {
required_providers {
oneuptime = {
source = "oneuptime/oneuptime"
version = "1.0.0"
}
}
}
provider "oneuptime" {
oneuptime_url = var.oneuptime_url
api_key = var.api_key
}
# Test for GitHub Issue #2228: probe_version field produces inconsistent result after apply
# The probe_version should remain as "1.0.0" and not be converted to JSON like {"_type":"Version","value":"1.0.0"}
resource "oneuptime_probe" "test" {
project_id = var.project_id
key = "terraform-e2e-probe-key-${formatdate("YYYYMMDDhhmmss", timestamp())}"
name = "terraform-e2e-probe-${formatdate("YYYYMMDDhhmmss", timestamp())}"
probe_version = "1.0.0"
}
output "probe_id" {
value = oneuptime_probe.test.id
}
output "probe_version" {
value = oneuptime_probe.test.probe_version
}

View File

@@ -0,0 +1,15 @@
variable "oneuptime_url" {
type = string
description = "OneUptime API URL"
}
variable "api_key" {
type = string
description = "OneUptime API Key"
sensitive = true
}
variable "project_id" {
type = string
description = "OneUptime Project ID"
}

View File

@@ -0,0 +1,38 @@
terraform {
required_providers {
oneuptime = {
source = "oneuptime/oneuptime"
version = "1.0.0"
}
}
}
provider "oneuptime" {
oneuptime_url = var.oneuptime_url
api_key = var.api_key
}
# Comprehensive CRUD test for label resource
# This test creates a label, then updates can be applied via variable changes
resource "oneuptime_label" "test" {
project_id = var.project_id
name = var.label_name
description = var.label_description
color = var.label_color
}
output "label_id" {
value = oneuptime_label.test.id
}
output "label_name" {
value = oneuptime_label.test.name
}
output "label_description" {
value = oneuptime_label.test.description
}
output "label_color" {
value = oneuptime_label.test.color
}

View File

@@ -0,0 +1,33 @@
variable "oneuptime_url" {
type = string
description = "OneUptime API URL"
}
variable "api_key" {
type = string
description = "OneUptime API Key"
sensitive = true
}
variable "project_id" {
type = string
description = "OneUptime Project ID"
}
variable "label_name" {
type = string
description = "Label name"
default = "terraform-crud-test-label"
}
variable "label_description" {
type = string
description = "Label description"
default = "Initial description for CRUD test"
}
variable "label_color" {
type = string
description = "Label color"
default = "#FF0000"
}

View File

@@ -0,0 +1,42 @@
terraform {
required_providers {
oneuptime = {
source = "oneuptime/oneuptime"
version = "1.0.0"
}
}
}
provider "oneuptime" {
oneuptime_url = var.oneuptime_url
api_key = var.api_key
}
# Comprehensive CRUD test for monitor_status resource
resource "oneuptime_monitor_status" "test" {
project_id = var.project_id
name = var.status_name
description = var.status_description
color = var.status_color
priority = var.status_priority
}
output "monitor_status_id" {
value = oneuptime_monitor_status.test.id
}
output "monitor_status_name" {
value = oneuptime_monitor_status.test.name
}
output "monitor_status_description" {
value = oneuptime_monitor_status.test.description
}
output "monitor_status_color" {
value = oneuptime_monitor_status.test.color
}
output "monitor_status_priority" {
value = oneuptime_monitor_status.test.priority
}

View File

@@ -0,0 +1,39 @@
variable "oneuptime_url" {
type = string
description = "OneUptime API URL"
}
variable "api_key" {
type = string
description = "OneUptime API Key"
sensitive = true
}
variable "project_id" {
type = string
description = "OneUptime Project ID"
}
variable "status_name" {
type = string
description = "Monitor status name"
default = "terraform-crud-test-status"
}
variable "status_description" {
type = string
description = "Monitor status description"
default = "Initial description for CRUD test"
}
variable "status_color" {
type = string
description = "Monitor status color"
default = "#00FF00"
}
variable "status_priority" {
type = number
description = "Monitor status priority"
default = 100
}

View File

@@ -0,0 +1,42 @@
terraform {
required_providers {
oneuptime = {
source = "oneuptime/oneuptime"
version = "1.0.0"
}
}
}
provider "oneuptime" {
oneuptime_url = var.oneuptime_url
api_key = var.api_key
}
# Comprehensive CRUD test for incident_severity resource
resource "oneuptime_incident_severity" "test" {
project_id = var.project_id
name = var.severity_name
description = var.severity_description
color = var.severity_color
order = var.severity_order
}
output "incident_severity_id" {
value = oneuptime_incident_severity.test.id
}
output "incident_severity_name" {
value = oneuptime_incident_severity.test.name
}
output "incident_severity_description" {
value = oneuptime_incident_severity.test.description
}
output "incident_severity_color" {
value = oneuptime_incident_severity.test.color
}
output "incident_severity_order" {
value = oneuptime_incident_severity.test.order
}

View File

@@ -0,0 +1,39 @@
variable "oneuptime_url" {
type = string
description = "OneUptime API URL"
}
variable "api_key" {
type = string
description = "OneUptime API Key"
sensitive = true
}
variable "project_id" {
type = string
description = "OneUptime Project ID"
}
variable "severity_name" {
type = string
description = "Incident severity name"
default = "terraform-crud-test-severity"
}
variable "severity_description" {
type = string
description = "Incident severity description"
default = "Initial description for CRUD test"
}
variable "severity_color" {
type = string
description = "Incident severity color"
default = "#FFA500"
}
variable "severity_order" {
type = number
description = "Incident severity order"
default = 100
}

View File

@@ -1073,9 +1073,13 @@ func (r *${resourceTypeName}Resource) Delete(ctx context.Context, req resource.D
terraformAttr.type === "string" &&
terraformAttr.isComplexObject
) {
// Try to parse as JSON first, but if it fails (e.g., for simple strings like "#FF0000"),
// fall back to sending the raw string value
return `var ${fieldName.toLowerCase()}Data interface{}
if err := json.Unmarshal([]byte(data.${fieldName}.ValueString()), &${fieldName.toLowerCase()}Data); err == nil {
requestDataMap["${apiFieldName}"] = ${fieldName.toLowerCase()}Data
} else {
requestDataMap["${apiFieldName}"] = data.${fieldName}.ValueString()
}`;
}
return `requestDataMap["${apiFieldName}"] = ${value}`;
@@ -1279,9 +1283,14 @@ func (r *${resourceTypeName}Resource) Delete(ctx context.Context, req resource.D
// ${fieldName} value is already set from the existing state
}`;
} else if (isComplexObject) {
// For complex object strings, convert API object response to JSON string
// For complex object strings, check if it's a wrapper object with _type and value fields
// (e.g., {"_type":"Version","value":"1.0.0"} or {"_type":"DateTime","value":"..."})
// If so, extract the value; otherwise convert the entire object to JSON string
return `if val, ok := ${responseValue}.(map[string]interface{}); ok {
if jsonBytes, err := json.Marshal(val); err == nil {
// Check if it's a wrapper object with value field (e.g., Version, DateTime types)
if innerVal, ok := val["value"].(string); ok {
${fieldName} = types.StringValue(innerVal)
} else if jsonBytes, err := json.Marshal(val); err == nil {
${fieldName} = types.StringValue(string(jsonBytes))
} else {
${fieldName} = types.StringNull()