Skip to content

Commit 96fc45a

Browse files
committed
Test extension data source against Kernel
1 parent 6aa8f7e commit 96fc45a

5 files changed

Lines changed: 168 additions & 48 deletions

File tree

.github/workflows/acceptance.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ jobs:
3333
- name: Extension
3434
package: ./internal/resources/extension
3535
project_id_required: true
36+
- name: Extension data source
37+
package: ./internal/datasources/extension
38+
project_id_required: true
3639
# Keep the job timeout above the go test timeout so Go can report the test
3740
# timeout before the runner stops the job. Either hard timeout can bypass
3841
# t.Cleanup, so release operators still inspect for leaked test resources.

docs/acceptance.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ operation. Secrets must remain GitHub Actions secrets and must not be printed.
4343
| `kernel_extension` resource | Test present | Upload, checksum state, no-drift plan, metadata-only import, content replacement with new ID, old-ID disappearance, delete, and 404 verification. | Add project-qualified import to live coverage before the v1 tag. |
4444
| `kernel_browser_pool` data source | Test present | A uniquely created pool is read by canonical ID and byte-exact name, including normalized durable configuration, a no-drift plan, and post-destroy coded `not_found` verification. | None. |
4545
| `kernel_project` data source | Test present | A uniquely created project is read by canonical ID and exact name; the provider default resolves the configured project; metadata, no-drift planning, and post-destroy coded `not_found` are verified. | None. |
46-
| `kernel_extension` data source | Test missing; tag blocker | Unit and fake-client tests only. | Use a uniquely uploaded `kernel_extension` fixture and verify ID/name metadata lookup plus no drift. |
46+
| `kernel_extension` data source | Test present | A uniquely uploaded extension is read by canonical ID and exact name through explicit and provider-default project scope; metadata, no-drift planning, and post-destroy coded `not_found` are verified. | None. |
4747
| `kernel_profile` data source | Test missing; tag blocker | Unit and fake-client tests only. | Add durable SDK fixture create/delete helpers, then verify ID/name lookup and cleanup. Do not model runtime-written profile contents. |
4848
| `kernel_proxy` data source | Test missing; tag blocker | Unit and fake-client tests only. | Add a durable, non-secret-leaking proxy fixture strategy and verify ID/name lookup, masked metadata, and cleanup. |
4949
| `kernel_app` data source | Fixture blocked; tag blocker | Unit, SDK transport, pagination, ambiguity, project-scope, and Framework state tests only. | Provide a release-owned running deployment fixture or a deterministic durable deployment setup. Verify exact app/version lookup without invocation and without exposing env values. |
@@ -55,13 +55,14 @@ against the release commit. The release record below supplies that evidence.
5555

5656
## Current Commands
5757

58-
Run the five existing packages independently for fast failure isolation:
58+
Run the six existing packages independently for fast failure isolation:
5959

6060
```sh
6161
go test -count=1 -timeout=30m -v ./internal/resources/project -run TestAcc
6262
go test -count=1 -timeout=30m -v ./internal/datasources/project -run TestAcc
6363
go test -count=1 -timeout=30m -v ./internal/resources/browserpool -run TestAcc
6464
go test -count=1 -timeout=30m -v ./internal/resources/extension -run TestAcc
65+
go test -count=1 -timeout=30m -v ./internal/datasources/extension -run TestAcc
6566
go test -count=1 -timeout=30m -v ./internal/datasources/browserpool -run TestAcc
6667
```
6768

