Skip to content

Commit 6182af4

Browse files
sreyaThomasK33
authored andcommitted
update tests
1 parent 1232eaa commit 6182af4

16 files changed

+631
-191
lines changed

provisioner/terraform/resources_test.go

Lines changed: 111 additions & 191 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,24 +1249,120 @@ func TestAgentNameDuplicate(t *testing.T) {
12491249
require.ErrorContains(t, err, "duplicate agent name")
12501250
}
12511251

1252-
func TestMetadataResourceDuplicate(t *testing.T) {
1252+
func TestMetadata(t *testing.T) {
12531253
t.Parallel()
1254-
ctx, logger := ctxAndLogger(t)
12551254

1256-
// Load the multiple-apps state file and edit it.
1257-
dir := filepath.Join("testdata", "resources", "resource-metadata-duplicate")
1258-
tfPlanRaw, err := os.ReadFile(filepath.Join(dir, "resource-metadata-duplicate.tfplan.json"))
1259-
require.NoError(t, err)
1260-
var tfPlan tfjson.Plan
1261-
err = json.Unmarshal(tfPlanRaw, &tfPlan)
1262-
require.NoError(t, err)
1263-
tfPlanGraph, err := os.ReadFile(filepath.Join(dir, "resource-metadata-duplicate.tfplan.dot"))
1264-
require.NoError(t, err)
1255+
t.Run("Duplicate", func(t *testing.T) {
1256+
t.Parallel()
1257+
ctx, logger := ctxAndLogger(t)
1258+
// Load the multiple-apps state file and edit it.
1259+
dir := filepath.Join("testdata", "resources", "resource-metadata-duplicate")
1260+
tfPlanRaw, err := os.ReadFile(filepath.Join(dir, "resource-metadata-duplicate.tfplan.json"))
1261+
require.NoError(t, err)
1262+
var tfPlan tfjson.Plan
1263+
err = json.Unmarshal(tfPlanRaw, &tfPlan)
1264+
require.NoError(t, err)
1265+
tfPlanGraph, err := os.ReadFile(filepath.Join(dir, "resource-metadata-duplicate.tfplan.dot"))
1266+
require.NoError(t, err)
12651267

1266-
state, err := terraform.ConvertState(ctx, []*tfjson.StateModule{tfPlan.PlannedValues.RootModule}, string(tfPlanGraph), logger)
1267-
require.Nil(t, state)
1268-
require.Error(t, err)
1269-
require.ErrorContains(t, err, "duplicate metadata resource: null_resource.about")
1268+
state, err := terraform.ConvertState(ctx, []*tfjson.StateModule{tfPlan.PlannedValues.RootModule}, string(tfPlanGraph), logger)
1269+
require.Nil(t, state)
1270+
require.Error(t, err)
1271+
require.ErrorContains(t, err, "duplicate metadata resource: null_resource.about")
1272+
})
1273+
1274+
t.Run("ResourceID", func(t *testing.T) {
1275+
t.Parallel()
1276+
1277+
t.Run("ResourceIDProvided", func(t *testing.T) {
1278+
t.Parallel()
1279+
ctx, logger := ctxAndLogger(t)
1280+
1281+
dir := filepath.Join("testdata", "resources", "resource-id-provided")
1282+
tfStateRaw, err := os.ReadFile(filepath.Join(dir, "resource-id-provided.tfstate.json"))
1283+
require.NoError(t, err)
1284+
var tfState tfjson.State
1285+
err = json.Unmarshal(tfStateRaw, &tfState)
1286+
require.NoError(t, err)
1287+
tfStateGraph, err := os.ReadFile(filepath.Join(dir, "resource-id-provided.tfstate.dot"))
1288+
require.NoError(t, err)
1289+
1290+
state, err := terraform.ConvertState(ctx, []*tfjson.StateModule{tfState.Values.RootModule}, string(tfStateGraph), logger)
1291+
require.NoError(t, err)
1292+
require.Len(t, state.Resources, 2)
1293+
1294+
// Find the resources
1295+
var firstResource, secondResource *proto.Resource
1296+
for _, res := range state.Resources {
1297+
if res.Name == "first" && res.Type == "null_resource" {
1298+
firstResource = res
1299+
} else if res.Name == "second" && res.Type == "null_resource" {
1300+
secondResource = res
1301+
}
1302+
}
1303+
1304+
require.NotNil(t, firstResource)
1305+
require.NotNil(t, secondResource)
1306+
1307+
// The metadata should be on the second resource (as specified by resource_id),
1308+
// not the first one (which is the closest in the graph)
1309+
require.Len(t, firstResource.Metadata, 0, "first resource should have no metadata")
1310+
require.Len(t, secondResource.Metadata, 1, "second resource should have metadata")
1311+
require.Equal(t, "test", secondResource.Metadata[0].Key)
1312+
require.Equal(t, "value", secondResource.Metadata[0].Value)
1313+
})
1314+
1315+
t.Run("ResourceIDNotFound", func(t *testing.T) {
1316+
t.Parallel()
1317+
ctx, logger := ctxAndLogger(t)
1318+
1319+
dir := filepath.Join("testdata", "resources", "resource-id-not-found")
1320+
tfStateRaw, err := os.ReadFile(filepath.Join(dir, "resource-id-not-found.tfstate.json"))
1321+
require.NoError(t, err)
1322+
var tfState tfjson.State
1323+
err = json.Unmarshal(tfStateRaw, &tfState)
1324+
require.NoError(t, err)
1325+
tfStateGraph, err := os.ReadFile(filepath.Join(dir, "resource-id-not-found.tfstate.dot"))
1326+
require.NoError(t, err)
1327+
1328+
state, err := terraform.ConvertState(ctx, []*tfjson.StateModule{tfState.Values.RootModule}, string(tfStateGraph), logger)
1329+
require.NoError(t, err)
1330+
require.Len(t, state.Resources, 1)
1331+
1332+
// The metadata should still be applied via graph traversal
1333+
require.Equal(t, "example", state.Resources[0].Name)
1334+
require.Len(t, state.Resources[0].Metadata, 1)
1335+
require.Equal(t, "test", state.Resources[0].Metadata[0].Key)
1336+
require.Equal(t, "value", state.Resources[0].Metadata[0].Value)
1337+
1338+
// When resource_id is not found, it falls back to graph traversal
1339+
// We can't easily verify the warning was logged without access to the log capture API
1340+
})
1341+
1342+
t.Run("ResourceIDNotProvided", func(t *testing.T) {
1343+
t.Parallel()
1344+
ctx, logger := ctxAndLogger(t)
1345+
1346+
dir := filepath.Join("testdata", "resources", "resource-id-not-provided")
1347+
tfStateRaw, err := os.ReadFile(filepath.Join(dir, "resource-id-not-provided.tfstate.json"))
1348+
require.NoError(t, err)
1349+
var tfState tfjson.State
1350+
err = json.Unmarshal(tfStateRaw, &tfState)
1351+
require.NoError(t, err)
1352+
tfStateGraph, err := os.ReadFile(filepath.Join(dir, "resource-id-not-provided.tfstate.dot"))
1353+
require.NoError(t, err)
1354+
1355+
state, err := terraform.ConvertState(ctx, []*tfjson.StateModule{tfState.Values.RootModule}, string(tfStateGraph), logger)
1356+
require.NoError(t, err)
1357+
require.Len(t, state.Resources, 1)
1358+
1359+
// The metadata should be applied via graph traversal
1360+
require.Equal(t, "example", state.Resources[0].Name)
1361+
require.Len(t, state.Resources[0].Metadata, 1)
1362+
require.Equal(t, "test", state.Resources[0].Metadata[0].Key)
1363+
require.Equal(t, "value", state.Resources[0].Metadata[0].Value)
1364+
})
1365+
})
12701366
}
12711367

12721368
func TestParameterValidation(t *testing.T) {
@@ -1608,179 +1704,3 @@ func sortExternalAuthProviders(providers []*proto.ExternalAuthProviderResource)
16081704
return strings.Compare(providers[i].Id, providers[j].Id) == -1
16091705
})
16101706
}
1611-
1612-
func TestMetadataResourceID(t *testing.T) {
1613-
t.Parallel()
1614-
1615-
t.Run("UsesResourceIDWhenProvided", func(t *testing.T) {
1616-
t.Parallel()
1617-
ctx, logger := ctxAndLogger(t)
1618-
1619-
// Create a state with two resources and metadata that references the second one via resource_id
1620-
state, err := terraform.ConvertState(ctx, []*tfjson.StateModule{{
1621-
Resources: []*tfjson.StateResource{{
1622-
Address: "null_resource.first",
1623-
Type: "null_resource",
1624-
Name: "first",
1625-
Mode: tfjson.ManagedResourceMode,
1626-
AttributeValues: map[string]interface{}{
1627-
"id": "first-resource-id",
1628-
},
1629-
}, {
1630-
Address: "null_resource.second",
1631-
Type: "null_resource",
1632-
Name: "second",
1633-
Mode: tfjson.ManagedResourceMode,
1634-
AttributeValues: map[string]interface{}{
1635-
"id": "second-resource-id",
1636-
},
1637-
}, {
1638-
Address: "coder_metadata.example",
1639-
Type: "coder_metadata",
1640-
Name: "example",
1641-
Mode: tfjson.ManagedResourceMode,
1642-
DependsOn: []string{"null_resource.first"},
1643-
AttributeValues: map[string]interface{}{
1644-
"resource_id": "second-resource-id",
1645-
"item": []interface{}{
1646-
map[string]interface{}{
1647-
"key": "test",
1648-
"value": "value",
1649-
},
1650-
},
1651-
},
1652-
}},
1653-
}}, `digraph {
1654-
compound = "true"
1655-
newrank = "true"
1656-
subgraph "root" {
1657-
"[root] null_resource.first" [label = "null_resource.first", shape = "box"]
1658-
"[root] null_resource.second" [label = "null_resource.second", shape = "box"]
1659-
"[root] coder_metadata.example" [label = "coder_metadata.example", shape = "box"]
1660-
"[root] coder_metadata.example" -> "[root] null_resource.first"
1661-
}
1662-
}`, logger)
1663-
require.NoError(t, err)
1664-
require.Len(t, state.Resources, 2)
1665-
1666-
// Find the resources
1667-
var firstResource, secondResource *proto.Resource
1668-
for _, res := range state.Resources {
1669-
if res.Name == "first" && res.Type == "null_resource" {
1670-
firstResource = res
1671-
} else if res.Name == "second" && res.Type == "null_resource" {
1672-
secondResource = res
1673-
}
1674-
}
1675-
1676-
require.NotNil(t, firstResource)
1677-
require.NotNil(t, secondResource)
1678-
1679-
// The metadata should be on the second resource (as specified by resource_id),
1680-
// not the first one (which is the closest in the graph)
1681-
require.Len(t, firstResource.Metadata, 0, "first resource should have no metadata")
1682-
require.Len(t, secondResource.Metadata, 1, "second resource should have metadata")
1683-
require.Equal(t, "test", secondResource.Metadata[0].Key)
1684-
require.Equal(t, "value", secondResource.Metadata[0].Value)
1685-
})
1686-
1687-
t.Run("FallsBackToGraphWhenResourceIDNotFound", func(t *testing.T) {
1688-
t.Parallel()
1689-
ctx, logger := ctxAndLogger(t)
1690-
1691-
// Create a state where resource_id references a non-existent ID
1692-
state, err := terraform.ConvertState(ctx, []*tfjson.StateModule{{
1693-
Resources: []*tfjson.StateResource{{
1694-
Address: "null_resource.example",
1695-
Type: "null_resource",
1696-
Name: "example",
1697-
Mode: tfjson.ManagedResourceMode,
1698-
AttributeValues: map[string]interface{}{
1699-
"id": "example-resource-id",
1700-
},
1701-
}, {
1702-
Address: "coder_metadata.example",
1703-
Type: "coder_metadata",
1704-
Name: "example",
1705-
Mode: tfjson.ManagedResourceMode,
1706-
DependsOn: []string{"null_resource.example"},
1707-
AttributeValues: map[string]interface{}{
1708-
"resource_id": "non-existent-id",
1709-
"item": []interface{}{
1710-
map[string]interface{}{
1711-
"key": "test",
1712-
"value": "value",
1713-
},
1714-
},
1715-
},
1716-
}},
1717-
}}, `digraph {
1718-
compound = "true"
1719-
newrank = "true"
1720-
subgraph "root" {
1721-
"[root] null_resource.example" [label = "null_resource.example", shape = "box"]
1722-
"[root] coder_metadata.example" [label = "coder_metadata.example", shape = "box"]
1723-
"[root] coder_metadata.example" -> "[root] null_resource.example"
1724-
}
1725-
}`, logger)
1726-
require.NoError(t, err)
1727-
require.Len(t, state.Resources, 1)
1728-
1729-
// The metadata should still be applied via graph traversal
1730-
require.Equal(t, "example", state.Resources[0].Name)
1731-
require.Len(t, state.Resources[0].Metadata, 1)
1732-
require.Equal(t, "test", state.Resources[0].Metadata[0].Key)
1733-
require.Equal(t, "value", state.Resources[0].Metadata[0].Value)
1734-
1735-
// When resource_id is not found, it falls back to graph traversal
1736-
// We can't easily verify the warning was logged without access to the log capture API
1737-
})
1738-
1739-
t.Run("UsesGraphWhenResourceIDNotProvided", func(t *testing.T) {
1740-
t.Parallel()
1741-
ctx, logger := ctxAndLogger(t)
1742-
1743-
// Create a state without resource_id
1744-
state, err := terraform.ConvertState(ctx, []*tfjson.StateModule{{
1745-
Resources: []*tfjson.StateResource{{
1746-
Address: "null_resource.example",
1747-
Type: "null_resource",
1748-
Name: "example",
1749-
Mode: tfjson.ManagedResourceMode,
1750-
AttributeValues: map[string]interface{}{
1751-
"id": "example-resource-id",
1752-
},
1753-
}, {
1754-
Address: "coder_metadata.example",
1755-
Type: "coder_metadata",
1756-
Name: "example",
1757-
Mode: tfjson.ManagedResourceMode,
1758-
DependsOn: []string{"null_resource.example"},
1759-
AttributeValues: map[string]interface{}{
1760-
"item": []interface{}{
1761-
map[string]interface{}{
1762-
"key": "test",
1763-
"value": "value",
1764-
},
1765-
},
1766-
},
1767-
}},
1768-
}}, `digraph {
1769-
compound = "true"
1770-
newrank = "true"
1771-
subgraph "root" {
1772-
"[root] null_resource.example" [label = "null_resource.example", shape = "box"]
1773-
"[root] coder_metadata.example" [label = "coder_metadata.example", shape = "box"]
1774-
"[root] coder_metadata.example" -> "[root] null_resource.example"
1775-
}
1776-
}`, logger)
1777-
require.NoError(t, err)
1778-
require.Len(t, state.Resources, 1)
1779-
1780-
// The metadata should be applied via graph traversal
1781-
require.Equal(t, "example", state.Resources[0].Name)
1782-
require.Len(t, state.Resources[0].Metadata, 1)
1783-
require.Equal(t, "test", state.Resources[0].Metadata[0].Key)
1784-
require.Equal(t, "value", state.Resources[0].Metadata[0].Value)
1785-
})
1786-
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
terraform {
2+
required_providers {
3+
coder = {
4+
source = "coder/coder"
5+
version = ">=2.0.0"
6+
}
7+
}
8+
}
9+
10+
resource "null_resource" "example" {}
11+
12+
resource "coder_metadata" "example" {
13+
resource_id = "non-existent-id"
14+
depends_on = [null_resource.example]
15+
item {
16+
key = "test"
17+
value = "value"
18+
}
19+
}

provisioner/terraform/testdata/resources/resource-id-not-found/resource-id-not-found.tfplan.dot

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

provisioner/terraform/testdata/resources/resource-id-not-found/resource-id-not-found.tfplan.json

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

provisioner/terraform/testdata/resources/resource-id-not-found/resource-id-not-found.tfstate.dot

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)