chore(test): add terraform tests for jetbrains, zed, code-server and keep mixed mode
- Add .tftest.hcl for jetbrains, zed, and code-server - Remove Bun tests for these migrated modules only - Keep Bun tests for other modules during transition - Update contributing guide to mention terraform test - Include runner script to execute terraform tests across modules
This commit is contained in:
parent
016d4dc523
commit
fb657b875d
@ -20,9 +20,9 @@ The Coder Registry is a collection of Terraform modules and templates for Coder
|
|||||||
|
|
||||||
- Basic Terraform knowledge (for module development)
|
- Basic Terraform knowledge (for module development)
|
||||||
- Terraform installed ([installation guide](https://developer.hashicorp.com/terraform/install))
|
- Terraform installed ([installation guide](https://developer.hashicorp.com/terraform/install))
|
||||||
- Docker (for running tests)
|
- Docker (for some modules' tests that rely on containers)
|
||||||
|
|
||||||
### Install Dependencies
|
### Install Dependencies (for formatting and scripts)
|
||||||
|
|
||||||
Install Bun:
|
Install Bun:
|
||||||
|
|
||||||
@ -124,17 +124,21 @@ This script generates:
|
|||||||
- Accurate description and usage examples
|
- Accurate description and usage examples
|
||||||
- Correct icon path (usually `../../../../.icons/your-icon.svg`)
|
- Correct icon path (usually `../../../../.icons/your-icon.svg`)
|
||||||
- Proper tags that describe your module
|
- Proper tags that describe your module
|
||||||
3. **Create `main.test.ts`** to test your module
|
3. **Create at least one `.tftest.hcl`** to test your module with `terraform test`
|
||||||
4. **Add any scripts** or additional files your module needs
|
4. **Add any scripts** or additional files your module needs
|
||||||
|
|
||||||
### 4. Test and Submit
|
### 4. Test and Submit
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Test your module
|
# Test your module (from the module directory)
|
||||||
bun test -t 'module-name'
|
terraform init -upgrade
|
||||||
|
terraform test -verbose
|
||||||
|
|
||||||
|
# Or run all tests in the repo
|
||||||
|
./scripts/terraform_test_all.sh
|
||||||
|
|
||||||
# Format code
|
# Format code
|
||||||
bun fmt
|
bun run fmt
|
||||||
|
|
||||||
# Commit and create PR
|
# Commit and create PR
|
||||||
git add .
|
git add .
|
||||||
@ -335,11 +339,12 @@ coder templates push test-[template-name] -d .
|
|||||||
### 2. Test Your Changes
|
### 2. Test Your Changes
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Test a specific module
|
# Test a specific module (from the module directory)
|
||||||
bun test -t 'module-name'
|
terraform init -upgrade
|
||||||
|
terraform test -verbose
|
||||||
|
|
||||||
# Test all modules
|
# Test all modules
|
||||||
bun test
|
./scripts/terraform_test_all.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. Maintain Backward Compatibility
|
### 3. Maintain Backward Compatibility
|
||||||
@ -388,7 +393,7 @@ Example: `https://github.com/coder/registry/compare/main...your-branch?template=
|
|||||||
### Every Module Must Have
|
### Every Module Must Have
|
||||||
|
|
||||||
- `main.tf` - Terraform code
|
- `main.tf` - Terraform code
|
||||||
- `main.test.ts` - Working tests
|
- One or more `.tftest.hcl` files - Working tests with `terraform test`
|
||||||
- `README.md` - Documentation with frontmatter
|
- `README.md` - Documentation with frontmatter
|
||||||
|
|
||||||
### Every Template Must Have
|
### Every Template Must Have
|
||||||
@ -488,6 +493,6 @@ When reporting bugs, include:
|
|||||||
2. **No tests** or broken tests
|
2. **No tests** or broken tests
|
||||||
3. **Hardcoded values** instead of variables
|
3. **Hardcoded values** instead of variables
|
||||||
4. **Breaking changes** without defaults
|
4. **Breaking changes** without defaults
|
||||||
5. **Not running** `bun fmt` before submitting
|
5. **Not running** formatting (`bun run fmt`) and tests (`terraform test`) before submitting
|
||||||
|
|
||||||
Happy contributing! 🚀
|
Happy contributing! 🚀
|
||||||
|
|||||||
50
registry/coder/modules/code-server/code-server.tftest.hcl
Normal file
50
registry/coder/modules/code-server/code-server.tftest.hcl
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
run "required_vars" {
|
||||||
|
command = plan
|
||||||
|
|
||||||
|
variables {
|
||||||
|
agent_id = "foo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
run "offline_and_use_cached_conflict" {
|
||||||
|
command = plan
|
||||||
|
|
||||||
|
variables {
|
||||||
|
agent_id = "foo"
|
||||||
|
use_cached = true
|
||||||
|
offline = true
|
||||||
|
}
|
||||||
|
|
||||||
|
expect_failures = [
|
||||||
|
resource.coder_script.code-server
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
run "offline_disallows_extensions" {
|
||||||
|
command = plan
|
||||||
|
|
||||||
|
variables {
|
||||||
|
agent_id = "foo"
|
||||||
|
offline = true
|
||||||
|
extensions = ["ms-python.python", "golang.go"]
|
||||||
|
}
|
||||||
|
|
||||||
|
expect_failures = [
|
||||||
|
resource.coder_script.code-server
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
run "url_with_folder_query" {
|
||||||
|
command = plan
|
||||||
|
|
||||||
|
variables {
|
||||||
|
agent_id = "foo"
|
||||||
|
folder = "/home/coder/project"
|
||||||
|
port = 13337
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {
|
||||||
|
condition = resource.coder_app.code-server.url == "http://localhost:13337/?folder=%2Fhome%2Fcoder%2Fproject"
|
||||||
|
error_message = "coder_app URL must include encoded folder query param"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,38 +0,0 @@
|
|||||||
import { describe, expect, it } from "bun:test";
|
|
||||||
import {
|
|
||||||
runTerraformApply,
|
|
||||||
runTerraformInit,
|
|
||||||
testRequiredVariables,
|
|
||||||
} from "~test";
|
|
||||||
|
|
||||||
describe("code-server", async () => {
|
|
||||||
await runTerraformInit(import.meta.dir);
|
|
||||||
|
|
||||||
testRequiredVariables(import.meta.dir, {
|
|
||||||
agent_id: "foo",
|
|
||||||
});
|
|
||||||
|
|
||||||
it("use_cached and offline can not be used together", () => {
|
|
||||||
const t = async () => {
|
|
||||||
await runTerraformApply(import.meta.dir, {
|
|
||||||
agent_id: "foo",
|
|
||||||
use_cached: "true",
|
|
||||||
offline: "true",
|
|
||||||
});
|
|
||||||
};
|
|
||||||
expect(t).toThrow("Offline and Use Cached can not be used together");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("offline and extensions can not be used together", () => {
|
|
||||||
const t = async () => {
|
|
||||||
await runTerraformApply(import.meta.dir, {
|
|
||||||
agent_id: "foo",
|
|
||||||
offline: "true",
|
|
||||||
extensions: '["1", "2"]',
|
|
||||||
});
|
|
||||||
};
|
|
||||||
expect(t).toThrow("Offline mode does not allow extensions to be installed");
|
|
||||||
});
|
|
||||||
|
|
||||||
// More tests depend on shebang refactors
|
|
||||||
});
|
|
||||||
131
registry/coder/modules/jetbrains/jetbrains.tftest.hcl
Normal file
131
registry/coder/modules/jetbrains/jetbrains.tftest.hcl
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
run "requires_agent_and_folder" {
|
||||||
|
command = plan
|
||||||
|
|
||||||
|
# Setting both required vars should plan
|
||||||
|
variables {
|
||||||
|
agent_id = "foo"
|
||||||
|
folder = "/home/coder"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
run "creates_parameter_when_default_empty_latest" {
|
||||||
|
command = plan
|
||||||
|
|
||||||
|
variables {
|
||||||
|
agent_id = "foo"
|
||||||
|
folder = "/home/coder"
|
||||||
|
major_version = "latest"
|
||||||
|
}
|
||||||
|
|
||||||
|
# When default is empty, a coder_parameter should be created
|
||||||
|
assert {
|
||||||
|
condition = can(data.coder_parameter.jetbrains_ides[0].type)
|
||||||
|
error_message = "Expected data.coder_parameter.jetbrains_ides to exist when default is empty"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
run "no_apps_when_default_empty" {
|
||||||
|
command = plan
|
||||||
|
|
||||||
|
variables {
|
||||||
|
agent_id = "foo"
|
||||||
|
folder = "/home/coder"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {
|
||||||
|
condition = length(resource.coder_app.jetbrains) == 0
|
||||||
|
error_message = "Expected no coder_app resources when default is empty"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
run "single_app_when_default_GO" {
|
||||||
|
command = plan
|
||||||
|
|
||||||
|
variables {
|
||||||
|
agent_id = "foo"
|
||||||
|
folder = "/home/coder"
|
||||||
|
default = ["GO"]
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {
|
||||||
|
condition = length(resource.coder_app.jetbrains) == 1
|
||||||
|
error_message = "Expected exactly one coder_app when default contains GO"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
run "url_contains_required_params" {
|
||||||
|
command = apply
|
||||||
|
|
||||||
|
variables {
|
||||||
|
agent_id = "test-agent-123"
|
||||||
|
folder = "/custom/project/path"
|
||||||
|
default = ["GO"]
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {
|
||||||
|
condition = anytrue([for app in values(resource.coder_app.jetbrains) : length(regexall("jetbrains://gateway/coder", app.url)) > 0])
|
||||||
|
error_message = "URL must contain jetbrains scheme"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {
|
||||||
|
condition = anytrue([for app in values(resource.coder_app.jetbrains) : length(regexall("&folder=/custom/project/path", app.url)) > 0])
|
||||||
|
error_message = "URL must include folder path"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {
|
||||||
|
condition = anytrue([for app in values(resource.coder_app.jetbrains) : length(regexall("ide_product_code=GO", app.url)) > 0])
|
||||||
|
error_message = "URL must include product code"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {
|
||||||
|
condition = anytrue([for app in values(resource.coder_app.jetbrains) : length(regexall("ide_build_number=", app.url)) > 0])
|
||||||
|
error_message = "URL must include build number"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
run "includes_agent_name_when_set" {
|
||||||
|
command = apply
|
||||||
|
|
||||||
|
variables {
|
||||||
|
agent_id = "test-agent-123"
|
||||||
|
agent_name = "main-agent"
|
||||||
|
folder = "/custom/project/path"
|
||||||
|
default = ["GO"]
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {
|
||||||
|
condition = anytrue([for app in values(resource.coder_app.jetbrains) : length(regexall("&agent_name=main-agent", app.url)) > 0])
|
||||||
|
error_message = "URL must include agent_name when provided"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
run "parameter_order_when_default_empty" {
|
||||||
|
command = plan
|
||||||
|
|
||||||
|
variables {
|
||||||
|
agent_id = "foo"
|
||||||
|
folder = "/home/coder"
|
||||||
|
coder_parameter_order = 5
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {
|
||||||
|
condition = data.coder_parameter.jetbrains_ides[0].order == 5
|
||||||
|
error_message = "Expected coder_parameter order to be set to 5"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
run "app_order_when_default_not_empty" {
|
||||||
|
command = plan
|
||||||
|
|
||||||
|
variables {
|
||||||
|
agent_id = "foo"
|
||||||
|
folder = "/home/coder"
|
||||||
|
default = ["GO"]
|
||||||
|
coder_app_order = 10
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {
|
||||||
|
condition = anytrue([for app in values(resource.coder_app.jetbrains) : app.order == 10])
|
||||||
|
error_message = "Expected coder_app order to be set to 10"
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,77 +0,0 @@
|
|||||||
import { describe, expect, it } from "bun:test";
|
|
||||||
import {
|
|
||||||
runTerraformApply,
|
|
||||||
runTerraformInit,
|
|
||||||
testRequiredVariables,
|
|
||||||
} from "~test";
|
|
||||||
|
|
||||||
describe("zed", async () => {
|
|
||||||
await runTerraformInit(import.meta.dir);
|
|
||||||
|
|
||||||
testRequiredVariables(import.meta.dir, {
|
|
||||||
agent_id: "foo",
|
|
||||||
});
|
|
||||||
|
|
||||||
it("default output", async () => {
|
|
||||||
const state = await runTerraformApply(import.meta.dir, {
|
|
||||||
agent_id: "foo",
|
|
||||||
});
|
|
||||||
expect(state.outputs.zed_url.value).toBe("zed://ssh/default.coder");
|
|
||||||
|
|
||||||
const coder_app = state.resources.find(
|
|
||||||
(res) => res.type === "coder_app" && res.name === "zed",
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(coder_app).not.toBeNull();
|
|
||||||
expect(coder_app?.instances.length).toBe(1);
|
|
||||||
expect(coder_app?.instances[0].attributes.order).toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("adds folder", async () => {
|
|
||||||
const state = await runTerraformApply(import.meta.dir, {
|
|
||||||
agent_id: "foo",
|
|
||||||
folder: "/foo/bar",
|
|
||||||
});
|
|
||||||
expect(state.outputs.zed_url.value).toBe("zed://ssh/default.coder/foo/bar");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("expect order to be set", async () => {
|
|
||||||
const state = await runTerraformApply(import.meta.dir, {
|
|
||||||
agent_id: "foo",
|
|
||||||
order: "22",
|
|
||||||
});
|
|
||||||
|
|
||||||
const coder_app = state.resources.find(
|
|
||||||
(res) => res.type === "coder_app" && res.name === "zed",
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(coder_app).not.toBeNull();
|
|
||||||
expect(coder_app?.instances.length).toBe(1);
|
|
||||||
expect(coder_app?.instances[0].attributes.order).toBe(22);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("expect display_name to be set", async () => {
|
|
||||||
const state = await runTerraformApply(import.meta.dir, {
|
|
||||||
agent_id: "foo",
|
|
||||||
display_name: "Custom Zed",
|
|
||||||
});
|
|
||||||
|
|
||||||
const coder_app = state.resources.find(
|
|
||||||
(res) => res.type === "coder_app" && res.name === "zed",
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(coder_app).not.toBeNull();
|
|
||||||
expect(coder_app?.instances.length).toBe(1);
|
|
||||||
expect(coder_app?.instances[0].attributes.display_name).toBe("Custom Zed");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("adds agent_name to hostname", async () => {
|
|
||||||
const state = await runTerraformApply(import.meta.dir, {
|
|
||||||
agent_id: "foo",
|
|
||||||
agent_name: "myagent",
|
|
||||||
});
|
|
||||||
expect(state.outputs.zed_url.value).toBe(
|
|
||||||
"zed://ssh/myagent.default.default.coder",
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
Loading…
x
Reference in New Issue
Block a user