github.com/supabase/cli@v1.168.1/internal/db/test/test.go (about)

     1  package test
     2  
     3  import (
     4  	"context"
     5  	_ "embed"
     6  	"fmt"
     7  	"os"
     8  	"path/filepath"
     9  
    10  	"github.com/docker/docker/api/types/container"
    11  	"github.com/docker/docker/api/types/network"
    12  	"github.com/go-errors/errors"
    13  	"github.com/jackc/pgconn"
    14  	"github.com/jackc/pgerrcode"
    15  	"github.com/jackc/pgx/v4"
    16  	"github.com/spf13/afero"
    17  	"github.com/spf13/viper"
    18  	"github.com/supabase/cli/internal/utils"
    19  )
    20  
    21  const (
    22  	ENABLE_PGTAP  = "create extension if not exists pgtap with schema extensions"
    23  	DISABLE_PGTAP = "drop extension if exists pgtap"
    24  )
    25  
    26  func Run(ctx context.Context, testFiles []string, config pgconn.Config, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error {
    27  	// Build test command
    28  	cmd := []string{"pg_prove", "--ext", ".pg", "--ext", ".sql", "-r"}
    29  	for _, fp := range testFiles {
    30  		relPath, err := filepath.Rel(utils.DbTestsDir, fp)
    31  		if err != nil {
    32  			return errors.Errorf("failed to resolve relative path: %w", err)
    33  		}
    34  		cmd = append(cmd, relPath)
    35  	}
    36  	if viper.GetBool("DEBUG") {
    37  		cmd = append(cmd, "--verbose")
    38  	}
    39  	// Mount tests directory into container as working directory
    40  	srcPath, err := filepath.Abs(utils.DbTestsDir)
    41  	if err != nil {
    42  		return errors.Errorf("failed to resolve absolute path: %w", err)
    43  	}
    44  	dstPath := "/tmp"
    45  	binds := []string{fmt.Sprintf("%s:%s:ro,z", srcPath, dstPath)}
    46  	// Enable pgTAP if not already exists
    47  	alreadyExists := false
    48  	options = append(options, func(cc *pgx.ConnConfig) {
    49  		cc.OnNotice = func(pc *pgconn.PgConn, n *pgconn.Notice) {
    50  			alreadyExists = n.Code == pgerrcode.DuplicateObject
    51  		}
    52  	})
    53  	conn, err := utils.ConnectByConfig(ctx, config, options...)
    54  	if err != nil {
    55  		return err
    56  	}
    57  	defer conn.Close(context.Background())
    58  	if _, err := conn.Exec(ctx, ENABLE_PGTAP); err != nil {
    59  		return errors.Errorf("failed to enable pgTAP: %w", err)
    60  	}
    61  	if !alreadyExists {
    62  		defer func() {
    63  			if _, err := conn.Exec(ctx, DISABLE_PGTAP); err != nil {
    64  				fmt.Fprintln(os.Stderr, "failed to disable pgTAP:", err)
    65  			}
    66  		}()
    67  	}
    68  	// Use custom network when connecting to local database
    69  	networkID := "host"
    70  	if utils.IsLocalDatabase(config) {
    71  		config.Host = utils.DbAliases[0]
    72  		config.Port = 5432
    73  		networkID = utils.NetId
    74  	}
    75  	// Run pg_prove on volume mount
    76  	return utils.DockerRunOnceWithConfig(
    77  		ctx,
    78  		container.Config{
    79  			Image: utils.PgProveImage,
    80  			Env: []string{
    81  				"PGHOST=" + config.Host,
    82  				fmt.Sprintf("PGPORT=%d", config.Port),
    83  				"PGUSER=" + config.User,
    84  				"PGPASSWORD=" + config.Password,
    85  				"PGDATABASE=" + config.Database,
    86  			},
    87  			Cmd:        cmd,
    88  			WorkingDir: dstPath,
    89  		},
    90  		container.HostConfig{
    91  			NetworkMode: container.NetworkMode(networkID),
    92  			Binds:       binds,
    93  		},
    94  		network.NetworkingConfig{},
    95  		"",
    96  		os.Stdout,
    97  		os.Stderr,
    98  	)
    99  }