Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/acceptance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ jobs:
- name: Browser pool
package: ./internal/resources/browserpool
project_id_required: true
- name: Browser pool data source
package: ./internal/datasources/browserpool
project_id_required: true
- name: Project
package: ./internal/resources/project
project_id_required: false
Expand Down
15 changes: 8 additions & 7 deletions docs/acceptance.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This document is the live-API release gate for the provider's selected public
surface. Unit tests remain the fast default. Acceptance tests run after changes
reach `main`, through explicit local opt-in, or by manual workflow dispatch.

The selected surface contains two managed resources and four read-only data
The selected surface contains two managed resources and five read-only data
sources. It does not claim coverage for future or unregistered Kernel objects.

## Gate Rules
Expand All @@ -29,7 +29,7 @@ export KERNEL_ALT_PROJECT_ID=... # optional second project
export KERNEL_BASE_URL=... # optional non-production API
```

`KERNEL_PROJECT_ID` is required for the browser-pool resource and all four data
`KERNEL_PROJECT_ID` is required for the browser-pool resource and all five data
sources. The project resource is organization-scoped and does not require it.

## Matrix
Expand All @@ -38,6 +38,7 @@ sources. The project resource is organization-scoped and does not require it.
| --- | --- | --- |
| `kernel_project` resource | `./internal/resources/project` | Create, rename with stable ID, no-drift plan, canonical-ID import, post-import no drift, delete, and HTTP 404 verification. |
| `kernel_browser_pool` resource | `./internal/resources/browserpool` | Create, durable update with stable ID, no-drift plan, provider-default and explicit project scope, bare and project-qualified import, non-force delete, and HTTP 404 verification. |
| `kernel_browser_pool` data source | `./internal/datasources/browserpool` | Create a unique browser-pool fixture, read it by canonical ID and exact name with explicit project scope, verify normalized durable configuration and no drift, then delete and require coded `not_found`. |
| `kernel_project` data source | `./internal/datasources/project` | Create a unique project fixture, read it by ID and exact name, read the provider-default project, verify durable metadata and no drift, then delete and require coded `not_found`. |
| `kernel_profile` data source | `./internal/datasources/profile` | Create a durable profile fixture through the SDK, read it by ID and exact name with explicit and default project scope, verify durable metadata and no drift, then delete and require coded `not_found`. |
| `kernel_proxy` data source | `./internal/datasources/proxy` | Create a managed datacenter proxy fixture through the SDK, read it by ID and exact name with explicit and default project scope, verify durable masked metadata and no drift, then delete and require coded `not_found`. |
Expand All @@ -53,21 +54,21 @@ Run packages independently for fast failure isolation:
```sh
go test -count=1 -timeout=30m -v ./internal/resources/project -run TestAcc
go test -count=1 -timeout=30m -v ./internal/resources/browserpool -run TestAcc
go test -count=1 -timeout=30m -v ./internal/datasources/browserpool -run TestAcc
go test -count=1 -timeout=30m -v ./internal/datasources/project -run TestAcc
go test -count=1 -timeout=30m -v ./internal/datasources/profile -run TestAcc
go test -count=1 -timeout=30m -v ./internal/datasources/proxy -run TestAcc
go test -count=1 -timeout=30m -v ./internal/datasources/extension -run TestAcc
```

The `Acceptance` workflow runs the same six packages as separate matrix jobs
The `Acceptance` workflow runs the same seven packages as separate matrix jobs
with `fail-fast: false` after changes reach `main` and on manual dispatch.

## Outside The Selected Surface

The release does not include a browser-pool data source or profile, proxy,
extension, deployment, app, or API-key resources. Runtime/session operations
remain outside Terraform. Unregistered surfaces are not acceptance blockers for
this selected release.
The release does not include profile, proxy, extension, deployment, app, or
API-key resources. Runtime/session operations remain outside Terraform.
Unregistered surfaces are not acceptance blockers for this selected release.

## Release Record

Expand Down
147 changes: 147 additions & 0 deletions internal/datasources/browserpool/datasource_acc_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package browserpool_test

import (
"context"
"fmt"
"os"
"testing"
"time"

"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
"github.com/kernel/terraform-provider-kernel/internal/acctest"
"github.com/kernel/terraform-provider-kernel/internal/projectscope"
)

const browserPoolAcceptanceResourceName = "kernel_browser_pool.data_source_test"

func TestAccBrowserPoolDataSourceByIDAndName(t *testing.T) {
name := acctest.UniqueName(t, "browser-pool-data")
projectID := os.Getenv(acctest.EnvAltProjectID)
if projectID == "" {
projectID = os.Getenv(acctest.EnvProjectID)
}
config := testAccBrowserPoolDataSourceConfig(name, projectID)

resource.Test(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(t)
if projectID == "" {
t.Fatalf("%s or %s must be set for the browser pool data source acceptance test", acctest.EnvProjectID, acctest.EnvAltProjectID)
}
Comment thread
IlyaasK marked this conversation as resolved.
},
ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories(),
CheckDestroy: testAccCheckBrowserPoolDataSourceDestroyed(),
Steps: []resource.TestStep{
{
Config: config,
Check: resource.ComposeAggregateTestCheckFunc(
testAccCaptureBrowserPoolDataSourceID(t),
resource.TestCheckResourceAttrPair("data.kernel_browser_pool.by_id", "id", browserPoolAcceptanceResourceName, "id"),
resource.TestCheckResourceAttrPair("data.kernel_browser_pool.by_name", "id", browserPoolAcceptanceResourceName, "id"),
resource.TestCheckResourceAttrPair("data.kernel_browser_pool.by_id", "name", browserPoolAcceptanceResourceName, "name"),
resource.TestCheckResourceAttr("data.kernel_browser_pool.by_id", "project_id", projectID),
resource.TestCheckResourceAttr("data.kernel_browser_pool.by_name", "project_id", projectID),
testAccCheckBrowserPoolDataSourceState("data.kernel_browser_pool.by_id", name),
testAccCheckBrowserPoolDataSourceState("data.kernel_browser_pool.by_name", name),
),
},
{
Config: config,
PlanOnly: true,
},
},
})
}

func testAccCheckBrowserPoolDataSourceDestroyed() resource.TestCheckFunc {
return func(state *terraform.State) error {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

client := acctest.ClientFromEnv()
for _, resourceState := range state.RootModule().Resources {
if resourceState.Type != "kernel_browser_pool" || resourceState.Primary == nil || resourceState.Primary.ID == "" {
continue
}

_, err := client.GetBrowserPool(ctx, resourceState.Primary.Attributes["project_id"], resourceState.Primary.ID)
if projectscope.IsNotFound(err) {
continue
}
if err != nil {
return fmt.Errorf("read Kernel browser pool %s after destroy: %w", resourceState.Primary.ID, err)
}
return fmt.Errorf("Kernel browser pool %s still exists after destroy", resourceState.Primary.ID)
}
return nil
}
}

func testAccBrowserPoolDataSourceConfig(name, projectID string) string {
return acctest.ProviderConfig() + fmt.Sprintf(`
resource "kernel_browser_pool" "data_source_test" {
name = %[1]q
size = 1
project_id = %[2]q
start_url = "chrome://newtab"
headless = true
kiosk_mode = false
stealth = false
timeout_seconds = 90
fill_rate_per_minute = 0
viewport = {
width = 1280
height = 800
refresh_rate = 60
}
chrome_policy = jsonencode({
HomepageLocation = "https://example.com"
RestoreOnStartup = 4
})
}