internal/acctest/extension.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package acctest
2+
3+
import (
4+
"archive/zip"
5+
"crypto/sha256"
6+
"encoding/hex"
7+
"os"
8+
"path/filepath"
9+
"testing"
10+
)
11+
12+
// ExtensionArchive writes a minimal Chrome extension ZIP and returns its path and SHA-256 checksum.
13+
func ExtensionArchive(t testing.TB, marker string) (string, string) {
14+
t.Helper()
15+
16+
path := filepath.Join(t.TempDir(), "extension.zip")
17+
file, err := os.Create(path)
18+
if err != nil {
19+
t.Fatalf("create extension archive: %v", err)
20+
}
21+
defer file.Close()
22+
23+
writer := zip.NewWriter(file)
24+
writeExtensionArchiveFile(t, writer, "manifest.json", `{"manifest_version":3,"name":"Kernel Terraform acceptance","version":"1.0.0"}`)
25+
writeExtensionArchiveFile(t, writer, "marker.txt", marker)
26+
if err := writer.Close(); err != nil {
27+
t.Fatalf("close extension ZIP: %v", err)
28+
}
29+
if err := file.Close(); err != nil {
30+
t.Fatalf("close extension archive: %v", err)
31+
}
32+
33+
contents, err := os.ReadFile(path)
34+
if err != nil {
35+
t.Fatalf("read extension archive: %v", err)
36+
}
37+
checksum := sha256.Sum256(contents)
38+
return path, hex.EncodeToString(checksum[:])
39+
}
40+
41+
func writeExtensionArchiveFile(t testing.TB, writer *zip.Writer, name, contents string) {
42+
t.Helper()
43+
44+
entry, err := writer.Create(name)
45+
if err != nil {
46+
t.Fatalf("create %s in extension ZIP: %v", name, err)
47+
}
48+
if _, err := entry.Write([]byte(contents)); err != nil {
49+
t.Fatalf("write %s in extension ZIP: %v", name, err)
50+
}
51+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package extension_test
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"os"
7+
"testing"
8+
"time"
9+
10+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
11+
"github.com/hashicorp/terraform-plugin-testing/terraform"
12+
"github.com/kernel/terraform-provider-kernel/internal/acctest"
13+
"github.com/kernel/terraform-provider-kernel/internal/projectscope"
14+
)
15+
16+
const extensionDataSourceFixtureName = "kernel_extension.data_source_test"
17+
18+
func TestAccExtensionDataSourceByIDAndName(t *testing.T) {
19+
name := acctest.UniqueName(t, "extension-data")
20+
sourcePath, _ := acctest.ExtensionArchive(t, "data-source")
21+
projectID := os.Getenv(acctest.EnvProjectID)
22+
config := testAccExtensionDataSourceConfig(name, sourcePath, projectID)
23+
24+
resource.Test(t, resource.TestCase{
25+
PreCheck: func() {
26+
acctest.PreCheck(t)
27+
if projectID == "" {
28+
t.Fatalf("%s must be set for the extension data source acceptance test", acctest.EnvProjectID)
29+
}
30+
},
31+
ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories(),
32+
CheckDestroy: testAccCheckExtensionDataSourceFixtureDestroyed(),
33+
Steps: []resource.TestStep{
34+
{
35+
Config: config,
36+
Check: resource.ComposeAggregateTestCheckFunc(
37+
testAccCaptureExtensionDataSourceFixture(t),
38+
resource.TestCheckResourceAttrPair("data.kernel_extension.by_id", "id", extensionDataSourceFixtureName, "id"),
39+
resource.TestCheckResourceAttrPair("data.kernel_extension.by_id", "name", extensionDataSourceFixtureName, "name"),
40+
resource.TestCheckResourceAttrPair("data.kernel_extension.by_name", "id", extensionDataSourceFixtureName, "id"),
41+
resource.TestCheckResourceAttrPair("data.kernel_extension.by_name", "name", extensionDataSourceFixtureName, "name"),
42+
resource.TestCheckResourceAttr("data.kernel_extension.by_id", "project_id", projectID),
43+
resource.TestCheckNoResourceAttr("data.kernel_extension.by_name", "project_id"),
44+
resource.TestCheckResourceAttrSet("data.kernel_extension.by_id", "created_at"),
45+
resource.TestCheckResourceAttrSet("data.kernel_extension.by_id", "size_bytes"),
46+
resource.TestCheckNoResourceAttr("data.kernel_extension.by_id", "last_used_at"),
47+
),
48+
},
49+
{
50+
Config: config,
51+
PlanOnly: true,
52+
},
53+
},
54+
})
55+
}
56+
57+
func testAccExtensionDataSourceConfig(name, sourcePath, projectID string) string {
58+
return acctest.ProviderConfig() + fmt.Sprintf(`
59+
resource "kernel_extension" "data_source_test" {
60+
name = %[1]q
61+
source_path = %[2]q
62+
source_sha256 = filesha256(%[2]q)
63+
}
64+
65+
data "kernel_extension" "by_id" {
66+
id = kernel_extension.data_source_test.id
67+
project_id = %[3]q
68+
}
69+
70+
data "kernel_extension" "by_name" {
71+
name = kernel_extension.data_source_test.name
72+
}
73+
`, name, sourcePath, projectID)
74+
}
75+
76+
func testAccCaptureExtensionDataSourceFixture(t *testing.T) resource.TestCheckFunc {
77+
t.Helper()
78+
79+
return func(state *terraform.State) error {
80+
resourceState, ok := state.RootModule().Resources[extensionDataSourceFixtureName]
81+
if !ok || resourceState.Primary == nil || resourceState.Primary.ID == "" {
82+
return fmt.Errorf("missing ID for %s", extensionDataSourceFixtureName)
83+
}
84+
acctest.CleanupExtension(t, resourceState.Primary.Attributes["project_id"], resourceState.Primary.ID)
85+
return nil
86+
}
87+
}
88+
89+
func testAccCheckExtensionDataSourceFixtureDestroyed() resource.TestCheckFunc {
90+
return func(state *terraform.State) error {
91+
resourceState, ok := state.RootModule().Resources[extensionDataSourceFixtureName]
92+
if !ok || resourceState.Primary == nil || resourceState.Primary.ID == "" {
93+
return nil
94+
}
95+
96+
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
97+
defer cancel()
98+
99+
projectID := resourceState.Primary.Attributes["project_id"]
100+
_, err := acctest.ClientFromEnv().GetExtension(ctx, projectID, resourceState.Primary.ID)
101+
if projectscope.IsNotFound(err) {
102+
return nil
103+
}
104+
if err != nil {
105+
return fmt.Errorf("read Kernel extension %s after destroy: %w", resourceState.Primary.ID, err)
106+
}
107+
return fmt.Errorf("Kernel extension %s still exists after destroy", resourceState.Primary.ID)
108+
}
109+
}

