1 package clickhouse_test
2
3 import (
4 "context"
5 "database/sql"
6 sqldriver "database/sql/driver"
7 "fmt"
8 "log"
9 "testing"
10
11 _ "github.com/ClickHouse/clickhouse-go"
12 "github.com/dhui/dktest"
13 "github.com/golang-migrate/migrate/v4"
14 "github.com/golang-migrate/migrate/v4/database/clickhouse"
15 dt "github.com/golang-migrate/migrate/v4/database/testing"
16 "github.com/golang-migrate/migrate/v4/dktesting"
17 _ "github.com/golang-migrate/migrate/v4/source/file"
18 )
19
20 const defaultPort = 9000
21
22 var (
23 tableEngines = []string{"TinyLog", "MergeTree"}
24 opts = dktest.Options{
25 Env: map[string]string{"CLICKHOUSE_USER": "user", "CLICKHOUSE_PASSWORD": "password", "CLICKHOUSE_DB": "db"},
26 PortRequired: true, ReadyFunc: isReady,
27 }
28 specs = []dktesting.ContainerSpec{
29 {ImageName: "yandex/clickhouse-server:21.3", Options: opts},
30 }
31 )
32
33 func clickhouseConnectionString(host, port, engine string) string {
34 if engine != "" {
35 return fmt.Sprintf(
36 "clickhouse://%v:%v?username=user&password=password&database=db&x-multi-statement=true&x-migrations-table-engine=%v&debug=false",
37 host, port, engine)
38 }
39
40 return fmt.Sprintf(
41 "clickhouse://%v:%v?username=user&password=password&database=db&x-multi-statement=true&debug=false",
42 host, port)
43 }
44
45 func isReady(ctx context.Context, c dktest.ContainerInfo) bool {
46 ip, port, err := c.Port(defaultPort)
47 if err != nil {
48 return false
49 }
50
51 db, err := sql.Open("clickhouse", clickhouseConnectionString(ip, port, ""))
52
53 if err != nil {
54 log.Println("open error", err)
55 return false
56 }
57 defer func() {
58 if err := db.Close(); err != nil {
59 log.Println("close error:", err)
60 }
61 }()
62
63 if err = db.PingContext(ctx); err != nil {
64 switch err {
65 case sqldriver.ErrBadConn:
66 return false
67 default:
68 fmt.Println(err)
69 }
70 return false
71 }
72
73 return true
74 }
75
76 func TestCases(t *testing.T) {
77 for _, engine := range tableEngines {
78 t.Run("Test_"+engine, func(t *testing.T) { testSimple(t, engine) })
79 t.Run("Migrate_"+engine, func(t *testing.T) { testMigrate(t, engine) })
80 t.Run("Version_"+engine, func(t *testing.T) { testVersion(t, engine) })
81 t.Run("Drop_"+engine, func(t *testing.T) { testDrop(t, engine) })
82 }
83 t.Run("WithInstanceDefaultConfigValues", func(t *testing.T) { testSimpleWithInstanceDefaultConfigValues(t) })
84 }
85
86 func testSimple(t *testing.T, engine string) {
87 dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) {
88 ip, port, err := c.Port(defaultPort)
89 if err != nil {
90 t.Fatal(err)
91 }
92
93 addr := clickhouseConnectionString(ip, port, engine)
94 p := &clickhouse.ClickHouse{}
95 d, err := p.Open(addr)
96 if err != nil {
97 t.Fatal(err)
98 }
99 defer func() {
100 if err := d.Close(); err != nil {
101 t.Error(err)
102 }
103 }()
104
105 dt.Test(t, d, []byte("SELECT 1"))
106 })
107 }
108
109 func testSimpleWithInstanceDefaultConfigValues(t *testing.T) {
110 dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) {
111 ip, port, err := c.Port(defaultPort)
112 if err != nil {
113 t.Fatal(err)
114 }
115
116 addr := clickhouseConnectionString(ip, port, "")
117 conn, err := sql.Open("clickhouse", addr)
118 if err != nil {
119 t.Fatal(err)
120 }
121 d, err := clickhouse.WithInstance(conn, &clickhouse.Config{})
122 if err != nil {
123 _ = conn.Close()
124 t.Fatal(err)
125 }
126 defer func() {
127 if err := d.Close(); err != nil {
128 t.Error(err)
129 }
130 }()
131
132 dt.Test(t, d, []byte("SELECT 1"))
133 })
134 }
135
136 func testMigrate(t *testing.T, engine string) {
137 dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) {
138 ip, port, err := c.Port(defaultPort)
139 if err != nil {
140 t.Fatal(err)
141 }
142
143 addr := clickhouseConnectionString(ip, port, engine)
144 p := &clickhouse.ClickHouse{}
145 d, err := p.Open(addr)
146 if err != nil {
147 t.Fatal(err)
148 }
149 defer func() {
150 if err := d.Close(); err != nil {
151 t.Error(err)
152 }
153 }()
154 m, err := migrate.NewWithDatabaseInstance("file://./examples/migrations", "db", d)
155
156 if err != nil {
157 t.Fatal(err)
158 }
159 dt.TestMigrate(t, m)
160 })
161 }
162
163 func testVersion(t *testing.T, engine string) {
164 dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) {
165 expectedVersion := 1
166
167 ip, port, err := c.Port(defaultPort)
168 if err != nil {
169 t.Fatal(err)
170 }
171
172 addr := clickhouseConnectionString(ip, port, engine)
173 p := &clickhouse.ClickHouse{}
174 d, err := p.Open(addr)
175 if err != nil {
176 t.Fatal(err)
177 }
178 defer func() {
179 if err := d.Close(); err != nil {
180 t.Error(err)
181 }
182 }()
183
184 err = d.SetVersion(expectedVersion, false)
185 if err != nil {
186 t.Fatal(err)
187 }
188
189 version, _, err := d.Version()
190 if err != nil {
191 t.Fatal(err)
192 }
193
194 if version != expectedVersion {
195 t.Fatal("Version mismatch")
196 }
197 })
198 }
199
200 func testDrop(t *testing.T, engine string) {
201 dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) {
202 ip, port, err := c.Port(defaultPort)
203 if err != nil {
204 t.Fatal(err)
205 }
206
207 addr := clickhouseConnectionString(ip, port, engine)
208 p := &clickhouse.ClickHouse{}
209 d, err := p.Open(addr)
210 if err != nil {
211 t.Fatal(err)
212 }
213 defer func() {
214 if err := d.Close(); err != nil {
215 t.Error(err)
216 }
217 }()
218
219 err = d.Drop()
220 if err != nil {
221 t.Fatal(err)
222 }
223 })
224 }
225
View as plain text