data "kernel_browser_pool" "by_id" {
id = kernel_browser_pool.data_source_test.id
project_id = %[2]q
}

data "kernel_browser_pool" "by_name" {
name = kernel_browser_pool.data_source_test.name
project_id = %[2]q
}
`, name, projectID)
}

func testAccCaptureBrowserPoolDataSourceID(t *testing.T) resource.TestCheckFunc {
t.Helper()

return func(state *terraform.State) error {
resourceState, ok := state.RootModule().Resources[browserPoolAcceptanceResourceName]
if !ok || resourceState.Primary == nil || resourceState.Primary.ID == "" {
return fmt.Errorf("missing ID for %s", browserPoolAcceptanceResourceName)
}
acctest.CleanupBrowserPool(t, resourceState.Primary.Attributes["project_id"], resourceState.Primary.ID)
return nil
}
}

func testAccCheckBrowserPoolDataSourceState(resourceName, name string) resource.TestCheckFunc {
return resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "name", name),
resource.TestCheckResourceAttr(resourceName, "size", "1"),
resource.TestCheckResourceAttr(resourceName, "start_url", "chrome://newtab"),
resource.TestCheckResourceAttr(resourceName, "headless", "true"),
resource.TestCheckResourceAttr(resourceName, "kiosk_mode", "false"),
resource.TestCheckResourceAttr(resourceName, "stealth", "false"),
resource.TestCheckResourceAttr(resourceName, "timeout_seconds", "90"),
resource.TestCheckResourceAttr(resourceName, "fill_rate_per_minute", "0"),
resource.TestCheckResourceAttr(resourceName, "viewport.width", "1280"),
resource.TestCheckResourceAttr(resourceName, "viewport.height", "800"),
resource.TestCheckResourceAttr(resourceName, "viewport.refresh_rate", "60"),
resource.TestCheckResourceAttr(resourceName, "chrome_policy", `{"HomepageLocation":"https://example.com","RestoreOnStartup":4}`),
resource.TestCheckResourceAttr(resourceName, "extension_ids.#", "0"),
resource.TestCheckNoResourceAttr(resourceName, "profile_id"),
resource.TestCheckNoResourceAttr(resourceName, "proxy_id"),
Comment thread
IlyaasK marked this conversation as resolved.
)
}