internal/resources/extension/resource_acc_test.go

Lines changed: 2 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
package extension_test
22

33
import (
4-
"archive/zip"
54
"context"
6-
"crypto/sha256"
7-
"encoding/hex"
85
"fmt"
96
"os"
10-
"path/filepath"
117
"testing"
128
"time"
139

@@ -20,8 +16,8 @@ const extensionResourceName = "kernel_extension.test"
2016

2117
func TestAccExtensionLifecycle(t *testing.T) {
2218
name := acctest.UniqueName(t, "extension")
23-
firstPath, firstChecksum := testAccWriteExtensionArchive(t, "first")
24-
secondPath, secondChecksum := testAccWriteExtensionArchive(t, "second")
19+
firstPath, firstChecksum := acctest.ExtensionArchive(t, "first")
20+
secondPath, secondChecksum := acctest.ExtensionArchive(t, "second")
2521
firstConfig := testAccExtensionConfig(name, firstPath)
2622
secondConfig := testAccExtensionConfig(name, secondPath)
2723
var firstID, secondID string
@@ -88,46 +84,6 @@ resource "kernel_extension" "test" {
8884
`, name, sourcePath, sourcePath)
8985
}
9086

91-
func testAccWriteExtensionArchive(t *testing.T, marker string) (string, string) {
92-
t.Helper()
93-
94-
path := filepath.Join(t.TempDir(), "extension.zip")
95-
file, err := os.Create(path)
96-
if err != nil {
97-
t.Fatalf("create extension archive: %v", err)
98-
}
99-
defer file.Close()
100-
101-
writer := zip.NewWriter(file)
102-
testAccWriteZipFile(t, writer, "manifest.json", `{"manifest_version":3,"name":"Kernel Terraform acceptance","version":"1.0.0"}`)
103-
testAccWriteZipFile(t, writer, "marker.txt", marker)
104-
if err := writer.Close(); err != nil {
105-
t.Fatalf("close extension ZIP: %v", err)
106-
}
107-
if err := file.Close(); err != nil {
108-
t.Fatalf("close extension archive: %v", err)
109-
}
110-
111-
contents, err := os.ReadFile(path)
112-
if err != nil {
113-
t.Fatalf("read extension archive: %v", err)
114-
}
115-
checksum := sha256.Sum256(contents)
116-
return path, hex.EncodeToString(checksum[:])
117-
}
118-
119-
func testAccWriteZipFile(t *testing.T, writer *zip.Writer, name, contents string) {
120-
t.Helper()
121-
122-
entry, err := writer.Create(name)
123-
if err != nil {
124-
t.Fatalf("create %s in extension ZIP: %v", name, err)
125-
}
126-
if _, err := entry.Write([]byte(contents)); err != nil {
127-
t.Fatalf("write %s in extension ZIP: %v", name, err)
128-
}
129-
}
130-
13187
func testAccCaptureExtensionID(t *testing.T, resourceName string, extensionID *string) resource.TestCheckFunc {
13288
t.Helper()
13389

0 commit comments

Comments
 (0)