From cd07cf71b27d9e5ff998e67f22673485b9ae2b61 Mon Sep 17 00:00:00 2001 From: Samuel Marks <807580+SamuelMarks@users.noreply.github.com> Date: Sun, 21 May 2023 05:53:37 -0400 Subject: [PATCH 1/3] [config.go] Add `GetConnectionURL` (#108) * [config.go] Add `GetConnectionURL` * [test_config.go] Add basic test for `GetConnectionURL` --- config.go | 5 +++++ test_config.go | 12 ++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 test_config.go diff --git a/config.go b/config.go index fd789fe..55c226c 100644 --- a/config.go +++ b/config.go @@ -1,6 +1,7 @@ package embeddedpostgres import ( + "fmt" "io" "os" "time" @@ -118,6 +119,10 @@ func (c Config) BinaryRepositoryURL(binaryRepositoryURL string) Config { return c } +func (c Config) GetConnectionURL() string { + return fmt.Sprintf("postgresql://%s:%s@%s:%d/%s", c.username, c.password, "localhost", c.port, c.database) +} + // PostgresVersion represents the semantic version used to fetch and run the Postgres process. type PostgresVersion string diff --git a/test_config.go b/test_config.go new file mode 100644 index 0000000..5646c9b --- /dev/null +++ b/test_config.go @@ -0,0 +1,12 @@ +package embeddedpostgres + +import "testing" + +func TestGetConnectionURL(t *testing.T) { + config := DefaultConfig().Database("mydb").Username("myuser").Password("mypass") + expect := "postgresql://myuser:mypass@localhost:5432/mydb" + + if got := config.GetConnectionURL(); got != expect { + t.Errorf("expected \"%s\" got \"%s\"", expect, got) + } +} From 54a6dcfcbf7826dd1171dc7abe9874a4887f1de1 Mon Sep 17 00:00:00 2001 From: Alec Sammon Date: Sun, 21 May 2023 11:04:14 +0100 Subject: [PATCH 2/3] Add `sync.Mutex` and `os.Rename` to prevent corrupted file when downloading the Postgres archive (#105) * Add sync.Mutex to prevent collisions * * add atomic download, and use defer to ensure mutex unlock * * move mutex to global * * fix tests * * update platform-test * * update examples * * remove atomic dependency * * remove code duplication * * reduce test parallel run count * * fix race condition in tests * * run tests * * attempt to fix windows * * attempt a different solution for windows * * revert changes * * try additional fix for windows * * add another test * * catch syscall.EEXIST * * fix test * * fix test * * add extra debugging * * attempt to fix windows * * add additional error message * * fix race in decompression * * more fixes * * use atomic * * add extra debug * * try catching the error * * try different permissions * * add more debugging * * more debug * * more debug * * test dest * * attempt to close temp file * * simplify * * remove atomic * * clean up code * * add more tests * * clean up temporary files * * prevent file being opened twice --- decompression.go | 45 ++++++++++++++++--- decompression_test.go | 43 +++++++++++++++++- embedded_postgres.go | 38 ++++++++++------ embedded_postgres_test.go | 63 ++++++++++++++++++++++++++- platform-test/platform_test.go | 4 +- remote_fetch.go | 71 +++++++++++++++++++++++------- remote_fetch_test.go | 79 ++++++++++++++++++++++++++++++---- rename.go | 27 ++++++++++++ rename_test.go | 21 +++++++++ 9 files changed, 343 insertions(+), 48 deletions(-) create mode 100644 rename.go create mode 100644 rename_test.go diff --git a/decompression.go b/decompression.go index 1b5f619..1e46e19 100644 --- a/decompression.go +++ b/decompression.go @@ -21,9 +21,19 @@ func defaultTarReader(xzReader *xz.Reader) (func() (*tar.Header, error), func() } func decompressTarXz(tarReader func(*xz.Reader) (func() (*tar.Header, error), func() io.Reader), path, extractPath string) error { + tempExtractPath, err := os.MkdirTemp(filepath.Dir(extractPath), "temp_") + if err != nil { + return errorUnableToExtract(path, extractPath, err) + } + defer func() { + if err := os.RemoveAll(tempExtractPath); err != nil { + panic(err) + } + }() + tarFile, err := os.Open(path) if err != nil { - return errorUnableToExtract(path, extractPath) + return errorUnableToExtract(path, extractPath, err) } defer func() { @@ -34,7 +44,7 @@ func decompressTarXz(tarReader func(*xz.Reader) (func() (*tar.Header, error), fu xzReader, err := xz.NewReader(tarFile, 0) if err != nil { - return errorUnableToExtract(path, extractPath) + return errorUnableToExtract(path, extractPath, err) } readNext, reader := tarReader(xzReader) @@ -43,16 +53,21 @@ func decompressTarXz(tarReader func(*xz.Reader) (func() (*tar.Header, error), fu header, err := readNext() if err == io.EOF { - return nil + break } if err != nil { return errorExtractingPostgres(err) } - targetPath := filepath.Join(extractPath, header.Name) + targetPath := filepath.Join(tempExtractPath, header.Name) + finalPath := filepath.Join(extractPath, header.Name) - if err := os.MkdirAll(filepath.Dir(targetPath), 0755); err != nil { + if err := os.MkdirAll(filepath.Dir(targetPath), os.ModePerm); err != nil { + return errorExtractingPostgres(err) + } + + if err := os.MkdirAll(filepath.Dir(finalPath), os.ModePerm); err != nil { return errorExtractingPostgres(err) } @@ -78,10 +93,26 @@ func decompressTarXz(tarReader func(*xz.Reader) (func() (*tar.Header, error), fu if err := os.Symlink(header.Linkname, targetPath); err != nil { return errorExtractingPostgres(err) } + + case tar.TypeDir: + if err := os.MkdirAll(finalPath, os.FileMode(header.Mode)); err != nil { + return errorExtractingPostgres(err) + } + continue + } + + if err := renameOrIgnore(targetPath, finalPath); err != nil { + return errorExtractingPostgres(err) } } + + return nil } -func errorUnableToExtract(cacheLocation, binariesPath string) error { - return fmt.Errorf("unable to extract postgres archive %s to %s, if running parallel tests, configure RuntimePath to isolate testing directories", cacheLocation, binariesPath) +func errorUnableToExtract(cacheLocation, binariesPath string, err error) error { + return fmt.Errorf("unable to extract postgres archive %s to %s, if running parallel tests, configure RuntimePath to isolate testing directories, %w", + cacheLocation, + binariesPath, + err, + ) } diff --git a/decompression_test.go b/decompression_test.go index 2566256..92c6a73 100644 --- a/decompression_test.go +++ b/decompression_test.go @@ -3,12 +3,16 @@ package embeddedpostgres import ( "archive/tar" "errors" + "fmt" "io" "os" + "path" "path/filepath" + "syscall" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/xi2/xz" ) @@ -17,6 +21,9 @@ func Test_decompressTarXz(t *testing.T) { if err != nil { panic(err) } + if err := syscall.Rmdir(tempDir); err != nil { + panic(err) + } archive, cleanUp := createTempXzArchive() defer cleanUp() @@ -37,7 +44,12 @@ func Test_decompressTarXz(t *testing.T) { func Test_decompressTarXz_ErrorWhenFileNotExists(t *testing.T) { err := decompressTarXz(defaultTarReader, "/does-not-exist", "/also-fake") - assert.EqualError(t, err, "unable to extract postgres archive /does-not-exist to /also-fake, if running parallel tests, configure RuntimePath to isolate testing directories") + assert.Error(t, err) + assert.Contains( + t, + err.Error(), + "unable to extract postgres archive /does-not-exist to /also-fake, if running parallel tests, configure RuntimePath to isolate testing directories", + ) } func Test_decompressTarXz_ErrorWhenErrorDuringRead(t *testing.T) { @@ -45,6 +57,9 @@ func Test_decompressTarXz_ErrorWhenErrorDuringRead(t *testing.T) { if err != nil { panic(err) } + if err := syscall.Rmdir(tempDir); err != nil { + panic(err) + } archive, cleanUp := createTempXzArchive() defer cleanUp() @@ -103,6 +118,9 @@ func Test_decompressTarXz_ErrorWhenFileToCopyToNotExists(t *testing.T) { if err != nil { panic(err) } + if err := syscall.Rmdir(tempDir); err != nil { + panic(err) + } archive, cleanUp := createTempXzArchive() defer cleanUp() @@ -137,6 +155,9 @@ func Test_decompressTarXz_ErrorWhenArchiveCorrupted(t *testing.T) { if err != nil { panic(err) } + if err := syscall.Rmdir(tempDir); err != nil { + panic(err) + } archive, cleanup := createTempXzArchive() @@ -163,3 +184,23 @@ func Test_decompressTarXz_ErrorWhenArchiveCorrupted(t *testing.T) { assert.EqualError(t, err, "unable to extract postgres archive: xz: data is corrupt") } + +func Test_decompressTarXz_ErrorWithInvalidDestination(t *testing.T) { + archive, cleanUp := createTempXzArchive() + defer cleanUp() + + tempDir, err := os.MkdirTemp("", "temp_tar_test") + require.NoError(t, err) + defer func() { + os.RemoveAll(tempDir) + }() + + op := fmt.Sprintf(path.Join(tempDir, "%c"), rune(0)) + + err = decompressTarXz(defaultTarReader, archive, op) + assert.EqualError( + t, + err, + fmt.Sprintf("unable to extract postgres archive: mkdir %s: invalid argument", op), + ) +} diff --git a/embedded_postgres.go b/embedded_postgres.go index 966f130..5088915 100644 --- a/embedded_postgres.go +++ b/embedded_postgres.go @@ -9,8 +9,11 @@ import ( "path/filepath" "runtime" "strings" + "sync" ) +var mu sync.Mutex + // EmbeddedPostgres maintains all configuration and runtime functions for maintaining the lifecycle of one Postgres process. type EmbeddedPostgres struct { config Config @@ -92,20 +95,11 @@ func (ep *EmbeddedPostgres) Start() error { ep.config.binariesPath = ep.config.runtimePath } - _, binDirErr := os.Stat(filepath.Join(ep.config.binariesPath, "bin")) - if os.IsNotExist(binDirErr) { - if !cacheExists { - if err := ep.remoteFetchStrategy(); err != nil { - return err - } - } - - if err := decompressTarXz(defaultTarReader, cacheLocation, ep.config.binariesPath); err != nil { - return err - } + if err := ep.downloadAndExtractBinary(cacheExists, cacheLocation); err != nil { + return err } - if err := os.MkdirAll(ep.config.runtimePath, 0755); err != nil { + if err := os.MkdirAll(ep.config.runtimePath, os.ModePerm); err != nil { return fmt.Errorf("unable to create runtime directory %s with error: %s", ep.config.runtimePath, err) } @@ -148,6 +142,26 @@ func (ep *EmbeddedPostgres) Start() error { return nil } +func (ep *EmbeddedPostgres) downloadAndExtractBinary(cacheExists bool, cacheLocation string) error { + // lock to prevent collisions with duplicate downloads + mu.Lock() + defer mu.Unlock() + + _, binDirErr := os.Stat(filepath.Join(ep.config.binariesPath, "bin")) + if os.IsNotExist(binDirErr) { + if !cacheExists { + if err := ep.remoteFetchStrategy(); err != nil { + return err + } + } + + if err := decompressTarXz(defaultTarReader, cacheLocation, ep.config.binariesPath); err != nil { + return err + } + } + return nil +} + func (ep *EmbeddedPostgres) cleanDataDirectoryAndInit() error { if err := os.RemoveAll(ep.config.dataPath); err != nil { return fmt.Errorf("unable to clean up data directory %s with error: %s", ep.config.dataPath, err) diff --git a/embedded_postgres_test.go b/embedded_postgres_test.go index 22212ee..5502c48 100644 --- a/embedded_postgres_test.go +++ b/embedded_postgres_test.go @@ -15,6 +15,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func Test_DefaultConfig(t *testing.T) { @@ -99,7 +100,7 @@ func Test_ErrorWhenUnableToUnArchiveFile_WrongFormat(t *testing.T) { } } - assert.EqualError(t, err, fmt.Sprintf(`unable to extract postgres archive %s to %s, if running parallel tests, configure RuntimePath to isolate testing directories`, jarFile, filepath.Join(filepath.Dir(jarFile), "extracted"))) + assert.EqualError(t, err, fmt.Sprintf(`unable to extract postgres archive %s to %s, if running parallel tests, configure RuntimePath to isolate testing directories, xz: file format not recognized`, jarFile, filepath.Join(filepath.Dir(jarFile), "extracted"))) } func Test_ErrorWhenUnableToInitDatabase(t *testing.T) { @@ -355,6 +356,66 @@ func Test_CustomLocaleConfig(t *testing.T) { } } +func Test_ConcurrentStart(t *testing.T) { + var wg sync.WaitGroup + + database := NewDatabase() + cacheLocation, _ := database.cacheLocator() + err := os.RemoveAll(cacheLocation) + require.NoError(t, err) + + port := 5432 + for i := 1; i <= 3; i++ { + port = port + 1 + wg.Add(1) + + go func(p int) { + defer wg.Done() + tempDir, err := os.MkdirTemp("", "embedded_postgres_test") + if err != nil { + panic(err) + } + + defer func() { + if err := os.RemoveAll(tempDir); err != nil { + panic(err) + } + }() + + database := NewDatabase(DefaultConfig(). + RuntimePath(tempDir). + Port(uint32(p))) + + if err := database.Start(); err != nil { + shutdownDBAndFail(t, err, database) + } + + db, err := sql.Open( + "postgres", + fmt.Sprintf("host=localhost port=%d user=postgres password=postgres dbname=postgres sslmode=disable", p), + ) + if err != nil { + shutdownDBAndFail(t, err, database) + } + + if err = db.Ping(); err != nil { + shutdownDBAndFail(t, err, database) + } + + if err := db.Close(); err != nil { + shutdownDBAndFail(t, err, database) + } + + if err := database.Stop(); err != nil { + shutdownDBAndFail(t, err, database) + } + + }(port) + } + + wg.Wait() +} + func Test_CanStartAndStopTwice(t *testing.T) { database := NewDatabase() diff --git a/platform-test/platform_test.go b/platform-test/platform_test.go index ad7a07d..9a4982b 100644 --- a/platform-test/platform_test.go +++ b/platform-test/platform_test.go @@ -72,8 +72,8 @@ func Test_AllMajorVersions(t *testing.T) { } func shutdownDBAndFail(t *testing.T, err error, db *embeddedpostgres.EmbeddedPostgres, version embeddedpostgres.PostgresVersion) { - if err := db.Stop(); err != nil { - t.Fatalf("Failed for version %s with error %s", version, err) + if err2 := db.Stop(); err2 != nil { + t.Fatalf("Failed for version %s with error %s, original error %s", version, err2, err) } t.Fatalf("Failed for version %s with error %s", version, err) diff --git a/remote_fetch.go b/remote_fetch.go index e420c00..dceae84 100644 --- a/remote_fetch.go +++ b/remote_fetch.go @@ -80,33 +80,72 @@ func decompressResponse(bodyBytes []byte, contentLength int64, cacheLocator Cach return errorFetchingPostgres(err) } + cacheLocation, _ := cacheLocator() + + if err := os.MkdirAll(filepath.Dir(cacheLocation), 0755); err != nil { + return errorExtractingPostgres(err) + } + for _, file := range zipReader.File { if !file.FileHeader.FileInfo().IsDir() && strings.HasSuffix(file.FileHeader.Name, ".txz") { - archiveReader, err := file.Open() - if err != nil { - return errorExtractingPostgres(err) + if err := decompressSingleFile(file, cacheLocation); err != nil { + return err } - archiveBytes, err := io.ReadAll(archiveReader) - if err != nil { - return errorExtractingPostgres(err) - } + // we have successfully found the file, return early + return nil + } + } - cacheLocation, _ := cacheLocator() + return fmt.Errorf("error fetching postgres: cannot find binary in archive retrieved from %s", downloadURL) +} - if err := os.MkdirAll(filepath.Dir(cacheLocation), 0755); err != nil { - return errorExtractingPostgres(err) - } +func decompressSingleFile(file *zip.File, cacheLocation string) error { + renamed := false - if err := os.WriteFile(cacheLocation, archiveBytes, file.FileHeader.Mode()); err != nil { - return errorExtractingPostgres(err) - } + archiveReader, err := file.Open() + if err != nil { + return errorExtractingPostgres(err) + } - return nil + archiveBytes, err := io.ReadAll(archiveReader) + if err != nil { + return errorExtractingPostgres(err) + } + + // if multiple processes attempt to extract + // to prevent file corruption when multiple processes attempt to extract at the same time + // first to a cache location, and then move the file into place. + tmp, err := os.CreateTemp(filepath.Dir(cacheLocation), "temp_") + if err != nil { + return errorExtractingPostgres(err) + } + defer func() { + // if anything failed before the rename then the temporary file should be cleaned up. + // if the rename was successful then there is no temporary file to remove. + if !renamed { + if err := os.Remove(tmp.Name()); err != nil { + panic(err) + } } + }() + + if _, err := tmp.Write(archiveBytes); err != nil { + return errorExtractingPostgres(err) } - return fmt.Errorf("error fetching postgres: cannot find binary in archive retrieved from %s", downloadURL) + // Windows cannot rename a file if is it still open. + // The file needs to be manually closed to allow the rename to happen + if err := tmp.Close(); err != nil { + return errorExtractingPostgres(err) + } + + if err := renameOrIgnore(tmp.Name(), cacheLocation); err != nil { + return errorExtractingPostgres(err) + } + renamed = true + + return nil } func errorExtractingPostgres(err error) error { diff --git a/remote_fetch_test.go b/remote_fetch_test.go index d2398e6..c884e5c 100644 --- a/remote_fetch_test.go +++ b/remote_fetch_test.go @@ -7,6 +7,7 @@ import ( "net/http" "net/http/httptest" "os" + "path" "path/filepath" "strings" "testing" @@ -122,12 +123,6 @@ func Test_defaultRemoteFetchStrategy_ErrorWhenCannotExtractSubArchive(t *testing jarFile, cleanUp := createTempZipArchive() defer cleanUp() - dirBlockingExtract := filepath.Join(filepath.Dir(jarFile), "some_dir") - - if err := os.MkdirAll(dirBlockingExtract, 0400); err != nil { - panic(err) - } - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if strings.HasSuffix(r.RequestURI, ".sha256") { w.WriteHeader(http.StatusNotFound) @@ -147,7 +142,7 @@ func Test_defaultRemoteFetchStrategy_ErrorWhenCannotExtractSubArchive(t *testing remoteFetchStrategy := defaultRemoteFetchStrategy(server.URL+"/maven2", testVersionStrategy(), func() (s string, b bool) { - return dirBlockingExtract, false + return filepath.FromSlash("/invalid"), false }) err := remoteFetchStrategy() @@ -201,7 +196,7 @@ func Test_defaultRemoteFetchStrategy_ErrorWhenCannotCreateSubArchiveFile(t *test cacheLocation := filepath.Join(filepath.Dir(jarFile), "extract_directory", "cache_file.jar") - if err := os.MkdirAll(cacheLocation, 0755); err != nil { + if err := os.MkdirAll(cacheLocation, os.ModePerm); err != nil { panic(err) } @@ -224,7 +219,7 @@ func Test_defaultRemoteFetchStrategy_ErrorWhenCannotCreateSubArchiveFile(t *test remoteFetchStrategy := defaultRemoteFetchStrategy(server.URL+"/maven2", testVersionStrategy(), func() (s string, b bool) { - return cacheLocation, false + return "/\\000", false }) err := remoteFetchStrategy() @@ -309,3 +304,69 @@ func Test_defaultRemoteFetchStrategy(t *testing.T) { assert.NoError(t, err) assert.FileExists(t, cacheLocation) } + +func Test_defaultRemoteFetchStrategyWithExistingDownload(t *testing.T) { + jarFile, cleanUp := createTempZipArchive() + defer cleanUp() + + // create a temp directory for testing + tempFile, err := os.MkdirTemp("", "cache_output") + if err != nil { + panic(err) + } + // clean up once the test is finished. + defer func() { + if err := os.RemoveAll(tempFile); err != nil { + panic(err) + } + }() + + cacheLocation := path.Join(tempFile, "temp.jar") + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + bytes, err := os.ReadFile(jarFile) + if err != nil { + panic(err) + } + + if strings.HasSuffix(r.RequestURI, ".sha256") { + w.WriteHeader(200) + contentHash := sha256.Sum256(bytes) + if _, err := w.Write([]byte(hex.EncodeToString(contentHash[:]))); err != nil { + panic(err) + } + + return + } + + if _, err := w.Write(bytes); err != nil { + panic(err) + } + })) + defer server.Close() + + remoteFetchStrategy := defaultRemoteFetchStrategy(server.URL+"/maven2", + testVersionStrategy(), + func() (s string, b bool) { + return cacheLocation, false + }) + + // call it the remoteFetchStrategy(). The output location should be empty and a new file created + err = remoteFetchStrategy() + assert.NoError(t, err) + assert.FileExists(t, cacheLocation) + out1, err := os.ReadFile(cacheLocation) + + // write some bad data to the file, this helps us test that the file is overwritten + err = os.WriteFile(cacheLocation, []byte("invalid"), 0600) + assert.NoError(t, err) + + // call the remoteFetchStrategy() again, this time the file should be overwritten + err = remoteFetchStrategy() + assert.NoError(t, err) + assert.FileExists(t, cacheLocation) + + // ensure that the file contents are the same from both downloads, and that it doesn't contain the `invalid` data. + out2, err := os.ReadFile(cacheLocation) + assert.Equal(t, out1, out2) +} diff --git a/rename.go b/rename.go new file mode 100644 index 0000000..0cd5da5 --- /dev/null +++ b/rename.go @@ -0,0 +1,27 @@ +package embeddedpostgres + +import ( + "errors" + "os" + "syscall" +) + +// renameOrIgnore will rename the oldpath to the newpath. +// +// On Unix this will be a safe atomic operation. +// On Windows this will do nothing if the new path already exists. +// +// This is only safe to use if you can be sure that the newpath is either missing, or contains the same data as the +// old path. +func renameOrIgnore(oldpath, newpath string) error { + err := os.Rename(oldpath, newpath) + + // if the error is due to syscall.EEXIST then this is most likely windows, and a race condition with + // multiple downloads of the file. We can assume that the existing file is the correct one and ignore + // the error + if errors.Is(err, syscall.EEXIST) { + return nil + } + + return err +} diff --git a/rename_test.go b/rename_test.go new file mode 100644 index 0000000..b764cf1 --- /dev/null +++ b/rename_test.go @@ -0,0 +1,21 @@ +package embeddedpostgres + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func Test_renameOrIgnore_NoErrorOnEEXIST(t *testing.T) { + tmpDir, err := os.MkdirTemp("", "test_dir") + require.NoError(t, err) + + tmpFil, err := os.CreateTemp("", "test_file") + require.NoError(t, err) + + // os.Rename would return an error here, ensure that the error is handled and returned as nil + err = renameOrIgnore(tmpFil.Name(), tmpDir) + assert.NoError(t, err) +} From b632dc8579d0c5a13f08a4ba82e110b1afe2028c Mon Sep 17 00:00:00 2001 From: Fergus Strange Date: Sun, 21 May 2023 20:06:14 +1000 Subject: [PATCH 3/3] Update default version (#113) Update major versions --- config.go | 12 ++++++------ version_strategy_test.go | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/config.go b/config.go index 55c226c..d67bdc3 100644 --- a/config.go +++ b/config.go @@ -33,7 +33,7 @@ type Config struct { // StartTimeout: 15 Seconds func DefaultConfig() Config { return Config{ - version: V14, + version: V15, port: 5432, database: "postgres", username: "postgres", @@ -128,11 +128,11 @@ type PostgresVersion string // Predefined supported Postgres versions. const ( - V15 = PostgresVersion("15.1.0") - V14 = PostgresVersion("14.6.0") - V13 = PostgresVersion("13.9.0") - V12 = PostgresVersion("12.13.0") - V11 = PostgresVersion("11.18.0") + V15 = PostgresVersion("15.3.0") + V14 = PostgresVersion("14.8.0") + V13 = PostgresVersion("13.11.0") + V12 = PostgresVersion("12.15.0") + V11 = PostgresVersion("11.20.0") V10 = PostgresVersion("10.23.0") V9 = PostgresVersion("9.6.24") ) diff --git a/version_strategy_test.go b/version_strategy_test.go index 87aabb0..e2c9527 100644 --- a/version_strategy_test.go +++ b/version_strategy_test.go @@ -57,7 +57,7 @@ func Test_DefaultVersionStrategy_AllGolangDistributions(t *testing.T) { PostgresVersion("14.0.0"): {}, PostgresVersion("14.1.0"): {}, PostgresVersion("14.2.0"): {"darwin/arm64": {"darwin", "arm64v8"}}, - V14: {"darwin/arm64": {"darwin", "arm64v8"}}, + V15: {"darwin/arm64": {"darwin", "arm64v8"}}, } defaultConfig := DefaultConfig() @@ -105,7 +105,7 @@ func Test_DefaultVersionStrategy_Linux_ARM32V6(t *testing.T) { assert.Equal(t, "linux", operatingSystem) assert.Equal(t, "arm32v6", architecture) - assert.Equal(t, V14, postgresVersion) + assert.Equal(t, V15, postgresVersion) } func Test_DefaultVersionStrategy_Linux_ARM32V7(t *testing.T) { @@ -121,7 +121,7 @@ func Test_DefaultVersionStrategy_Linux_ARM32V7(t *testing.T) { assert.Equal(t, "linux", operatingSystem) assert.Equal(t, "arm32v7", architecture) - assert.Equal(t, V14, postgresVersion) + assert.Equal(t, V15, postgresVersion) } func Test_DefaultVersionStrategy_Linux_Alpine(t *testing.T) { @@ -139,7 +139,7 @@ func Test_DefaultVersionStrategy_Linux_Alpine(t *testing.T) { assert.Equal(t, "linux", operatingSystem) assert.Equal(t, "amd64-alpine", architecture) - assert.Equal(t, V14, postgresVersion) + assert.Equal(t, V15, postgresVersion) } func Test_DefaultVersionStrategy_shouldUseAlpineLinuxBuild(t *testing.T) {