Testing Data Sources

3 minute read

Testing Data Sources Overview

Data sources read existing infrastructure. Test that they correctly query, filter, and return data.

Basic Data Source Test

func TestAccCacheDataSource_basic(t *testing.T) {
    rName := acctest.RandomWithPrefix("tf-acc-test")
    dataSourceName := "data.cachecloud_cache.test"
    resourceName := "cachecloud_cache.test"
    
    resource.Test(t, resource.TestCase{
        PreCheck:                 func() { testAccPreCheck(t) },
        ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
        Steps: []resource.TestStep{
            {
                Config: testAccCacheDataSourceConfig_basic(rName),
                Check: resource.ComposeAggregateTestCheckFunc(
                    // Verify data source matches resource
                    resource.TestCheckResourceAttrPair(dataSourceName, "id", resourceName, "id"),
                    resource.TestCheckResourceAttrPair(dataSourceName, "name", resourceName, "name"),
                    resource.TestCheckResourceAttrPair(dataSourceName, "engine", resourceName, "engine"),
                    resource.TestCheckResourceAttrPair(dataSourceName, "node_type", resourceName, "node_type"),
                    
                    // Verify computed attributes
                    resource.TestCheckResourceAttrSet(dataSourceName, "endpoint"),
                    resource.TestCheckResourceAttrSet(dataSourceName, "status"),
                ),
            },
        },
    })
}

func testAccCacheDataSourceConfig_basic(rName string) string {
    return fmt.Sprintf(`
resource "cachecloud_cache" "test" {
  name      = %[1]q
  engine    = "redis"
  node_type = "cache.t3.micro"
  num_nodes = 1
}

data "cachecloud_cache" "test" {
  id = cachecloud_cache.test.id
}
`, rName)
}

Testing Filters

Filter by Name

func TestAccCacheDataSource_filterByName(t *testing.T) {
    rName := acctest.RandomWithPrefix("tf-acc-test")
    dataSourceName := "data.cachecloud_cache.test"
    
    resource.Test(t, resource.TestCase{
        PreCheck:                 func() { testAccPreCheck(t) },
        ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
        Steps: []resource.TestStep{
            {
                Config: testAccCacheDataSourceConfig_name(rName),
                Check: resource.ComposeTestCheckFunc(
                    resource.TestCheckResourceAttr(dataSourceName, "name", rName),
                    resource.TestCheckResourceAttrSet(dataSourceName, "id"),
                ),
            },
        },
    })
}

func testAccCacheDataSourceConfig_name(rName string) string {
    return fmt.Sprintf(`
resource "cachecloud_cache" "test" {
  name      = %[1]q
  engine    = "redis"
  node_type = "cache.t3.micro"
  num_nodes = 1
}

data "cachecloud_cache" "test" {
  name = cachecloud_cache.test.name
}
`, rName)
}

Filter by Tags

func TestAccCacheDataSource_filterByTags(t *testing.T) {
    rName := acctest.RandomWithPrefix("tf-acc-test")
    dataSourceName := "data.cachecloud_cache.test"
    
    resource.Test(t, resource.TestCase{
        PreCheck:                 func() { testAccPreCheck(t) },
        ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
        Steps: []resource.TestStep{
            {
                Config: testAccCacheDataSourceConfig_tags(rName),
                Check: resource.ComposeTestCheckFunc(
                    resource.TestCheckResourceAttr(dataSourceName, "tags.%", "2"),
                    resource.TestCheckResourceAttr(dataSourceName, "tags.Environment", "test"),
                ),
            },
        },
    })
}

Testing List Data Sources

List All

func TestAccCachesDataSource_all(t *testing.T) {
    dataSourceName := "data.cachecloud_caches.test"
    
    resource.Test(t, resource.TestCase{
        PreCheck:                 func() { testAccPreCheck(t) },
        ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
        Steps: []resource.TestStep{
            {
                Config: testAccCachesDataSourceConfig_all(),
                Check: resource.ComposeTestCheckFunc(
                    resource.TestCheckResourceAttrSet(dataSourceName, "caches.#"),
                    resource.TestCheckResourceAttrSet(dataSourceName, "caches.0.id"),
                    resource.TestCheckResourceAttrSet(dataSourceName, "caches.0.name"),
                ),
            },
        },
    })
}

func testAccCachesDataSourceConfig_all() string {
    return `
data "cachecloud_caches" "test" {}
`
}

List with Filter

