Skip to content

SQL Server SSL Integration Tests #129

Description

@rosanemelo

T-7: SQL Server SSL Integration Tests

Description

Implement integration tests that validate SSL connections with SQL Server, including tests with custom CA (now that SQL Server factory supports msdsn.Config.TLSConfig via Task 3), SSL mode tests, and backward compatibility tests without CA.

Delivered Value

Complete validation that SQL Server SSL connections work correctly with and without custom CA.

Files to Create

File Action Description
tests/integration/ssl/sqlserver_ssl_integration_test.go Create SQL Server SSL integration tests (modes + CA)

Implementation

//go:build integration && ssl

package ssl

import (
    "context"
    "testing"

    "github.com/LerianStudio/fetcher/pkg/constant"
    "github.com/LerianStudio/fetcher/pkg/datasource"
    "github.com/LerianStudio/fetcher/pkg/model"
    "github.com/LerianStudio/fetcher/tests/shared/setup"
    "github.com/stretchr/testify/require"
)

// === Testes de Modos SSL (sem CA) ===

func TestSQLServerSSL_BasicConnection(t *testing.T) {
    ctx := context.Background()

    opts := setup.SSLInfrastructureOptions()
    infra, err := setup.NewSharedInfrastructure(ctx, opts)
    require.NoError(t, err)
    defer infra.Cleanup(ctx)

    sqlInfo := infra.SQLServerSSL.ConnectionInfo()

    // Testar cada modo SSL sem CA (retrocompatibilidade)
    for _, config := range GetSQLServerSSLConfigs() {
        t.Run(config.Name, func(t *testing.T) {
            conn := model.Connection{
                Type:     constant.SQLServerProvider,
                Host:     sqlInfo.Host,
                Port:     sqlInfo.Port,
                Username: sqlInfo.Username,
                Password: sqlInfo.Password,
                Database: sqlInfo.Database,
                SSL: model.SSLConfig{
                    Mode: config.Mode,
                },
            }

            ds, err := datasource.NewDataSourceFromConnection(ctx, &conn)
            AssertConnectionSuccess(t, err, config)

            if err == nil && ds != nil {
                _, queryErr := ds.Query(ctx, "SELECT 1")
                require.NoError(t, queryErr)
            }
        })
    }
}

func TestSQLServerSSL_StrictMode_WithoutCA(t *testing.T) {
    ctx := context.Background()

    opts := setup.SSLInfrastructureOptions()
    infra, err := setup.NewSharedInfrastructure(ctx, opts)
    require.NoError(t, err)
    defer infra.Cleanup(ctx)

    sqlInfo := infra.SQLServerSSL.ConnectionInfo()

    // Modo strict sem CA:
    // - Valida certificado contra system CA store
    // - Espera-se falha em containers com cert auto-assinado nao instalado no system store
    conn := model.Connection{
        Type:     constant.SQLServerProvider,
        Host:     sqlInfo.Host,
        Port:     sqlInfo.Port,
        Username: sqlInfo.Username,
        Password: sqlInfo.Password,
        Database: sqlInfo.Database,
        SSL: model.SSLConfig{
            Mode: "strict",
        },
    }

    ds, err := datasource.NewDataSourceFromConnection(ctx, &conn)
    if err != nil {
        t.Logf("Modo strict sem CA falhou (esperado com cert auto-assinado nao no system CA store): %v", err)
    } else {
        _, queryErr := ds.Query(ctx, "SELECT 1")
        require.NoError(t, queryErr)
    }
}

func TestSQLServerSSL_InvalidMode(t *testing.T) {
    ctx := context.Background()

    opts := setup.SSLInfrastructureOptions()
    infra, err := setup.NewSharedInfrastructure(ctx, opts)
    require.NoError(t, err)
    defer infra.Cleanup(ctx)

    sqlInfo := infra.SQLServerSSL.ConnectionInfo()

    conn := model.Connection{
        Type:     constant.SQLServerProvider,
        Host:     sqlInfo.Host,
        Port:     sqlInfo.Port,
        Username: sqlInfo.Username,
        Password: sqlInfo.Password,
        Database: sqlInfo.Database,
        SSL: model.SSLConfig{
            Mode: "modo-invalido",
        },
    }

    _, err = datasource.NewDataSourceFromConnection(ctx, &conn)
    require.Error(t, err, "Conexao deve falhar com modo SSL invalido")
    require.Contains(t, err.Error(), "FET-0413", "Deve retornar erro de modo SSL invalido")
}

// === Testes com CA Customizado (factory agora suporta msdsn.Config.TLSConfig) ===

