github.com/angryronald/go-kit@v0.0.0-20240505173814-ff2bd9c79dbf/test/docker/postgres/postgres.go (about)

     1  package postgres
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"sync"
     7  
     8  	"gorm.io/driver/postgres"
     9  	"gorm.io/gorm"
    10  
    11  	"github.com/ory/dockertest"
    12  	"github.com/ory/dockertest/docker"
    13  
    14  	internalDocker "github.com/angryronald/go-kit/test/docker"
    15  )
    16  
    17  // ref: https://jonnylangefeld.com/blog/how-to-write-a-go-api-part-3-testing-with-dockertest
    18  
    19  var dbInstanceLock sync.Mutex
    20  
    21  func GenerateInstance(pool *dockertest.Pool) (*gorm.DB, *dockertest.Resource) {
    22  	dbInstanceLock.Lock()
    23  	defer dbInstanceLock.Unlock()
    24  
    25  	var db *gorm.DB
    26  	port := internalDocker.GetAvailablePort(5432)
    27  
    28  	// Pull an image, create a container based on it and set all necessary parameters
    29  	opts := dockertest.RunOptions{
    30  		Repository:   "mdillon/postgis",
    31  		Tag:          "latest",
    32  		Env:          []string{"POSTGRES_PASSWORD=password"},
    33  		ExposedPorts: []string{"5432"},
    34  		PortBindings: map[docker.Port][]docker.PortBinding{
    35  			"5432": {
    36  				{HostIP: "0.0.0.0", HostPort: port},
    37  			},
    38  		},
    39  	}
    40  
    41  	// Run the Docker container
    42  	resource, err := pool.RunWithOptions(&opts)
    43  	if err != nil {
    44  		log.Fatalf("Could not start resource: %s", err)
    45  	}
    46  
    47  	// Exponential retry to connect to database while it is booting
    48  	if err := pool.Retry(func() error {
    49  		databaseConnStr := fmt.Sprintf("host=localhost port=%s user=postgres dbname=postgres password=password sslmode=disable", port)
    50  		db, err = gorm.Open(postgres.Open(databaseConnStr), &gorm.Config{})
    51  		if err != nil {
    52  			log.Println("Database not ready yet (it is booting up, wait for a few tries)...")
    53  			return err
    54  		}
    55  
    56  		// Tests if database is reachable
    57  		dbinstance, err := db.DB()
    58  		if err != nil {
    59  			log.Println("Database instance cannot created")
    60  			return err
    61  		}
    62  		return dbinstance.Ping()
    63  	}); err != nil {
    64  		log.Fatalf("Could not connect to Docker: %s", err)
    65  	}
    66  
    67  	return db, resource
    68  }