func TestAccCachesDataSource_filter(t *testing.T) {
    rName := acctest.RandomWithPrefix("tf-acc-test")
    dataSourceName := "data.cachecloud_caches.test"
    
    resource.Test(t, resource.TestCase{
        PreCheck:                 func() { testAccPreCheck(t) },
        ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
        Steps: []resource.TestStep{
            {
                Config: testAccCachesDataSourceConfig_filter(rName),
                Check: resource.ComposeTestCheckFunc(
                    resource.TestCheckResourceAttr(dataSourceName, "filter.#", "1"),
                    resource.TestCheckResourceAttr(dataSourceName, "filter.0.name", "engine"),
                    resource.TestCheckResourceAttr(dataSourceName, "filter.0.values.#", "1"),
                    resource.TestCheckResourceAttr(dataSourceName, "filter.0.values.0", "redis"),
                    
                    // Verify results contain our cache
                    resource.TestCheckResourceAttrSet(dataSourceName, "caches.#"),
                ),
            },
        },
    })
}

func testAccCachesDataSourceConfig_filter(rName string) string {
    return fmt.Sprintf(`
resource "cachecloud_cache" "test" {
  name      = %[1]q
  engine    = "redis"
  node_type = "cache.t3.micro"
  num_nodes = 1
}

data "cachecloud_caches" "test" {
  filter {
    name   = "engine"
    values = ["redis"]
  }
  
  depends_on = [cachecloud_cache.test]
}
`, rName)
}

Testing Not Found

func TestAccCacheDataSource_notFound(t *testing.T) {
    resource.Test(t, resource.TestCase{
        PreCheck:                 func() { testAccPreCheck(t) },
        ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
        Steps: []resource.TestStep{
            {
                Config:      testAccCacheDataSourceConfig_notFound(),
                ExpectError: regexp.MustCompile(`cache with ID .+ not found`),
            },
        },
    })
}

func testAccCacheDataSourceConfig_notFound() string {
    return `
data "cachecloud_cache" "test" {
  id = "non-existent-id"
}
`
}

Testing Computed Attributes

func TestAccCacheDataSource_computedAttributes(t *testing.T) {
    rName := acctest.RandomWithPrefix("tf-acc-test")
    dataSourceName := "data.cachecloud_cache.test"
    
    resource.Test(t, resource.TestCase{
        PreCheck:                 func() { testAccPreCheck(t) },
        ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
        Steps: []resource.TestStep{
            {
                Config: testAccCacheDataSourceConfig_basic(rName),
                Check: resource.ComposeTestCheckFunc(
                    // All computed attributes should be set
                    resource.TestCheckResourceAttrSet(dataSourceName, "id"),
                    resource.TestCheckResourceAttrSet(dataSourceName, "endpoint"),
                    resource.TestCheckResourceAttrSet(dataSourceName, "status"),
                    resource.TestCheckResourceAttrSet(dataSourceName, "created_at"),
                    resource.TestCheckResourceAttrSet(dataSourceName, "updated_at"),
                    
                    // Verify format
                    resource.TestMatchResourceAttr(dataSourceName, "endpoint",
                        regexp.MustCompile(`^[a-z0-9\-]+\.cache\.example\.com:\d+$`)),
                ),
            },
        },
    })
}

Best Practices

1. Test with Resource Dependency

// ✅ Good: Create resource first
Config: `
resource "cachecloud_cache" "test" { ... }
data "cachecloud_cache" "test" {
  id = cachecloud_cache.test.id
}
`

// ❌ Bad: Data source without resource
Config: `
data "cachecloud_cache" "test" {
  id = "hardcoded-id"
}
`

2. Use TestCheckResourceAttrPair

// ✅ Good: Compare with resource
resource.TestCheckResourceAttrPair(
    dataSourceName, "name",
    resourceName, "name",
)

// ❌ Bad: Hardcode expected value
resource.TestCheckResourceAttr(dataSourceName, "name", "test")

3. Test Filters

// ✅ Good: Test filter functionality
data "cachecloud_caches" "test" {
  filter {
    name   = "engine"
    values = ["redis"]
  }
}

Key Takeaways

  • ✅ Test data sources with existing resources
  • ✅ Verify all computed attributes
  • ✅ Test filters and queries
  • ✅ Use TestCheckResourceAttrPair for comparisons
  • ✅ Test not found scenarios
  • ✅ Test list data sources
  • ✅ Verify data matches resource state
  • ✅ Test multiple filter combinations

What’s Next?

Learn how to mock API clients for isolated unit testing.

Next: Mocking & Test Doubles →


Previous: ← Testing Resources

Last updated: July 3, 2026

Updated: