Testing Patterns

Simfra is well-suited for testing Terraform modules. Write your module normally, point it at Simfra, and verify that it produces the expected resources and outputs.

Prerequisites

Plan / Apply / Verify / Destroy

The basic testing cycle:

# 1. Plan - verify no errors, check resource count
terraform plan -out=tfplan
# Inspect the plan output for expected resources

# 2. Apply
terraform apply tfplan

# 3. Verify outputs
terraform output -json | jq .

# 4. Verify resources exist via AWS CLI
aws ec2 describe-vpcs --filters Name=tag:Name,Values=my-vpc

# 5. Destroy
terraform destroy -auto-approve

Simfra is in-memory by default, so this cycle runs in seconds. There are no API rate limits and no eventual consistency delays.

Verifying State with Data Sources

Use Terraform data sources to verify that resources were created correctly:

module "network" {
  source = "./modules/network"
}

# Verify the VPC exists and has the expected CIDR
data "aws_vpc" "check" {
  id = module.network.vpc_id
}

output "verified_cidr" {
  value = data.aws_vpc.check.cidr_block
}

# Verify subnets were created in the right AZs
data "aws_subnets" "check" {
  filter {
    name   = "vpc-id"
    values = [module.network.vpc_id]
  }
}

output "subnet_count" {
  value = length(data.aws_subnets.check.ids)
}

Data sources read from Simfra the same way they read from AWS, so any validation logic in your Terraform code works without modification.

Using terraform test

Terraform 1.6+ supports native test files (.tftest.hcl). These work with Simfra out of the box.

Module Under Test

# modules/network/main.tf
variable "vpc_cidr" {
  type    = string
  default = "10.0.0.0/16"
}

variable "subnet_count" {
  type    = number
  default = 2
}

resource "aws_vpc" "this" {
  cidr_block = var.vpc_cidr

  tags = {
    Name = "test-vpc"
  }
}

resource "aws_subnet" "this" {
  count      = var.subnet_count
  vpc_id     = aws_vpc.this.id
  cidr_block = cidrsubnet(var.vpc_cidr, 8, count.index)
}

output "vpc_id" {
  value = aws_vpc.this.id
}

output "subnet_ids" {
  value = aws_subnet.this[*].id
}

Test File

# tests/network.tftest.hcl

run "creates_vpc_and_subnets" {
  command = apply

  assert {
    condition     = output.vpc_id != ""
    error_message = "VPC ID should not be empty"
  }

  assert {
    condition     = length(output.subnet_ids) == 2
    error_message = "Expected 2 subnets"
  }
}

run "custom_cidr" {
  command = apply

  variables {
    vpc_cidr     = "172.16.0.0/16"
    subnet_count = 3
  }

  assert {
    condition     = length(output.subnet_ids) == 3
    error_message = "Expected 3 subnets with custom count"
  }
}

Running Tests

terraform test

Each run block creates a fresh apply/destroy cycle. Against Simfra, the entire test suite runs in seconds.

Testing Modules in Isolation

Test individual modules without a full root configuration:

project/
  modules/
    network/
      main.tf
      outputs.tf
    compute/
      main.tf
      variables.tf
  tests/
    network.tftest.hcl
    compute.tftest.hcl

Each test file can target a specific module and assert on its outputs independently. Since Simfra has no costs, you can run terraform test on every commit.

Asserting on Resource Attributes

Use data sources inside test runs to inspect resources beyond what outputs expose:

run "vpc_has_dns_enabled" {
  command = apply

  assert {
    condition     = output.vpc_id != ""
    error_message = "VPC should be created"
  }
}

run "verify_vpc_dns" {
  command = plan

  module {
    source = "./tests/helpers/check-vpc"
  }

  variables {
    vpc_id = run.vpc_has_dns_enabled.vpc_id
  }

  assert {
    condition     = data.aws_vpc.this.enable_dns_support
    error_message = "VPC should have DNS support enabled"
  }
}

Fast Iteration Tips

  • No SIMFRA_DATA_DIR - leave persistence off for testing. State resets on restart, giving you a clean slate.
  • SIMFRA_BOOTSTRAP=standard - pre-creates default VPCs and KMS keys so modules that depend on default resources work immediately.
  • Parallel applies - Simfra handles concurrent requests. Run multiple test suites in parallel.
  • -parallelism=30 - Terraform defaults to 10 concurrent operations. Simfra can handle more.
  • No state locking needed - with a local backend and ephemeral Simfra, there is no contention.

CI Integration

Simfra runs as a single binary or Docker container, making it straightforward to add to CI pipelines:

# GitHub Actions example
- name: Start Simfra
  run: |
    docker run -d --name simfra -p 4599:4599 \
      -e SIMFRA_BOOTSTRAP=standard \
      ghcr.io/simfra-dev/simfra:latest

- name: Wait for healthy
  run: |
    for i in $(seq 1 30); do
      curl -sf http://localhost:4599/_simfra/health && break
      sleep 1
    done

- name: Terraform test
  env:
    AWS_ENDPOINT_URL: http://localhost:4599
    AWS_ACCESS_KEY_ID: AKIAIOSFODNN7EXAMPLE
    AWS_SECRET_ACCESS_KEY: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
    AWS_DEFAULT_REGION: us-east-1
  run: terraform test

Next Steps