github.com/tommi2day/tnscli@v0.0.0-20240401211958-338fc0647b73/cmd/oracle_docker_test.go (about)

     1  package cmd
     2  
     3  import (
     4  	"database/sql"
     5  	"fmt"
     6  	"os"
     7  	"time"
     8  
     9  	"github.com/tommi2day/tnscli/test"
    10  
    11  	"github.com/ory/dockertest/v3"
    12  	"github.com/ory/dockertest/v3/docker"
    13  	"github.com/tommi2day/gomodules/common"
    14  )
    15  
    16  // DBPort is the port of the Oracle DB to access (default:21521)
    17  const DBPort = "21521"
    18  const repo = "docker.io/gvenzl/oracle-free"
    19  const repoTag = "23.3-slim"
    20  const containerTimeout = 600
    21  
    22  // SYSTEMUSER is the name of the default DBA user
    23  const SYSTEMUSER = "system"
    24  
    25  // SYSTEMSERVICE is the name of the root service
    26  const SYSTEMSERVICE = "FREE"
    27  
    28  var containerName string
    29  
    30  // prepareContainer create an Oracle Docker Container
    31  func prepareContainer() (container *dockertest.Resource, err error) {
    32  	if os.Getenv("SKIP_ORACLE") != "" {
    33  		err = fmt.Errorf("skipping ORACLE Container in CI environment")
    34  		return
    35  	}
    36  	containerName = os.Getenv("CONTAINER_NAME")
    37  	if containerName == "" {
    38  		containerName = "tnscli-oracledb"
    39  	}
    40  	var pool *dockertest.Pool
    41  	pool, err = common.GetDockerPool()
    42  	if err != nil {
    43  		return
    44  	}
    45  
    46  	vendorImagePrefix := os.Getenv("VENDOR_IMAGE_PREFIX")
    47  	repoString := vendorImagePrefix + repo
    48  
    49  	fmt.Printf("Try to start docker container for %s:%s\n", repoString, repoTag)
    50  	container, err = pool.RunWithOptions(&dockertest.RunOptions{
    51  		Repository: repoString,
    52  		Tag:        repoTag,
    53  
    54  		Hostname: containerName,
    55  		Name:     containerName,
    56  		Env: []string{
    57  			"ORACLE_PASSWORD=" + DBPASSWORD,
    58  		},
    59  		ExposedPorts: []string{"1521"},
    60  		// need fixed mapping here
    61  		PortBindings: map[docker.Port][]docker.PortBinding{
    62  			"1521": {
    63  				{HostIP: "0.0.0.0", HostPort: DBPort},
    64  			},
    65  		},
    66  		Mounts: []string{
    67  			test.TestDir + "/docker/oracle-db:/container-entrypoint-initdb.d:ro",
    68  		},
    69  	}, func(config *docker.HostConfig) {
    70  		// set AutoRemove to true so that stopped container goes away by itself
    71  		config.AutoRemove = true
    72  		config.RestartPolicy = docker.RestartPolicy{Name: "no"}
    73  	})
    74  
    75  	if err != nil {
    76  		err = fmt.Errorf("error starting DB docker %s container: %v", containerName, err)
    77  		_ = pool.Purge(container)
    78  		return
    79  	}
    80  
    81  	start := time.Now()
    82  	err = WaitForOracle(pool)
    83  	if err != nil {
    84  		_ = pool.Purge(container)
    85  		return
    86  	}
    87  	elapsed := time.Since(start)
    88  	fmt.Printf("DB Container is available after %s\n", elapsed.Round(time.Millisecond))
    89  	err = nil
    90  	return
    91  }
    92  
    93  // WaitForOracle waits to successfully connect to Oracle
    94  func WaitForOracle(pool *dockertest.Pool) (err error) {
    95  	if os.Getenv("SKIP_ORACLE") != "" {
    96  		err = fmt.Errorf("skipping ORACLE Container in CI environment")
    97  		return
    98  	}
    99  
   100  	if pool == nil {
   101  		pool, err = common.GetDockerPool()
   102  		if err != nil {
   103  			return
   104  		}
   105  	}
   106  
   107  	pool.MaxWait = containerTimeout * time.Second
   108  	target = fmt.Sprintf("oracle://%s:%s@%s:%s/%s", SYSTEMUSER, DBPASSWORD, dbhost, DBPort, SYSTEMSERVICE)
   109  	fmt.Printf("Wait to successfully init db with %s (max %ds)...\n", target, containerTimeout)
   110  	start := time.Now()
   111  	if err = pool.Retry(func() error {
   112  		var err error
   113  		var db *sql.DB
   114  		db, err = sql.Open("oracle", target)
   115  		if err != nil {
   116  			// cannot open connection
   117  			return err
   118  		}
   119  		err = db.Ping()
   120  		if err != nil {
   121  			// db not answering
   122  			return err
   123  		}
   124  		// check if init_done table exists, then we are ready
   125  		checkSQL := "select count(*) from init_done"
   126  		row := db.QueryRow(checkSQL)
   127  		var count int64
   128  		err = row.Scan(&count)
   129  		if err != nil {
   130  			// query failed, final init table not there
   131  			return err
   132  		}
   133  		return nil
   134  	}); err != nil {
   135  		fmt.Printf("DB Container not ready: %s", err)
   136  		return
   137  	}
   138  	elapsed := time.Since(start)
   139  	fmt.Printf("DB Ready is available after %s\n", elapsed.Round(time.Millisecond))
   140  	// wait for init scripts finished
   141  	err = nil
   142  	return
   143  }