Passed
Push — main ( 6ef1c9...bfdedc )
by Christian
01:44 queued 16s
created

lConn_CanThrowUniqueConstraintViolationError   A

Complexity

Conditions 1

Size

Total Lines 18
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 12
nop 1
dl 0
loc 18
rs 9.8
c 0
b 0
f 0
1
package sqldb
2
3
import (
4
	"database/sql"
5
	"fmt"
6
	"testing"
7
	"time"
8
9
	"github.com/cdleo/go-commons/logger"
10
	"github.com/cdleo/go-commons/sqlcommons"
11
	"github.com/cdleo/go-sqldb/adapter"
12
	"github.com/cdleo/go-sqldb/connector"
13
14
	"github.com/stretchr/testify/require"
15
)
16
17
type Customers struct {
18
	Id         int           `db:"id"`
19
	Name       string        `db:"name"`
20
	Updatetime time.Time     `db:"updatetime"`
21
	Age        sql.NullInt64 `db:"age"`
22
	Group      int           `db:"cust_group"`
23
	Dummy      string        `db:"not_existing_field"`
24
}
25
26
func Test_sqlConn_InitErr(t *testing.T) {
27
	// Setup
28
	sqlProxy := NewSQLProxyBuilder(connector.NewMockSQLConnector(false)).
29
		WithAdapter(adapter.NewNoopAdapter()).
30
		WithLogger(logger.NewNoLogLogger()).
31
		Build()
32
33
	_, err := sqlProxy.Open()
34
	require.Error(t, err)
35
}
36
37
func Test_sqlConn_InitOK(t *testing.T) {
38
	// Setup
39
	sqlProxy := NewSQLProxyBuilder(connector.NewMockSQLConnector(true)).
40
		WithAdapter(adapter.NewNoopAdapter()).
41
		WithLogger(logger.NewNoLogLogger()).
42
		Build()
43
44
	_, err := sqlProxy.Open()
45
	require.NoError(t, err)
46
}
47
48
func Test_sqlConn_CreateTables(t *testing.T) {
49
	// Setup
50
	sqlProxy := NewSQLProxyBuilder(connector.NewSqlite3Connector(":memory:")).
51
		WithAdapter(adapter.NewSQLite3Adapter()).
52
		WithLogger(logger.NewNoLogLogger()).
53
		Build()
54
55
	sqlDB, err := sqlProxy.Open()
56
	require.NoError(t, err)
57
58
	// Exec
59
	require.NoError(t, createTablesHelper(sqlDB))
60
61
	sqlProxy.Close()
62
}
63
64
func Test_sqlConn_DropTables(t *testing.T) {
65
	// Setup
66
	sqlProxy := NewSQLProxyBuilder(connector.NewSqlite3Connector(":memory:")).
67
		WithAdapter(adapter.NewSQLite3Adapter()).
68
		WithLogger(logger.NewNoLogLogger()).
69
		Build()
70
71
	sqlDB, err := sqlProxy.Open()
72
	require.NoError(t, err)
73
	defer sqlProxy.Close()
74
75
	require.NoError(t, createTablesHelper(sqlDB))
76
77
	// Exec
78
	require.NoError(t, dropTablesHelper(sqlDB))
79
}
80
81
func Test_sqlConn_StoreData(t *testing.T) {
82
	// Setup
83
	sqlProxy := NewSQLProxyBuilder(connector.NewSqlite3Connector(":memory:")).
84
		WithAdapter(adapter.NewSQLite3Adapter()).
85
		WithLogger(logger.NewNoLogLogger()).
86
		Build()
87
88
	sqlDB, err := sqlProxy.Open()
89
	require.NoError(t, err)
90
	defer sqlProxy.Close()
91
92
	require.NoError(t, createTablesHelper(sqlDB))
93
94
	// Exec
95
	require.NoError(t, insertDataHelper(sqlDB))
96
}
97
98
func Test_sqlConn_ReturnData(t *testing.T) {
99
	// Setup
100
	sqlProxy := NewSQLProxyBuilder(connector.NewSqlite3Connector(":memory:")).
101
		WithAdapter(adapter.NewSQLite3Adapter()).
102
		WithLogger(logger.NewNoLogLogger()).
103
		Build()
104
105
	sqlDB, err := sqlProxy.Open()
106
	require.NoError(t, err)
107
	defer sqlProxy.Close()
108
109
	require.NoError(t, createTablesHelper(sqlDB))
110
	require.NoError(t, insertDataHelper(sqlDB))
111
112
	// Exec
113
	rows, err2 := sqlDB.Query("SELECT name FROM customers")
114
	defer rows.Close()
115
116
	require.NoError(t, err2)
117
	require.True(t, rows.Next())
118
}
119
120
func Test_sqlConn_CanThrowInvalidTableError(t *testing.T) {
121
	// Setup
122
	sqlProxy := NewSQLProxyBuilder(connector.NewSqlite3Connector(":memory:")).
123
		WithAdapter(adapter.NewSQLite3Adapter()).
124
		WithLogger(logger.NewNoLogLogger()).
125
		Build()
126
127
	sqlDB, err := sqlProxy.Open()
128
	require.NoError(t, err)
129
	defer sqlProxy.Close()
130
131
	require.NoError(t, createTablesHelper(sqlDB))
132
	require.NoError(t, insertDataHelper(sqlDB))
133
134
	// Exec
135
	_, err2 := sqlDB.Query("SELECT name FROM customerxs")
136
137
	require.Error(t, err2)
138
}
139
140
func Test_sqlConn_CanThrowCannotInsertNullError(t *testing.T) {
141
	// Setup
142
	sqlProxy := NewSQLProxyBuilder(connector.NewSqlite3Connector(":memory:")).
143
		WithAdapter(adapter.NewSQLite3Adapter()).
144
		WithLogger(logger.NewNoLogLogger()).
145
		Build()
146
147
	sqlDB, err := sqlProxy.Open()
148
	require.NoError(t, err)
149
	defer sqlProxy.Close()
150
151
	require.NoError(t, createTablesHelper(sqlDB))
152
153
	// Exec
154
	_, err2 := sqlDB.Exec("INSERT INTO customers (name, updatetime) VALUES (:1,:2)", nil, time.Now())
155
156
	require.ErrorIs(t, err2, sqlcommons.CannotSetNullColumn)
157
}
158
159
func Test_sqlConn_CanThrowCannotUpdateNullError(t *testing.T) {
160
	// Setup
161
	sqlProxy := NewSQLProxyBuilder(connector.NewSqlite3Connector(":memory:")).
162
		WithAdapter(adapter.NewSQLite3Adapter()).
163
		WithLogger(logger.NewNoLogLogger()).
164
		Build()
165
166
	sqlDB, err := sqlProxy.Open()
167
	require.NoError(t, err)
168
	defer sqlProxy.Close()
169
170
	require.NoError(t, createTablesHelper(sqlDB))
171
	require.NoError(t, insertDataHelper(sqlDB))
172
173
	// Exec
174
	_, err2 := sqlDB.Exec("UPDATE customers c SET name = :1 WHERE c.name = :2", nil, "Pablo")
175
176
	require.Error(t, err2, sqlcommons.CannotSetNullColumn)
177
}
178
179
func Test_sqlConn_CanThrowUniqueConstraintViolationError(t *testing.T) {
180
	// Setup
181
	sqlProxy := NewSQLProxyBuilder(connector.NewSqlite3Connector(":memory:?_foreign_keys=on")).
182
		WithAdapter(adapter.NewSQLite3Adapter()).
183
		WithLogger(logger.NewNoLogLogger()).
184
		Build()
185
186
	sqlDB, err := sqlProxy.Open()
187
	require.NoError(t, err)
188
	defer sqlProxy.Close()
189
190
	require.NoError(t, createTablesHelper(sqlDB))
191
	require.NoError(t, insertDataHelper(sqlDB))
192
193
	// Exec
194
	_, err2 := sqlDB.Exec("INSERT INTO customers (name, updatetime, age, cust_group)VALUES(:1, :2, :3, :4)", "Juan", time.Now(), nil, 1)
195
196
	require.ErrorIs(t, err2, sqlcommons.UniqueConstraintViolation)
197
198
}
199
200
func Test_sqlConn_CanThrowForeignKeyConstraintViolationError(t *testing.T) {
201
	// Setup
202
	sqlProxy := NewSQLProxyBuilder(connector.NewSqlite3Connector(":memory:?_foreign_keys=on")).
203
		WithAdapter(adapter.NewSQLite3Adapter()).
204
		WithLogger(logger.NewNoLogLogger()).
205
		Build()
206
207
	sqlDB, err := sqlProxy.Open()
208
	require.NoError(t, err)
209
	defer sqlProxy.Close()
210
211
	require.NoError(t, createTablesHelper(sqlDB))
212
	require.NoError(t, insertDataHelper(sqlDB))
213
214
	// Exec
215
	_, err2 := sqlDB.Exec("UPDATE customers SET cust_group = :1 WHERE name = :2", 2, "Pablo")
216
217
	require.ErrorIs(t, err2, sqlcommons.IntegrityConstraintViolation)
218
219
}
220
221
func Test_sqlConn_CanThrowIntegrityConstraintViolationError(t *testing.T) {
222
	// Setup
223
	sqlProxy := NewSQLProxyBuilder(connector.NewSqlite3Connector(":memory:?_foreign_keys=on")).
224
		WithAdapter(adapter.NewSQLite3Adapter()).
225
		WithLogger(logger.NewNoLogLogger()).
226
		Build()
227
228
	sqlDB, err := sqlProxy.Open()
229
	require.NoError(t, err)
230
	defer sqlProxy.Close()
231
232
	require.NoError(t, createTablesHelper(sqlDB))
233
	require.NoError(t, insertDataHelper(sqlDB))
234
235
	// Exec
236
	_, err2 := sqlDB.Exec("DELETE from customers_groups WHERE id = :1", 1)
237
238
	require.ErrorIs(t, err2, sqlcommons.IntegrityConstraintViolation)
239
}
240
241
func Test_sqlConn_CanThrowValueTooLargeError(t *testing.T) {
242
	// Setup
243
	connector := connector.NewMockSQLConnector(true)
244
	sqlProxy := NewSQLProxyBuilder(connector).
245
		WithAdapter(adapter.NewNoopAdapter()).
246
		WithLogger(logger.NewNoLogLogger()).
247
		Build()
248
249
	sqlDB, err := sqlProxy.Open()
250
	require.NoError(t, err)
251
	defer sqlProxy.Close()
252
253
	// Exec
254
	query := fmt.Sprintf("INSERT INTO customers (name, cust_group) VALUES (%s,%d)", "'verylongname'", 1)
255
	connector.PatchExec(query, sqlcommons.ValueTooLargeForColumn)
256
257
	_, err2 := sqlDB.Exec(query)
258
259
	require.ErrorIs(t, err2, sqlcommons.ValueTooLargeForColumn)
260
}
261
262
func Test_sqlConn_CanThrowSubqueryReturnsMoreThanOneRowError(t *testing.T) {
263
	// Setup
264
	connector := connector.NewMockSQLConnector(true)
265
	sqlProxy := NewSQLProxyBuilder(connector).
266
		WithAdapter(adapter.NewNoopAdapter()).
267
		WithLogger(logger.NewNoLogLogger()).
268
		Build()
269
270
	sqlDB, err := sqlProxy.Open()
271
	require.NoError(t, err)
272
	defer sqlProxy.Close()
273
274
	query := "SELECT name FROM customers WHERE id = (SELECT id FROM customers)"
275
	connector.PatchQuery(query, nil, nil, sqlcommons.SubqueryReturnsMoreThanOneRow)
276
277
	// Exec
278
	_, err2 := sqlDB.Query(query)
279
280
	require.ErrorIs(t, err2, sqlcommons.SubqueryReturnsMoreThanOneRow)
281
}
282
283
func Test_sqlConn_CanThrowInvalidNumericValueError(t *testing.T) {
284
	// Setup
285
	connector := connector.NewMockSQLConnector(true)
286
	sqlProxy := NewSQLProxyBuilder(connector).
287
		WithAdapter(adapter.NewNoopAdapter()).
288
		WithLogger(logger.NewNoLogLogger()).
289
		Build()
290
291
	sqlDB, err := sqlProxy.Open()
292
	require.NoError(t, err)
293
	defer sqlProxy.Close()
294
295
	query := "UPDATE customers SET age = :1 WHERE name = :2"
296
	connector.PatchExec(query, sqlcommons.InvalidNumericValue, "twelve", "Pablo")
297
298
	// Exec
299
	_, err2 := sqlDB.Exec(query, "twelve", "Pablo")
300
301
	require.ErrorIs(t, err2, sqlcommons.InvalidNumericValue)
302
}
303
304
func Test_sqlConn_CanThrowValueLargerThanPrecisionError(t *testing.T) {
305
	// Setup
306
	connector := connector.NewMockSQLConnector(true)
307
	sqlProxy := NewSQLProxyBuilder(connector).
308
		WithAdapter(adapter.NewNoopAdapter()).
309
		WithLogger(logger.NewNoLogLogger()).
310
		Build()
311
312
	sqlDB, err := sqlProxy.Open()
313
	require.NoError(t, err)
314
	defer sqlProxy.Close()
315
316
	query := "UPDATE customers SET age = :1 WHERE name = :2"
317
	connector.PatchExec(query, sqlcommons.ValueLargerThanPrecision, 949.0044, "Pablo")
318
319
	// Exec
320
	_, err2 := sqlDB.Exec(query, 949.0044, "Pablo")
321
322
	require.ErrorIs(t, err2, sqlcommons.ValueLargerThanPrecision)
323
}
324
325
func createTablesHelper(sqlClient *sql.DB) error {
326
327
	if _, err := sqlClient.Exec(`CREATE TABLE IF NOT EXISTS customers_groups (
328
		id INTEGER PRIMARY KEY AUTOINCREMENT,
329
		groupname TEXT NOT NULL)`); err != nil {
330
		return err
331
	}
332
	if _, err := sqlClient.Exec(`CREATE TABLE IF NOT EXISTS customers (
333
		id INTEGER PRIMARY KEY AUTOINCREMENT,
334
		name CHAR(10) NOT NULL,
335
		updatetime TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
336
		age INT NULL,
337
		cust_group INT NOT NULL,
338
		FOREIGN KEY (cust_group) REFERENCES customers_groups (id) ON DELETE RESTRICT
339
		CONSTRAINT customers_un UNIQUE (name))`); err != nil {
340
		return err
341
	}
342
	return nil
343
}
344
345
func insertDataHelper(sqlClient *sql.DB) error {
346
347
	if _, err := sqlClient.Exec(`INSERT INTO customers_groups (groupname) VALUES('General');`); err != nil {
348
		return err
349
	}
350
351
	if statement, err := sqlClient.Prepare("INSERT INTO customers (name, updatetime, age, cust_group)VALUES(:1, :2, :3, :4)"); err != nil {
352
		return err
353
	} else {
354
		if _, err := statement.Exec("Juan", time.Now(), nil, 1); err != nil {
355
			return err
356
		}
357
		if _, err := statement.Exec("Pedro", time.Now(), nil, 1); err != nil {
358
			return err
359
		}
360
		if _, err := statement.Exec("Pablo", time.Now(), 99, 1); err != nil {
361
			return err
362
		}
363
	}
364
365
	return nil
366
}
367
368
func dropTablesHelper(sqlClient *sql.DB) error {
369
370
	if _, err := sqlClient.Exec(`DROP TABLE IF EXISTS customers_groups`); err != nil {
371
		return err
372
	}
373
	if _, err := sqlClient.Exec(`DROP TABLE IF EXISTS customers`); err != nil {
374
		return err
375
	}
376
	return nil
377
}
378