debian-mirror-gitlab/workhorse-vendor/gocloud.dev/postgres/postgres_test.go
2023-01-13 15:02:22 +05:30

139 lines
3.8 KiB
Go

// Copyright 2019 The Go Cloud Development Kit Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package postgres
import (
"bytes"
"context"
"fmt"
"io/ioutil"
"net/url"
"os"
"os/exec"
"os/user"
"path/filepath"
"runtime"
"testing"
"time"
)
func TestOpen(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("Can't use Unix sockets on Windows")
}
postgresPath, err := exec.LookPath("postgres")
if err != nil {
t.Skip("Can't find postgres:", err)
}
initdbPath, err := exec.LookPath("initdb")
if err != nil {
t.Skip("Can't find initdb:", err)
}
// Create a temporary database data directory.
currUser, err := user.Current()
if err != nil {
t.Fatal(err)
}
dir, err := ioutil.TempDir("", "gocloud_postgres_test")
if err != nil {
t.Fatal(err)
}
defer func() {
if err := os.RemoveAll(dir); err != nil {
t.Errorf("Cleaning up: %v", err)
}
}()
dataDir := filepath.Join(dir, "data")
initdbCmd := exec.Command(initdbPath, "-U", currUser.Username, "-D", dataDir)
initdbOutput := new(bytes.Buffer)
initdbCmd.Stdout = initdbOutput
initdbCmd.Stderr = initdbOutput
err = initdbCmd.Run()
if err != nil {
t.Log(initdbOutput)
t.Fatal(err)
}
// Configure the database server to listen on a Unix socket located in the temporary directory.
socketDir, err := filepath.Abs(filepath.Join(dir, "socket"))
if err != nil {
t.Fatal(err)
}
if err := os.Mkdir(socketDir, 0777); err != nil {
t.Fatal(err)
}
confData := new(bytes.Buffer)
fmt.Fprintf(confData, "unix_socket_directories = '%s'\n", socketDir)
err = ioutil.WriteFile(filepath.Join(dataDir, "postgresql.conf"), confData.Bytes(), 0666)
if err != nil {
t.Fatal(err)
}
// Start the database server (and arrange for it to be stopped at test end).
server := exec.Command(postgresPath, "-D", dataDir)
serverOutput := new(bytes.Buffer)
server.Stdout = serverOutput
server.Stderr = serverOutput
if err := server.Start(); err != nil {
t.Fatal(err)
}
serverSignaled := false
defer func() {
if !serverSignaled {
if err := server.Process.Kill(); err != nil {
t.Error("Stopping server:", err)
}
}
// Wait for server to exit, but ignore the expected failure error code.
server.Wait()
if t.Failed() {
t.Log(serverOutput)
}
}()
// Now the actual test: can we connect to the database via URL opener?
ctx := context.Background()
dbURL := &url.URL{
Scheme: "blablabla", // Intentionally not "postgres" to ensure any scheme works.
User: url.User(currUser.Username),
Path: "/postgres",
// Use the query parameter to avoid https://github.com/lib/pq/issues/796
RawQuery: url.Values{"host": {socketDir}}.Encode(),
}
t.Logf("PostgreSQL URL: %s", dbURL)
db, err := new(URLOpener).OpenPostgresURL(ctx, dbURL)
if err != nil {
t.Fatal(err)
}
// Developing a realistic query would be hard, so instead we trust that the
// PostgreSQL library reports healthy correctly. Since there's no way to
// synchronize the server start and the ping, we might have to ping a few
// times before it is healthy. (The overall test runner timeout will interrupt
// if this takes too long.)
for {
err := db.Ping()
if err == nil {
break
}
t.Log("Ping:", err)
time.Sleep(100 * time.Millisecond)
}
if err := db.Close(); err != nil {
t.Error("Close:", err)
}
server.Process.Signal(os.Interrupt)
serverSignaled = true
}