github.com/etecs-ru/gnomock@v0.13.2/preset/cockroachdb/preset.go (about) 1 // Package cockroachdb includes CockroachDB implementation of Gnomock Preset interface. 2 // This Preset can be passed to gnomock.Start() function to create a configured 3 // CockroachDB container to use in tests. 4 // 5 // Containers created with this preset use `root` user without a password for 6 // authentication. There is currently no way to setup an initial user at create 7 // time. 8 // 9 // By default, a new database "mydb" is created, and all the provided queries 10 // are executed against it. 11 package cockroachdb 12 13 import ( 14 "context" 15 "database/sql" 16 "fmt" 17 "io/ioutil" 18 19 "github.com/etecs-ru/gnomock" 20 "github.com/etecs-ru/gnomock/internal/registry" 21 _ "github.com/lib/pq" // postgres driver 22 ) 23 24 const ( 25 defaultVersion = "v20.1.10" 26 defaultPort = 26257 27 defaultDatabase = "mydb" 28 ) 29 30 func init() { 31 registry.Register("cockroachdb", func() gnomock.Preset { return &P{} }) 32 } 33 34 // Preset creates a new Gmomock CockroachDB preset. This preset includes a CockroachDB 35 // specific healthcheck function and default CockroachDB image and port. 36 func Preset(opts ...Option) gnomock.Preset { 37 p := &P{} 38 39 for _, opt := range opts { 40 opt(p) 41 } 42 43 return p 44 } 45 46 // P is a Gnomock Preset implementation for CockroachDB. 47 type P struct { 48 Version string `json:"version"` 49 DB string `json:"db"` 50 Queries []string `json:"queries"` 51 QueriesFiles []string `json:"queries_files"` 52 } 53 54 // Image returns an image that should be pulled to create this container. 55 func (p *P) Image() string { 56 return fmt.Sprintf("docker.io/cockroachdb/cockroach:%s", p.Version) 57 } 58 59 // Ports returns ports that should be used to access this container. 60 func (p *P) Ports() gnomock.NamedPorts { 61 return gnomock.DefaultTCP(defaultPort) 62 } 63 64 // Options returns a list of options to configure this container. 65 func (p *P) Options() []gnomock.Option { 66 p.setDefaults() 67 68 opts := []gnomock.Option{ 69 gnomock.WithHealthCheck(healthcheck), 70 gnomock.WithCommand("start-single-node", "--insecure"), 71 gnomock.WithInit(p.initf()), 72 } 73 74 return opts 75 } 76 77 func (p *P) setDefaults() { 78 if p.Version == "" { 79 p.Version = defaultVersion 80 } 81 82 if p.DB == "" { 83 p.DB = defaultDatabase 84 } 85 } 86 87 func healthcheck(ctx context.Context, c *gnomock.Container) error { 88 db, err := connect(c, "") 89 if err != nil { 90 return err 91 } 92 93 defer func() { 94 _ = db.Close() 95 }() 96 97 var one int 98 99 return db.QueryRow(`select 1`).Scan(&one) 100 } 101 102 func (p *P) initf() gnomock.InitFunc { 103 return func(ctx context.Context, c *gnomock.Container) error { 104 db, err := connect(c, "") 105 if err != nil { 106 return err 107 } 108 109 _, err = db.Exec("create database " + p.DB) 110 if err != nil { 111 return err 112 } 113 114 _ = db.Close() 115 116 db, err = connect(c, p.DB) 117 if err != nil { 118 return err 119 } 120 121 defer func() { _ = db.Close() }() 122 123 if len(p.QueriesFiles) > 0 { 124 for _, f := range p.QueriesFiles { 125 bs, err := ioutil.ReadFile(f) // nolint:gosec 126 if err != nil { 127 return fmt.Errorf("can't read queries file '%s': %w", f, err) 128 } 129 130 p.Queries = append([]string{string(bs)}, p.Queries...) 131 } 132 } 133 134 for _, q := range p.Queries { 135 _, err = db.Exec(q) 136 if err != nil { 137 return err 138 } 139 } 140 141 return nil 142 } 143 } 144 145 func connect(c *gnomock.Container, db string) (*sql.DB, error) { 146 connStr := fmt.Sprintf( 147 "host=%s port=%d sslmode=disable user=root dbname=%s", 148 c.Host, c.Port(gnomock.DefaultPort), db, 149 ) 150 151 conn, err := sql.Open("postgres", connStr) 152 if err != nil { 153 return nil, err 154 } 155 156 return conn, conn.Ping() 157 }