Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add GitHub Actions for e2e test #62

Merged
merged 25 commits into from
Feb 27, 2025
Merged
Show file tree
Hide file tree
Changes from 23 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
37 changes: 37 additions & 0 deletions .github/workflows/e2e_test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: E2E tests

on:
push:
paths-ignore:
- "README.md"
- docs/**
- examples/**
pull_request:
paths-ignore:
- "README.md"
- docs/**
- examples/**
branches:
- main

permissions:
contents: read

jobs:
e2e_test:
name: E2E tests
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1
with:
go-version-file: "go.mod"
cache: true
- uses: hashicorp/setup-terraform@651471c36a6092792c552e8b1bef71e592b462d8 # v3.1.1
- run: go mod download
- run: |
make testacc
env:
TROCCO_API_KEY: ${{ secrets.TROCCO_API_KEY }}
TROCCO_TEST_URL: https://trocco.io
5 changes: 5 additions & 0 deletions GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,8 @@ default: testacc
.PHONY: testacc
testacc:
TF_ACC=1 go test ./... -v $(TESTARGS) -timeout 120m

# example)
# $ TROCCO_TEST_URL=https://localhost:4000 \
# TROCCO_API_KEY=**** \
# make testacc TESTARGS="-run TestAccConnectionResource"
5 changes: 4 additions & 1 deletion docs/resources/connection.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,10 @@ resource "trocco_connection" "s3_with_assume_role" {
- `aws_auth_type` (String) S3: The authentication type for the S3 connection. It must be one of `iam_user` or `assume_role`.
- `aws_iam_user` (Attributes) S3: IAM User configuration. (see [below for nested schema](#nestedatt--aws_iam_user))
- `description` (String) The description of the connection.
- `driver` (String) PostgreSQL: The name of a PostgreSQL driver.
- `driver` (String) Snowflake, MySQL, PostgreSQL: The name of a Database driver.
- MySQL: null, mysql_connector_java_5_1_49
- Snowflake: null, snowflake_jdbc_3_14_2, snowflake_jdbc_3_17_0,
- PostgreSQL: postgresql_42_5_1, postgresql_9_4_1205_jdbc41
- `gateway` (Attributes) MySQL, PostgreSQL: Whether to connect via SSH (see [below for nested schema](#nestedatt--gateway))
- `host` (String) Snowflake, PostgreSQL: The host of a (Snowflake, PostgreSQL) account.
- `password` (String, Sensitive) Snowflake, PostgreSQL: The password for the (Snowflake, PostgreSQL) user.
Expand Down
4 changes: 2 additions & 2 deletions internal/client/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ type CreateConnectionInput struct {
SSLClientCa *string `json:"ssl_client_ca,omitempty"`
SSLClientKey *string `json:"ssl_client_key,omitempty"`
SSLMode *parameter.NullableString `json:"ssl_mode,omitempty"`
Driver *string `json:"driver,omitempty"`
Driver *parameter.NullableString `json:"driver,omitempty"`
}

type UpdateConnectionInput struct {
Expand Down Expand Up @@ -163,7 +163,7 @@ type UpdateConnectionInput struct {
SSLClientCa *string `json:"ssl_client_ca,omitempty"`
SSLClientKey *string `json:"ssl_client_key,omitempty"`
SSLMode *parameter.NullableString `json:"ssl_mode,omitempty"`
Driver *string `json:"driver,omitempty"`
Driver *parameter.NullableString `json:"driver,omitempty"`
}

func (c *TroccoClient) GetConnections(connectionType string, in *GetConnectionsInput) (*ConnectionList, error) {
Expand Down
48 changes: 43 additions & 5 deletions internal/provider/connection_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ func (m *connectionResourceModel) ToCreateConnectionInput() *client.CreateConnec
AWSAuthType: m.AWSAuthType.ValueStringPointer(),

// PostgreSQL Fields
Driver: m.Driver.ValueStringPointer(),
Driver: model.NewNullableString(m.Driver),
}

// SSL Fields
Expand Down Expand Up @@ -182,7 +182,7 @@ func (m *connectionResourceModel) ToUpdateConnectionInput() *client.UpdateConnec
AWSAuthType: m.AWSAuthType.ValueStringPointer(),

// PostgreSQL Fields
Driver: m.Driver.ValueStringPointer(),
Driver: model.NewNullableString(m.Driver),
}

// SSL Fields
Expand Down Expand Up @@ -569,10 +569,23 @@ func (r *connectionResource) Schema(

// PostgreSQL Fields
"driver": schema.StringAttribute{
MarkdownDescription: "PostgreSQL: The name of a PostgreSQL driver.",
Optional: true,
MarkdownDescription: `Snowflake, MySQL, PostgreSQL: The name of a Database driver.
- MySQL: null, mysql_connector_java_5_1_49
- Snowflake: null, snowflake_jdbc_3_14_2, snowflake_jdbc_3_17_0,
- PostgreSQL: postgresql_42_5_1, postgresql_9_4_1205_jdbc41
`,
Optional: true,
Validators: []validator.String{
stringvalidator.OneOf("postgresql_42_5_1", "postgresql_9_4_1205_jdbc41"),
stringvalidator.OneOf(
// MySQL
"mysql_connector_java_5_1_49",
// Snowflake
"snowflake_jdbc_3_14_2",
"snowflake_jdbc_3_17_0",
// PostgreSQL
"postgresql_42_5_1",
"postgresql_9_4_1205_jdbc41",
),
},
},
},
Expand Down Expand Up @@ -885,6 +898,7 @@ func (r *connectionResource) ValidateConfig(
if plan.AuthMethod.ValueString() == "user_password" {
validateRequiredString(plan.Password, "password", "Snowflake", resp)
}
validateStringAgainstPatterns(plan.Driver, "driver", "Snowflake", resp, "snowflake_jdbc_3_14_2", "snowflake_jdbc_3_17_0")
case "gcs":
validateRequiredString(plan.ApplicationName, "application_name", "GCS", resp)
validateRequiredString(plan.ServiceAccountEmail, "service_account_email", "GCS", resp)
Expand All @@ -896,6 +910,7 @@ func (r *connectionResource) ValidateConfig(
validateRequiredInt(plan.Port, "port", "MySQL", resp)
validateRequiredString(plan.UserName, "user_name", "MySQL", resp)
validateRequiredString(plan.Password, "password", "MySQL", resp)
validateStringAgainstPatterns(plan.Driver, "driver", "MySQL", resp, "mysql_connector_java_5_1_49")
if plan.Gateway != nil {
validateRequiredString(plan.Gateway.Host, "gateway.host", "MySQL", resp)
validateRequiredInt(plan.Gateway.Port, "gateway.port", "MySQL", resp)
Expand Down Expand Up @@ -948,6 +963,7 @@ func (r *connectionResource) ValidateConfig(
validateRequiredInt(plan.Port, "port", "PostgreSQL", resp)
validateRequiredString(plan.UserName, "user_name", "PostgreSQL", resp)
validateRequiredString(plan.Driver, "driver", "PostgreSQL", resp)
validateStringAgainstPatterns(plan.Driver, "driver", "PostgreSQL", resp, "postgresql_42_5_1", "postgresql_9_4_1205_jdbc41")
if plan.Gateway != nil {
validateRequiredString(plan.Gateway.Host, "gateway.host", "PostgreSQL", resp)
validateRequiredInt(plan.Gateway.Port, "gateway.port", "PostgreSQL", resp)
Expand All @@ -956,6 +972,28 @@ func (r *connectionResource) ValidateConfig(
}
}

func validateStringAgainstPatterns(field types.String, fieldName, connectionType string, resp *resource.ValidateConfigResponse, patterns ...string) {
if field.IsNull() {
return
}

for _, pattern := range patterns {
if field.ValueString() == pattern {
return
}
}

resp.Diagnostics.AddError(
fieldName,
fmt.Sprintf("%s: `%s` is invalid for %s connection. Valid values are: %s",
fieldName,
field.ValueString(),
connectionType,
strings.Join(patterns, ", "),
),
)
}

func validateRequiredString(field types.String, fieldName, connectionType string, resp *resource.ValidateConfigResponse) {
if field.IsNull() {
resp.Diagnostics.AddError(
Expand Down
124 changes: 123 additions & 1 deletion internal/provider/connection_resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package provider

import (
"fmt"
"regexp"
"testing"

"github.com/hashicorp/terraform-plugin-testing/helper/resource"
Expand All @@ -16,9 +17,9 @@ func TestAccConnectionResource(t *testing.T) {
Config: providerConfig + `
resource "trocco_connection" "test" {
connection_type = "bigquery"

name = "test"
description = "The quick brown fox jumps over the lazy dog."
project_id = "test"

service_account_json_key = "{\"type\":\"service_account\",\"project_id\":\"\",\"private_key_id\":\"\",\"private_key\":\"\"}"
}
Expand All @@ -42,6 +43,127 @@ func TestAccConnectionResource(t *testing.T) {
return fmt.Sprintf("bigquery,%s", connectionID), nil
},
},
// Snowflake
{
Config: providerConfig + `
resource "trocco_connection" "snowflake_test" {
connection_type = "snowflake"
auth_method = "user_password"

name = "snowflake test"
host = "example.snowflakecomputing.com"
user_name = "root"
password = "password"
}
`,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("trocco_connection.snowflake_test", "connection_type", "snowflake"),
resource.TestCheckResourceAttr("trocco_connection.snowflake_test", "name", "snowflake test"),
resource.TestCheckResourceAttrSet("trocco_connection.snowflake_test", "id"),
),
},
// MySQL
{
Config: providerConfig + `
resource "trocco_connection" "mysql_test" {
connection_type = "mysql"

name = "mysql test"
host = "localhost"
user_name = "root"
password = "password"
port = 3306
}
`,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("trocco_connection.mysql_test", "connection_type", "mysql"),
resource.TestCheckResourceAttr("trocco_connection.mysql_test", "name", "mysql test"),
resource.TestCheckResourceAttrSet("trocco_connection.mysql_test", "id"),
),
},
// PostgreSQL
{
Config: providerConfig + `
resource "trocco_connection" "postgresql_test" {
connection_type = "postgresql"
name = "postgresql test"
host = "localhost"
user_name = "root"
password = "password"
port = 5432
driver = "postgresql_42_5_1"
}
`,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("trocco_connection.postgresql_test", "connection_type", "postgresql"),
resource.TestCheckResourceAttrSet("trocco_connection.postgresql_test", "id"),
),
},
},
})
}

func TestInvalidDriver(t *testing.T) {
resource.Test(t, resource.TestCase{
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
{
Config: providerConfig + `
resource "trocco_connection" "invalid_driver_test" {
connection_type = "postgresql"
name = "invalid driver test"
host = "localhost"
user_name = "root"
password = "password"
port = 5432
driver = "invalid_driver"
}
`,
ExpectError: regexp.MustCompile("driver: `invalid_driver` is invalid for PostgreSQL connection. "),
},
{
Config: providerConfig + `
resource "trocco_connection" "mismatch_driver_test_postgresql" {
connection_type = "postgresql"
name = "invalid driver test"
host = "localhost"
user_name = "root"
password = "password"
port = 5432
driver = "mysql_connector_java_5_1_49"
}
`,
ExpectError: regexp.MustCompile("are: postgresql_42_5_1, postgresql_9_4_1205_jdbc41"),
},
{
Config: providerConfig + `
resource "trocco_connection" "mismatch_driver_test_mysql" {
connection_type = "mysql"
name = "invalid driver test"
host = "localhost"
user_name = "root"
password = "password"
port = 3306
driver = "snowflake_jdbc_3_14_2"
}
`,
ExpectError: regexp.MustCompile("are: mysql_connector_java_5_1_49"),
},
{
Config: providerConfig + `
resource "trocco_connection" "mismatch_driver_test_snowflake" {
connection_type = "snowflake"
name = "invalid driver test"

auth_method = "user_password"
host = "example.snowflakecomputing.com"
user_name = "root"
password = "password"
driver = "mysql_connector_java_5_1_49"
}
`,
ExpectError: regexp.MustCompile("are: snowflake_jdbc_3_14_2, snowflake_jdbc_3_17_0"),
},
},
})
}
Loading