Skip to content

Commit 45b72c7

Browse files
authored
Migrate tests to Terraform for jetbrains, zed, and code-server (#307)
## Summary - Introduces Terraform native tests (`terraform test`) alongside existing Bun tests - Migrates tests for modules: jetbrains, zed, and code-server - Removes Bun test files for these migrated modules only - Adds repo-wide test runner script for Terraform tests - Updates docs and new-module sample to reflect Terraform tests ## Transition plan - Mixed mode: Other modules retain Bun tests; CI should run both Bun and Terraform tests temporarily - Follow the linked epic to migrate remaining modules ## Test plan - Run: `./scripts/terraform_test_all.sh` (passes locally) - Bun tests still available for non-migrated modules ## Affected paths - registry/coder/modules/jetbrains/jetbrains.tftest.hcl - registry/coder/modules/zed/zed.tftest.hcl - registry/coder/modules/code-server/code-server.tftest.hcl - scripts/terraform_test_all.sh - examples/modules/MODULE_NAME.tftest.hcl - CONTRIBUTING.md Contributes to #308
1 parent 2646b36 commit 45b72c7

File tree

8 files changed

+287
-14
lines changed

8 files changed

+287
-14
lines changed

CONTRIBUTING.md

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ The Coder Registry is a collection of Terraform modules and templates for Coder
2424

2525
### Install Dependencies
2626

27-
Install Bun:
27+
Install Bun (for formatting and scripts):
2828

2929
```bash
3030
curl -fsSL https://bun.sh/install | bash
@@ -124,19 +124,23 @@ This script generates:
124124
- Accurate description and usage examples
125125
- Correct icon path (usually `../../../../.icons/your-icon.svg`)
126126
- Proper tags that describe your module
127-
3. **Create `main.test.ts`** to test your module
127+
3. **Create at least one `.tftest.hcl`** to test your module with `terraform test`
128128
4. **Add any scripts** or additional files your module needs
129129

130130
### 4. Test and Submit
131131

132132
```bash
133-
# Test your module
134-
bun test -t 'module-name'
133+
# Test your module (from the module directory)
134+
terraform init -upgrade
135+
terraform test -verbose
136+
137+
# Or run all tests in the repo
138+
./scripts/terraform_test_all.sh
135139

136140
# Format code
137-
bun fmt
141+
bun run fmt
138142

139-
# Commit and create PR
143+
# Commit and create PR (do not push to main directly)
140144
git add .
141145
git commit -m "Add [module-name] module"
142146
git push origin your-branch
@@ -335,11 +339,12 @@ coder templates push test-[template-name] -d .
335339
### 2. Test Your Changes
336340

337341
```bash
338-
# Test a specific module
339-
bun test -t 'module-name'
342+
# Test a specific module (from the module directory)
343+
terraform init -upgrade
344+
terraform test -verbose
340345

341346
# Test all modules
342-
bun test
347+
./scripts/terraform_test_all.sh
343348
```
344349

345350
### 3. Maintain Backward Compatibility
@@ -388,7 +393,7 @@ Example: `https://github.com/coder/registry/compare/main...your-branch?template=
388393
### Every Module Must Have
389394

390395
- `main.tf` - Terraform code
391-
- `main.test.ts` - Working tests
396+
- One or more `.tftest.hcl` files - Working tests with `terraform test`
392397
- `README.md` - Documentation with frontmatter
393398

394399
### Every Template Must Have
@@ -488,6 +493,6 @@ When reporting bugs, include:
488493
2. **No tests** or broken tests
489494
3. **Hardcoded values** instead of variables
490495
4. **Breaking changes** without defaults
491-
5. **Not running** `bun fmt` before submitting
496+
5. **Not running** formatting (`bun run fmt`) and tests (`terraform test`) before submitting
492497

493498
Happy contributing! 🚀

MAINTAINER.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ sudo apt install golang-go
1818

1919
Check that PRs have:
2020

21-
- [ ] All required files (`main.tf`, `main.test.ts`, `README.md`)
21+
- [ ] All required files (`main.tf`, `README.md`, at least one `.tftest.hcl`)
2222
- [ ] Proper frontmatter in README
23-
- [ ] Working tests (`bun test`)
23+
- [ ] Working tests (`terraform test`)
2424
- [ ] Formatted code (`bun run fmt`)
2525
- [ ] Avatar image for new namespaces (`avatar.png` or `avatar.svg` in `.images/`)
2626

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
run "plan_with_required_vars" {
2+
command = plan
3+
4+
variables {
5+
agent_id = "example-agent-id"
6+
}
7+
}
8+
9+
run "app_url_uses_port" {
10+
command = plan
11+
12+
variables {
13+
agent_id = "example-agent-id"
14+
port = 19999
15+
}
16+
17+
assert {
18+
condition = resource.coder_app.MODULE_NAME.url == "http://localhost:19999"
19+
error_message = "Expected MODULE_NAME app URL to include configured port"
20+
}
21+
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"fmt": "bun x prettier --write **/*.sh **/*.ts **/*.md *.md && terraform fmt -recursive -diff",
55
"fmt:ci": "bun x prettier --check **/*.sh **/*.ts **/*.md *.md && terraform fmt -check -recursive -diff",
66
"terraform-validate": "./scripts/terraform_validate.sh",
7-
"test": "bun test",
7+
"test": "./scripts/terraform_test_all.sh",
88
"update-version": "./update-version.sh"
99
},
1010
"devDependencies": {
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
run "required_vars" {
2+
command = plan
3+
4+
variables {
5+
agent_id = "foo"
6+
}
7+
}
8+
9+
run "offline_and_use_cached_conflict" {
10+
command = plan
11+
12+
variables {
13+
agent_id = "foo"
14+
use_cached = true
15+
offline = true
16+
}
17+
18+
expect_failures = [
19+
resource.coder_script.code-server
20+
]
21+
}
22+
23+
run "offline_disallows_extensions" {
24+
command = plan
25+
26+
variables {
27+
agent_id = "foo"
28+
offline = true
29+
extensions = ["ms-python.python", "golang.go"]
30+
}
31+
32+
expect_failures = [
33+
resource.coder_script.code-server
34+
]
35+
}
36+
37+
run "url_with_folder_query" {
38+
command = plan
39+
40+
variables {
41+
agent_id = "foo"
42+
folder = "/home/coder/project"
43+
port = 13337
44+
}
45+
46+
assert {
47+
condition = resource.coder_app.code-server.url == "http://localhost:13337/?folder=%2Fhome%2Fcoder%2Fproject"
48+
error_message = "coder_app URL must include encoded folder query param"
49+
}
50+
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
run "requires_agent_and_folder" {
2+
command = plan
3+
4+
# Setting both required vars should plan
5+
variables {
6+
agent_id = "foo"
7+
folder = "/home/coder"
8+
}
9+
}
10+
11+
run "creates_parameter_when_default_empty_latest" {
12+
command = plan
13+
14+
variables {
15+
agent_id = "foo"
16+
folder = "/home/coder"
17+
major_version = "latest"
18+
}
19+
20+
# When default is empty, a coder_parameter should be created
21+
assert {
22+
condition = can(data.coder_parameter.jetbrains_ides[0].type)
23+
error_message = "Expected data.coder_parameter.jetbrains_ides to exist when default is empty"
24+
}
25+
}
26+
27+
run "no_apps_when_default_empty" {
28+
command = plan
29+
30+
variables {
31+
agent_id = "foo"
32+
folder = "/home/coder"
33+
}
34+
35+
assert {
36+
condition = length(resource.coder_app.jetbrains) == 0
37+
error_message = "Expected no coder_app resources when default is empty"
38+
}
39+
}
40+
41+
run "single_app_when_default_GO" {
42+
command = plan
43+
44+
variables {
45+
agent_id = "foo"
46+
folder = "/home/coder"
47+
default = ["GO"]
48+
}
49+
50+
assert {
51+
condition = length(resource.coder_app.jetbrains) == 1
52+
error_message = "Expected exactly one coder_app when default contains GO"
53+
}
54+
}
55+
56+
run "url_contains_required_params" {
57+
command = apply
58+
59+
variables {
60+
agent_id = "test-agent-123"
61+
folder = "/custom/project/path"
62+
default = ["GO"]
63+
}
64+
65+
assert {
66+
condition = anytrue([for app in values(resource.coder_app.jetbrains) : length(regexall("jetbrains://gateway/coder", app.url)) > 0])
67+
error_message = "URL must contain jetbrains scheme"
68+
}
69+
70+
assert {
71+
condition = anytrue([for app in values(resource.coder_app.jetbrains) : length(regexall("&folder=/custom/project/path", app.url)) > 0])
72+
error_message = "URL must include folder path"
73+
}
74+
75+
assert {
76+
condition = anytrue([for app in values(resource.coder_app.jetbrains) : length(regexall("ide_product_code=GO", app.url)) > 0])
77+
error_message = "URL must include product code"
78+
}
79+
80+
assert {
81+
condition = anytrue([for app in values(resource.coder_app.jetbrains) : length(regexall("ide_build_number=", app.url)) > 0])
82+
error_message = "URL must include build number"
83+
}
84+
}
85+
86+
run "includes_agent_name_when_set" {
87+
command = apply
88+
89+
variables {
90+
agent_id = "test-agent-123"
91+
agent_name = "main-agent"
92+
folder = "/custom/project/path"
93+
default = ["GO"]
94+
}
95+
96+
assert {
97+
condition = anytrue([for app in values(resource.coder_app.jetbrains) : length(regexall("&agent_name=main-agent", app.url)) > 0])
98+
error_message = "URL must include agent_name when provided"
99+
}
100+
}
101+
102+
run "parameter_order_when_default_empty" {
103+
command = plan
104+
105+
variables {
106+
agent_id = "foo"
107+
folder = "/home/coder"
108+
coder_parameter_order = 5
109+
}
110+
111+
assert {
112+
condition = data.coder_parameter.jetbrains_ides[0].order == 5
113+
error_message = "Expected coder_parameter order to be set to 5"
114+
}
115+
}
116+
117+
run "app_order_when_default_not_empty" {
118+
command = plan
119+
120+
variables {
121+
agent_id = "foo"
122+
folder = "/home/coder"
123+
default = ["GO"]
124+
coder_app_order = 10
125+
}
126+
127+
assert {
128+
condition = anytrue([for app in values(resource.coder_app.jetbrains) : app.order == 10])
129+
error_message = "Expected coder_app order to be set to 10"
130+
}
131+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
run "default_output" {
2+
command = apply
3+
4+
variables {
5+
agent_id = "foo"
6+
}
7+
8+
assert {
9+
condition = output.zed_url == "zed://ssh/default.coder"
10+
error_message = "zed_url did not match expected default URL"
11+
}
12+
}
13+
14+
run "adds_folder" {
15+
command = apply
16+
17+
variables {
18+
agent_id = "foo"
19+
folder = "/foo/bar"
20+
}
21+
22+
assert {
23+
condition = output.zed_url == "zed://ssh/default.coder/foo/bar"
24+
error_message = "zed_url did not include provided folder path"
25+
}
26+
}
27+
28+
run "adds_agent_name" {
29+
command = apply
30+
31+
variables {
32+
agent_id = "foo"
33+
agent_name = "myagent"
34+
}
35+
36+
assert {
37+
condition = output.zed_url == "zed://ssh/myagent.default.default.coder"
38+
error_message = "zed_url did not include agent_name in hostname"
39+
}
40+
}

scripts/terraform_test_all.sh

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
# Find all directories that contain any .tftest.hcl files and run terraform test in each
5+
6+
run_dir() {
7+
local dir="$1"
8+
echo "==> Running terraform test in $dir"
9+
(cd "$dir" && terraform init -upgrade -input=false -no-color > /dev/null && terraform test -no-color -verbose)
10+
}
11+
12+
mapfile -t test_dirs < <(find . -type f -name "*.tftest.hcl" -print0 | xargs -0 -I{} dirname {} | sort -u)
13+
14+
if [[ ${#test_dirs[@]} -eq 0 ]]; then
15+
echo "No .tftest.hcl tests found."
16+
exit 0
17+
fi
18+
19+
status=0
20+
for d in "${test_dirs[@]}"; do
21+
if ! run_dir "$d"; then
22+
status=1
23+
fi
24+
done
25+
26+
exit $status

0 commit comments

Comments
 (0)