func TestSQLServerSSL_WithCustomCA_TrueMode(t *testing.T) {
    ctx := context.Background()

    opts := setup.SSLInfrastructureOptions()
    infra, err := setup.NewSharedInfrastructure(ctx, opts)
    require.NoError(t, err)
    defer infra.Cleanup(ctx)

    sqlInfo := infra.SQLServerSSL.ConnectionInfo()

    // Com CA + modo "true": valida cert contra CA fornecido (sem TrustServerCertificate)
    conn := model.Connection{
        Type:     constant.SQLServerProvider,
        Host:     sqlInfo.Host,
        Port:     sqlInfo.Port,
        Username: sqlInfo.Username,
        Password: sqlInfo.Password,
        Database: sqlInfo.Database,
        SSL: model.SSLConfig{
            Mode: "true",
            CA:   string(infra.SSLCertBundle.CACert),
        },
    }

    ds, err := datasource.NewDataSourceFromConnection(ctx, &conn)
    require.NoError(t, err, "Conexao com CA valido modo true deve funcionar")
    require.NotNil(t, ds)

    _, queryErr := ds.Query(ctx, "SELECT 1")
    require.NoError(t, queryErr, "Query deve funcionar via SSL com CA customizado")
}

func TestSQLServerSSL_WithCustomCA_StrictMode(t *testing.T) {
    ctx := context.Background()

    opts := setup.SSLInfrastructureOptions()
    infra, err := setup.NewSharedInfrastructure(ctx, opts)
    require.NoError(t, err)
    defer infra.Cleanup(ctx)

    sqlInfo := infra.SQLServerSSL.ConnectionInfo()

    // Com CA + modo "strict": valida cert contra CA fornecido
    conn := model.Connection{
        Type:     constant.SQLServerProvider,
        Host:     sqlInfo.Host,
        Port:     sqlInfo.Port,
        Username: sqlInfo.Username,
        Password: sqlInfo.Password,
        Database: sqlInfo.Database,
        SSL: model.SSLConfig{
            Mode: "strict",
            CA:   string(infra.SSLCertBundle.CACert),
        },
    }

    ds, err := datasource.NewDataSourceFromConnection(ctx, &conn)
    require.NoError(t, err, "Conexao com CA valido modo strict deve funcionar")
    require.NotNil(t, ds)

    _, queryErr := ds.Query(ctx, "SELECT 1")
    require.NoError(t, queryErr, "Query deve funcionar via SSL strict com CA customizado")
}

func TestSQLServerSSL_WithInvalidCA(t *testing.T) {
    ctx := context.Background()

    opts := setup.SSLInfrastructureOptions()
    infra, err := setup.NewSharedInfrastructure(ctx, opts)
    require.NoError(t, err)
    defer infra.Cleanup(ctx)

    sqlInfo := infra.SQLServerSSL.ConnectionInfo()

    // Conexao com CA invalido - deve falhar
    conn := model.Connection{
        Type:     constant.SQLServerProvider,
        Host:     sqlInfo.Host,
        Port:     sqlInfo.Port,
        Username: sqlInfo.Username,
        Password: sqlInfo.Password,
        Database: sqlInfo.Database,
        SSL: model.SSLConfig{
            Mode: "true",
            CA:   "certificado-invalido-nao-e-pem",
        },
    }

    _, err = datasource.NewDataSourceFromConnection(ctx, &conn)
    require.Error(t, err, "Conexao com CA invalido deve falhar")
}

func TestSQLServerSSL_WithoutCA_BackwardsCompatible(t *testing.T) {
    ctx := context.Background()

    opts := setup.SSLInfrastructureOptions()
    infra, err := setup.NewSharedInfrastructure(ctx, opts)
    require.NoError(t, err)
    defer infra.Cleanup(ctx)

    sqlInfo := infra.SQLServerSSL.ConnectionInfo()

    // Sem CA + modo "true": mantem TrustServerCertificate=true (comportamento atual)
    conn := model.Connection{
        Type:     constant.SQLServerProvider,
        Host:     sqlInfo.Host,
        Port:     sqlInfo.Port,
        Username: sqlInfo.Username,
        Password: sqlInfo.Password,
        Database: sqlInfo.Database,
        SSL: model.SSLConfig{
            Mode: "true",
        },
    }

    ds, err := datasource.NewDataSourceFromConnection(ctx, &conn)
    require.NoError(t, err, "Conexao sem CA modo true deve funcionar (TrustServerCertificate=true)")
    require.NotNil(t, ds)
}

Dependencies

  • Task 3 (SQL Server factory with CA)
  • Task 5 (SSL helpers)

Estimate

  • Size: M (medium)
  • Complexity: Medium

Acceptance Criteria

  • Test connects to SQL Server using SSL mode "true" (no CA, TrustServerCertificate=true)
  • Test documents behavior of "strict" mode without CA (validates against system CA store)
  • Test rejects invalid SSL mode with error FET-0413
  • Test with valid CA + "true" mode: connection works with real validation
  • Test with valid CA + "strict" mode: connection works with real validation
  • Test with invalid CA: connection fails with descriptive error
  • Test without CA (backwards compatible): connection works with TrustServerCertificate=true
  • All tests pass with go test -tags="integration,ssl"

Test Strategy

  • Local execution with ENABLE_SSL=true
  • CI validation
  • Tests cover: SSL modes, valid CA (true + strict), invalid CA, no CA (backward compatibility)


Task gerada pelo Floki


Jira: FET-150
Link: https://lerian.atlassian.net/browse/FET-150

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions