1 package database
2
3 import (
4 "context"
5 "testing"
6
7 "github.com/DATA-DOG/go-sqlmock"
8 "github.com/jackc/pgconn"
9 "github.com/stretchr/testify/assert"
10 "github.com/stretchr/testify/require"
11
12 "edge-infra.dev/pkg/lib/fog"
13 rulesengine "edge-infra.dev/pkg/sds/emergencyaccess/rules"
14 datasql "edge-infra.dev/pkg/sds/emergencyaccess/rules/storage/database/sql"
15 )
16
17 func TestAddCommands(t *testing.T) {
18 db, mock := initMockDB(t)
19 defer db.Close()
20 ds := New(fog.New(), db)
21
22 mock.ExpectBegin()
23 mock.ExpectExec(datasql.InsertCommand).WithArgs("ls").WillReturnResult(sqlmock.NewResult(1, 1))
24 mock.ExpectExec(datasql.InsertCommand).WithArgs("mv").WillReturnResult(sqlmock.NewResult(2, 1))
25 mock.ExpectCommit()
26
27 res, err := ds.AddCommands(context.Background(), []string{"ls", "mv"})
28 assert.NoError(t, err)
29 assert.Nil(t, res.Conflicts)
30 if err := mock.ExpectationsWereMet(); err != nil {
31 t.Errorf("there were unfulfilled expectations: %s", err)
32 }
33 }
34
35 func TestDeleteCommand(t *testing.T) {
36 db, mock := initMockDB(t)
37 defer db.Close()
38 ds := New(fog.New(), db)
39
40 mock.ExpectExec(datasql.DeleteCommand).WithArgs("ls").WillReturnResult(sqlmock.NewResult(1, 1))
41
42 _, err := ds.DeleteCommand(context.Background(), "ls")
43 assert.NoError(t, err)
44 if err := mock.ExpectationsWereMet(); err != nil {
45 t.Errorf("there were unfulfilled expectations: %s", err)
46 }
47 }
48
49 func TestDeleteCommandNoChange(t *testing.T) {
50 db, mock := initMockDB(t)
51 defer db.Close()
52 ds := New(fog.New(), db)
53
54 command := "not-on-db"
55 mock.ExpectExec(datasql.DeleteCommand).WithArgs(command).WillReturnResult(sqlmock.NewResult(0, 0))
56
57 res, err := ds.DeleteCommand(context.Background(), command)
58 assert.NoError(t, err)
59 if err := mock.ExpectationsWereMet(); err != nil {
60 t.Errorf("there were unfulfilled expectations: %s", err)
61 }
62 assert.NotEmpty(t, res.Errors)
63 assert.Equal(t, rulesengine.UnknownCommand, res.Errors[0].Type)
64 assert.Equal(t, int64(0), res.RowsAffected)
65 }
66
67 func TestDeleteCommandConflict(t *testing.T) {
68 db, mock := initMockDB(t)
69 defer db.Close()
70 ds := New(fog.New(), db)
71
72 command := "ls"
73 mock.ExpectExec(datasql.DeleteCommand).WithArgs(command).WillReturnError(&pgconn.PgError{Code: "23503"})
74
75 res, err := ds.DeleteCommand(context.Background(), command)
76 assert.NoError(t, err)
77 if err := mock.ExpectationsWereMet(); err != nil {
78 t.Errorf("there were unfulfilled expectations: %s", err)
79 }
80 assert.NotEmpty(t, res.Errors)
81 assert.Equal(t, rulesengine.Conflict, res.Errors[0].Type)
82 assert.Equal(t, res.RowsAffected, int64(0))
83 }
84
85 func TestReadCommand(t *testing.T) {
86 db, mock := initMockDB(t)
87 defer db.Close()
88 ds := New(fog.New(), db)
89
90 mockRow := sqlmock.NewRows([]string{"command_id", "name"}).AddRow("test", "ls")
91 mock.ExpectQuery(datasql.SelectCommandByName).WithArgs("ls").WillReturnRows(mockRow)
92
93 res, err := ds.ReadCommand(context.Background(), "ls")
94 assert.NoError(t, err)
95 assert.EqualValues(t, rulesengine.Command{Name: "ls", ID: "test"}, res)
96 if err := mock.ExpectationsWereMet(); err != nil {
97 t.Errorf("there were unfulfilled expectations: %s", err)
98 }
99 }
100
101 func TestReadAllCommands(t *testing.T) {
102 db, mock := initMockDB(t)
103 defer db.Close()
104 ds := New(fog.New(), db)
105
106 mockRow := sqlmock.NewRows([]string{"command_id", "name"}).AddRow("test", "ls")
107 mock.ExpectQuery(datasql.SelectAllCommands).WillReturnRows(mockRow)
108
109 res, err := ds.ReadAllCommands(context.Background())
110 assert.EqualValues(t, []rulesengine.Command{{Name: "ls", ID: "test"}}, res)
111 assert.NoError(t, err)
112 if err := mock.ExpectationsWereMet(); err != nil {
113 t.Errorf("there were unfulfilled expectations: %s", err)
114 }
115 }
116
117
118 func TestReadCommandsWithFilter(t *testing.T) {
119 t.Parallel()
120
121 tests := map[string]struct {
122 args []string
123 mockRowsFunc func(mock sqlmock.Sqlmock) *sqlmock.ExpectedQuery
124 expectedRes []rulesengine.Command
125 }{
126 "All Valid": {
127 args: []string{"name1", "name2", "name3"},
128 mockRowsFunc: func(mock sqlmock.Sqlmock) *sqlmock.ExpectedQuery {
129 mockRows := sqlmock.NewRows([]string{"command_id", "name"}).AddRow("id1", "name1").AddRow("id2", "name2").AddRow("id3", "name3")
130 return mock.ExpectQuery(datasql.SelectCommandsByName).WithArgs([]string{"name1", "name2", "name3"}).WillReturnRows(mockRows)
131 },
132 expectedRes: []rulesengine.Command{
133 {ID: "id1", Name: "name1"},
134 {ID: "id2", Name: "name2"},
135 {ID: "id3", Name: "name3"},
136 },
137 },
138 "No Rows Returned": {
139 args: []string{"nonexistant1", "nonexistant2", "nonexistant3"},
140 mockRowsFunc: func(mock sqlmock.Sqlmock) *sqlmock.ExpectedQuery {
141 mockRows := sqlmock.NewRows([]string{"command_id", "name"})
142 return mock.ExpectQuery(datasql.SelectCommandsByName).WithArgs([]string{"nonexistant1", "nonexistant2", "nonexistant3"}).WillReturnRows(mockRows)
143 },
144 },
145 "Some Valid": {
146 args: []string{"name1", "nonexistant2", "name3"},
147 mockRowsFunc: func(mock sqlmock.Sqlmock) *sqlmock.ExpectedQuery {
148 mockRows := sqlmock.NewRows([]string{"command_id", "name"}).AddRow("id1", "name1").AddRow("id3", "name3")
149 return mock.ExpectQuery(datasql.SelectCommandsByName).WithArgs([]string{"name1", "nonexistant2", "name3"}).WillReturnRows(mockRows)
150 },
151 expectedRes: []rulesengine.Command{
152 {ID: "id1", Name: "name1"},
153 {ID: "id3", Name: "name3"},
154 },
155 },
156 "No Filter Passed In": {
157 mockRowsFunc: func(mock sqlmock.Sqlmock) *sqlmock.ExpectedQuery {
158 mockRows := sqlmock.NewRows([]string{"command_id", "name"}).AddRow("all", "all")
159 return mock.ExpectQuery(datasql.SelectAllCommands).WillReturnRows(mockRows)
160 },
161 expectedRes: []rulesengine.Command{
162 {ID: "all", Name: "all"},
163 },
164 },
165 }
166
167 for name, tc := range tests {
168 tc := tc
169 t.Run(name, func(t *testing.T) {
170 t.Parallel()
171
172 db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual), sqlmock.ValueConverterOption(StringSliceValueConverter{}))
173 require.NoError(t, err, "an error '%s' was not expected when opening a stub database connection", err)
174 defer db.Close()
175
176 ds := New(fog.New(), db)
177 tc.mockRowsFunc(mock)
178
179 res, err := ds.ReadCommandsWithFilter(context.Background(), tc.args)
180
181 assert.EqualValues(t, tc.expectedRes, res)
182 assert.NoError(t, err)
183 if err := mock.ExpectationsWereMet(); err != nil {
184 t.Errorf("there were unfulfilled expectations: %s", err)
185 }
186 })
187 }
188 }
189
View as plain text