github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/repo/list_union_test.go (about)

     1  package repo_test
     2  
     3  import (
     4  	"context"
     5  	"database/sql/driver"
     6  	"fmt"
     7  	"regexp"
     8  	"testing"
     9  
    10  	"github.com/DATA-DOG/go-sqlmock"
    11  	"github.com/jmoiron/sqlx"
    12  	"github.com/kyma-incubator/compass/components/director/internal/repo"
    13  	"github.com/kyma-incubator/compass/components/director/internal/repo/testdb"
    14  	"github.com/kyma-incubator/compass/components/director/pkg/apperrors"
    15  	"github.com/kyma-incubator/compass/components/director/pkg/persistence"
    16  	"github.com/kyma-incubator/compass/components/director/pkg/resource"
    17  	"github.com/stretchr/testify/assert"
    18  	"github.com/stretchr/testify/require"
    19  )
    20  
    21  func TestUnionList(t *testing.T) {
    22  	sut := repo.NewUnionLister(appTableName, appColumns)
    23  	resourceType := resource.Application
    24  	m2mTable, ok := resourceType.TenantAccessTable()
    25  	require.True(t, ok)
    26  
    27  	t.Run("success", func(t *testing.T) {
    28  		db, mock := testdb.MockDatabase(t)
    29  		defer mock.AssertExpectations(t)
    30  
    31  		rows := sqlmock.NewRows(appColumns).
    32  			AddRow(appID, appName, appDescription).
    33  			AddRow(appID2, appName2, appDescription2)
    34  
    35  		mock.ExpectQuery(regexp.QuoteMeta(fmt.Sprintf("(SELECT id, name, description FROM %s WHERE %s AND id = $2 ORDER BY id ASC LIMIT $3 OFFSET $4) UNION (SELECT id, name, description FROM %s WHERE %s AND id = $6 ORDER BY id ASC LIMIT $7 OFFSET $8)",
    36  			appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$1"), appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$5")))).
    37  			WithArgs(tenantID, appID, 10, 0, tenantID, appID2, 10, 0).WillReturnRows(rows)
    38  		mock.ExpectQuery(regexp.QuoteMeta(fmt.Sprintf("SELECT id AS id, COUNT(*) AS total_count FROM %s WHERE %s GROUP BY id ORDER BY id ASC",
    39  			appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$1")))).
    40  			WithArgs(tenantID).WillReturnRows(sqlmock.NewRows([]string{"id", "total_count"}).AddRow(appID, 1).AddRow(appID2, 1))
    41  		ctx := persistence.SaveToContext(context.TODO(), db)
    42  		var dest AppCollection
    43  
    44  		counts, err := sut.List(ctx, resourceType, tenantID, []string{appID, appID2}, "id", 10, "", repo.OrderByParams{repo.NewAscOrderBy("id")}, &dest)
    45  		require.NoError(t, err)
    46  		assert.Equal(t, 2, len(counts))
    47  		assert.Equal(t, 1, counts[appID])
    48  		assert.Equal(t, 1, counts[appID2])
    49  		assert.Len(t, dest, 2)
    50  		assert.Equal(t, *fixApp, dest[0])
    51  		assert.Equal(t, *fixApp2, dest[1])
    52  	})
    53  
    54  	t.Run("success with additional conditions", func(t *testing.T) {
    55  		db, mock := testdb.MockDatabase(t)
    56  		defer mock.AssertExpectations(t)
    57  
    58  		rows := sqlmock.NewRows(appColumns).
    59  			AddRow(appID, appName, appDescription)
    60  
    61  		mock.ExpectQuery(regexp.QuoteMeta(fmt.Sprintf("(SELECT id, name, description FROM %s WHERE name = $1 AND %s AND id = $3 ORDER BY id ASC LIMIT $4 OFFSET $5) UNION (SELECT id, name, description FROM %s WHERE name = $6 AND %s AND id = $8 ORDER BY id ASC LIMIT $9 OFFSET $10)",
    62  			appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$2"), appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$7")))).
    63  			WithArgs(appName, tenantID, appID, 10, 0, appName, tenantID, appID2, 10, 0).WillReturnRows(rows)
    64  		mock.ExpectQuery(regexp.QuoteMeta(fmt.Sprintf("SELECT id AS id, COUNT(*) AS total_count FROM %s WHERE name = $1 AND %s GROUP BY id ORDER BY id ASC",
    65  			appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$2")))).
    66  			WithArgs(appName, tenantID).WillReturnRows(sqlmock.NewRows([]string{"id", "total_count"}).AddRow(appID, 1))
    67  		ctx := persistence.SaveToContext(context.TODO(), db)
    68  		var dest AppCollection
    69  
    70  		counts, err := sut.List(ctx, resourceType, tenantID, []string{appID, appID2}, "id", 10, "", repo.OrderByParams{repo.NewAscOrderBy("id")}, &dest, repo.NewEqualCondition("name", appName))
    71  		require.NoError(t, err)
    72  		assert.Equal(t, 1, len(counts))
    73  		assert.Equal(t, 1, counts[appID])
    74  		assert.Len(t, dest, 1)
    75  		assert.Equal(t, *fixApp, dest[0])
    76  	})
    77  
    78  	t.Run("error when union list fails", func(t *testing.T) {
    79  		db, mock := testdb.MockDatabase(t)
    80  		ctx := persistence.SaveToContext(context.TODO(), db)
    81  		defer mock.AssertExpectations(t)
    82  
    83  		mock.ExpectQuery(regexp.QuoteMeta(fmt.Sprintf("(SELECT id, name, description FROM %s WHERE %s AND id = $2 ORDER BY id ASC LIMIT $3 OFFSET $4) UNION (SELECT id, name, description FROM %s WHERE %s AND id = $6 ORDER BY id ASC LIMIT $7 OFFSET $8)",
    84  			appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$1"), appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$5")))).
    85  			WithArgs(tenantID, appID, 10, 0, tenantID, appID2, 10, 0).WillReturnError(someError())
    86  		var dest AppCollection
    87  
    88  		counts, err := sut.List(ctx, resourceType, tenantID, []string{appID, appID2}, "id", 10, "", repo.OrderByParams{repo.NewAscOrderBy("id")}, &dest)
    89  		require.Error(t, err)
    90  		require.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query")
    91  		require.Nil(t, counts)
    92  	})
    93  
    94  	t.Run("error when count fails", func(t *testing.T) {
    95  		db, mock := testdb.MockDatabase(t)
    96  		ctx := persistence.SaveToContext(context.TODO(), db)
    97  		defer mock.AssertExpectations(t)
    98  
    99  		rows := sqlmock.NewRows(appColumns).
   100  			AddRow(appID, appName, appDescription).
   101  			AddRow(appID2, appName2, appDescription2)
   102  
   103  		mock.ExpectQuery(regexp.QuoteMeta(fmt.Sprintf("(SELECT id, name, description FROM %s WHERE %s AND id = $2 ORDER BY id ASC LIMIT $3 OFFSET $4) UNION (SELECT id, name, description FROM %s WHERE %s AND id = $6 ORDER BY id ASC LIMIT $7 OFFSET $8)",
   104  			appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$1"), appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$5")))).
   105  			WithArgs(tenantID, appID, 10, 0, tenantID, appID2, 10, 0).WillReturnRows(rows)
   106  		mock.ExpectQuery(regexp.QuoteMeta(fmt.Sprintf("SELECT id AS id, COUNT(*) AS total_count FROM %s WHERE %s GROUP BY id ORDER BY id ASC",
   107  			appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$1")))).
   108  			WithArgs(tenantID).WillReturnError(someError())
   109  		var dest AppCollection
   110  
   111  		counts, err := sut.List(ctx, resourceType, tenantID, []string{appID, appID2}, "id", 10, "", repo.OrderByParams{repo.NewAscOrderBy("id")}, &dest)
   112  		require.Error(t, err)
   113  		require.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query")
   114  		require.Nil(t, counts)
   115  	})
   116  
   117  	t.Run("returns error if missing persistence context", func(t *testing.T) {
   118  		ctx := context.TODO()
   119  		_, err := sut.List(ctx, resourceType, tenantID, []string{appID, appID2}, "id", 10, "", repo.OrderByParams{repo.NewAscOrderBy("id")}, nil)
   120  		require.EqualError(t, err, apperrors.NewInternalError("unable to fetch database from context").Error())
   121  	})
   122  
   123  	t.Run("returns error if empty tenant", func(t *testing.T) {
   124  		ctx := context.TODO()
   125  		_, err := sut.List(ctx, resourceType, "", []string{appID, appID2}, "id", 10, "", repo.OrderByParams{repo.NewAscOrderBy("id")}, nil)
   126  		require.EqualError(t, err, apperrors.NewTenantRequiredError().Error())
   127  	})
   128  
   129  	t.Run("returns error if wrong cursor", func(t *testing.T) {
   130  		ctx := persistence.SaveToContext(context.TODO(), &sqlx.Tx{})
   131  		_, err := sut.List(ctx, resourceType, tenantID, []string{appID, appID2}, "id", 10, "zzz", repo.OrderByParams{repo.NewAscOrderBy("id")}, nil)
   132  		require.EqualError(t, err, "while decoding page cursor: cursor is not correct: illegal base64 data at input byte 0")
   133  	})
   134  
   135  	t.Run("returns error on db operation", func(t *testing.T) {
   136  		db, mock := testdb.MockDatabase(t)
   137  		defer mock.AssertExpectations(t)
   138  
   139  		mock.ExpectQuery(`SELECT .*`).WillReturnError(someError())
   140  		ctx := persistence.SaveToContext(context.TODO(), db)
   141  		var dest AppCollection
   142  
   143  		_, err := sut.List(ctx, resourceType, tenantID, []string{appID, appID2}, "id", 10, "", repo.OrderByParams{repo.NewAscOrderBy("id")}, &dest)
   144  
   145  		require.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query")
   146  	})
   147  }
   148  
   149  func TestUnionListWithEmbeddedTenant(t *testing.T) {
   150  	peterID := "peterID"
   151  	homerID := "homerID"
   152  	peter := User{FirstName: "Peter", LastName: "Griffin", Age: 40, Tenant: tenantID, ID: peterID}
   153  	peterRow := []driver.Value{peterID, tenantID, "Peter", "Griffin", 40}
   154  	homer := User{FirstName: "Homer", LastName: "Simpson", Age: 55, Tenant: tenantID, ID: homerID}
   155  	homerRow := []driver.Value{homerID, tenantID, "Homer", "Simpson", 55}
   156  
   157  	sut := repo.NewUnionListerWithEmbeddedTenant(userTableName, "tenant_id", []string{"id", "tenant_id", "first_name", "last_name", "age"})
   158  
   159  	t.Run("success", func(t *testing.T) {
   160  		db, mock := testdb.MockDatabase(t)
   161  		defer mock.AssertExpectations(t)
   162  
   163  		rows := sqlmock.NewRows([]string{"id", "tenant_id", "first_name", "last_name", "age"}).
   164  			AddRow(peterRow...).
   165  			AddRow(homerRow...)
   166  
   167  		mock.ExpectQuery(regexp.QuoteMeta("(SELECT id, tenant_id, first_name, last_name, age FROM users WHERE tenant_id = $1 AND id = $2 ORDER BY id ASC LIMIT $3 OFFSET $4) UNION (SELECT id, tenant_id, first_name, last_name, age FROM users WHERE tenant_id = $5 AND id = $6 ORDER BY id ASC LIMIT $7 OFFSET $8)")).
   168  			WithArgs(tenantID, peterID, 10, 0, tenantID, homerID, 10, 0).WillReturnRows(rows)
   169  		mock.ExpectQuery(regexp.QuoteMeta("SELECT id AS id, COUNT(*) AS total_count FROM users WHERE tenant_id = $1 GROUP BY id ORDER BY id ASC")).
   170  			WithArgs(tenantID).WillReturnRows(sqlmock.NewRows([]string{"id", "total_count"}).AddRow(peterID, 1).AddRow(homerID, 1))
   171  		ctx := persistence.SaveToContext(context.TODO(), db)
   172  		var dest UserCollection
   173  
   174  		counts, err := sut.List(ctx, UserType, tenantID, []string{peterID, homerID}, "id", 10, "", repo.OrderByParams{repo.NewAscOrderBy("id")}, &dest)
   175  		require.NoError(t, err)
   176  		assert.Equal(t, 2, len(counts))
   177  		assert.Equal(t, 1, counts[peterID])
   178  		assert.Equal(t, 1, counts[homerID])
   179  		assert.Len(t, dest, 2)
   180  		assert.Equal(t, peter, dest[0])
   181  		assert.Equal(t, homer, dest[1])
   182  	})
   183  
   184  	t.Run("success with additional conditions", func(t *testing.T) {
   185  		db, mock := testdb.MockDatabase(t)
   186  		defer mock.AssertExpectations(t)
   187  
   188  		rows := sqlmock.NewRows([]string{"id", "tenant_id", "first_name", "last_name", "age"}).
   189  			AddRow(peterRow...)
   190  
   191  		mock.ExpectQuery(regexp.QuoteMeta("(SELECT id, tenant_id, first_name, last_name, age FROM users WHERE tenant_id = $1 AND first_name = $2 AND id = $3 ORDER BY id ASC LIMIT $4 OFFSET $5) UNION (SELECT id, tenant_id, first_name, last_name, age FROM users WHERE tenant_id = $6 AND first_name = $7 AND id = $8 ORDER BY id ASC LIMIT $9 OFFSET $10)")).
   192  			WithArgs(tenantID, "Peter", peterID, 10, 0, tenantID, "Peter", homerID, 10, 0).WillReturnRows(rows)
   193  		mock.ExpectQuery(regexp.QuoteMeta("SELECT id AS id, COUNT(*) AS total_count FROM users WHERE tenant_id = $1 AND first_name = $2 GROUP BY id ORDER BY id ASC")).
   194  			WithArgs(tenantID, "Peter").WillReturnRows(sqlmock.NewRows([]string{"id", "total_count"}).AddRow(peterID, 1))
   195  		ctx := persistence.SaveToContext(context.TODO(), db)
   196  		var dest UserCollection
   197  
   198  		counts, err := sut.List(ctx, UserType, tenantID, []string{peterID, homerID}, "id", 10, "", repo.OrderByParams{repo.NewAscOrderBy("id")}, &dest, repo.NewEqualCondition("first_name", "Peter"))
   199  		require.NoError(t, err)
   200  		assert.Equal(t, 1, len(counts))
   201  		assert.Equal(t, 1, counts[peterID])
   202  		assert.Len(t, dest, 1)
   203  		assert.Equal(t, peter, dest[0])
   204  	})
   205  
   206  	t.Run("error when union list fails", func(t *testing.T) {
   207  		db, mock := testdb.MockDatabase(t)
   208  		ctx := persistence.SaveToContext(context.TODO(), db)
   209  		defer mock.AssertExpectations(t)
   210  
   211  		mock.ExpectQuery(regexp.QuoteMeta("(SELECT id, tenant_id, first_name, last_name, age FROM users WHERE tenant_id = $1 AND id = $2 ORDER BY id ASC LIMIT $3 OFFSET $4) UNION (SELECT id, tenant_id, first_name, last_name, age FROM users WHERE tenant_id = $5 AND id = $6 ORDER BY id ASC LIMIT $7 OFFSET $8)")).
   212  			WithArgs(tenantID, peterID, 10, 0, tenantID, homerID, 10, 0).WillReturnError(someError())
   213  		var dest UserCollection
   214  
   215  		counts, err := sut.List(ctx, UserType, tenantID, []string{peterID, homerID}, "id", 10, "", repo.OrderByParams{repo.NewAscOrderBy("id")}, &dest)
   216  		require.Error(t, err)
   217  		require.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query")
   218  		require.Nil(t, counts)
   219  	})
   220  
   221  	t.Run("error when count fails", func(t *testing.T) {
   222  		db, mock := testdb.MockDatabase(t)
   223  		ctx := persistence.SaveToContext(context.TODO(), db)
   224  		defer mock.AssertExpectations(t)
   225  
   226  		rows := sqlmock.NewRows([]string{"id", "tenant_id", "first_name", "last_name", "age"}).
   227  			AddRow(peterRow...).
   228  			AddRow(homerRow...)
   229  
   230  		mock.ExpectQuery(regexp.QuoteMeta("(SELECT id, tenant_id, first_name, last_name, age FROM users WHERE tenant_id = $1 AND id = $2 ORDER BY id ASC LIMIT $3 OFFSET $4) UNION (SELECT id, tenant_id, first_name, last_name, age FROM users WHERE tenant_id = $5 AND id = $6 ORDER BY id ASC LIMIT $7 OFFSET $8)")).
   231  			WithArgs(tenantID, peterID, 10, 0, tenantID, homerID, 10, 0).WillReturnRows(rows)
   232  		mock.ExpectQuery(regexp.QuoteMeta("SELECT id AS id, COUNT(*) AS total_count FROM users WHERE tenant_id = $1 GROUP BY id ORDER BY id ASC")).
   233  			WithArgs(tenantID).WillReturnError(someError())
   234  		var dest UserCollection
   235  
   236  		counts, err := sut.List(ctx, UserType, tenantID, []string{peterID, homerID}, "id", 10, "", repo.OrderByParams{repo.NewAscOrderBy("id")}, &dest)
   237  		require.Error(t, err)
   238  		require.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query")
   239  		require.Nil(t, counts)
   240  	})
   241  
   242  	t.Run("returns error if missing persistence context", func(t *testing.T) {
   243  		ctx := context.TODO()
   244  		_, err := sut.List(ctx, UserType, tenantID, []string{peterID, homerID}, "id", 10, "", repo.OrderByParams{repo.NewAscOrderBy("id")}, nil)
   245  		require.EqualError(t, err, apperrors.NewInternalError("unable to fetch database from context").Error())
   246  	})
   247  
   248  	t.Run("returns error if wrong cursor", func(t *testing.T) {
   249  		ctx := persistence.SaveToContext(context.TODO(), &sqlx.Tx{})
   250  		_, err := sut.List(ctx, UserType, tenantID, []string{peterID, homerID}, "id", 10, "zzz", repo.OrderByParams{repo.NewAscOrderBy("id")}, nil)
   251  		require.EqualError(t, err, "while decoding page cursor: cursor is not correct: illegal base64 data at input byte 0")
   252  	})
   253  
   254  	t.Run("returns error on db operation", func(t *testing.T) {
   255  		db, mock := testdb.MockDatabase(t)
   256  		defer mock.AssertExpectations(t)
   257  
   258  		mock.ExpectQuery(`SELECT .*`).WillReturnError(someError())
   259  		ctx := persistence.SaveToContext(context.TODO(), db)
   260  		var dest UserCollection
   261  
   262  		_, err := sut.List(ctx, UserType, tenantID, []string{peterID, homerID}, "id", 10, "", repo.OrderByParams{repo.NewAscOrderBy("id")}, &dest)
   263  
   264  		require.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query")
   265  	})
   266  }
   267  
   268  func TestUnionListGlobal(t *testing.T) {
   269  	peterID := "peterID"
   270  	homerID := "homerID"
   271  	peter := User{FirstName: "Peter", LastName: "Griffin", Age: 40, Tenant: tenantID, ID: peterID}
   272  	peterRow := []driver.Value{peterID, tenantID, "Peter", "Griffin", 40}
   273  	homer := User{FirstName: "Homer", LastName: "Simpson", Age: 55, Tenant: tenantID, ID: homerID}
   274  	homerRow := []driver.Value{homerID, tenantID, "Homer", "Simpson", 55}
   275  
   276  	sut := repo.NewUnionListerGlobal(UserType, userTableName, []string{"id", "tenant_id", "first_name", "last_name", "age"})
   277  
   278  	t.Run("success", func(t *testing.T) {
   279  		db, mock := testdb.MockDatabase(t)
   280  		defer mock.AssertExpectations(t)
   281  
   282  		rows := sqlmock.NewRows([]string{"id", "tenant_id", "first_name", "last_name", "age"}).
   283  			AddRow(peterRow...).
   284  			AddRow(homerRow...)
   285  
   286  		mock.ExpectQuery(regexp.QuoteMeta("(SELECT id, tenant_id, first_name, last_name, age FROM users WHERE id = $1 ORDER BY id ASC LIMIT $2 OFFSET $3) UNION (SELECT id, tenant_id, first_name, last_name, age FROM users WHERE id = $4 ORDER BY id ASC LIMIT $5 OFFSET $6)")).
   287  			WithArgs(peterID, 10, 0, homerID, 10, 0).WillReturnRows(rows)
   288  		mock.ExpectQuery(regexp.QuoteMeta("SELECT id AS id, COUNT(*) AS total_count FROM users GROUP BY id ORDER BY id ASC")).
   289  			WillReturnRows(sqlmock.NewRows([]string{"id", "total_count"}).AddRow(peterID, 1).AddRow(homerID, 1))
   290  		ctx := persistence.SaveToContext(context.TODO(), db)
   291  		var dest UserCollection
   292  
   293  		counts, err := sut.ListGlobal(ctx, []string{peterID, homerID}, "id", 10, "", repo.OrderByParams{repo.NewAscOrderBy("id")}, &dest)
   294  		require.NoError(t, err)
   295  		assert.Equal(t, 2, len(counts))
   296  		assert.Equal(t, 1, counts[peterID])
   297  		assert.Equal(t, 1, counts[homerID])
   298  		assert.Len(t, dest, 2)
   299  		assert.Equal(t, peter, dest[0])
   300  		assert.Equal(t, homer, dest[1])
   301  	})
   302  
   303  	t.Run("success with additional conditions", func(t *testing.T) {
   304  		db, mock := testdb.MockDatabase(t)
   305  		defer mock.AssertExpectations(t)
   306  
   307  		rows := sqlmock.NewRows([]string{"id", "tenant_id", "first_name", "last_name", "age"}).
   308  			AddRow(peterRow...)
   309  
   310  		mock.ExpectQuery(regexp.QuoteMeta("(SELECT id, tenant_id, first_name, last_name, age FROM users WHERE first_name = $1 AND id = $2 ORDER BY id ASC LIMIT $3 OFFSET $4) UNION (SELECT id, tenant_id, first_name, last_name, age FROM users WHERE first_name = $5 AND id = $6 ORDER BY id ASC LIMIT $7 OFFSET $8)")).
   311  			WithArgs("Peter", peterID, 10, 0, "Peter", homerID, 10, 0).WillReturnRows(rows)
   312  		mock.ExpectQuery(regexp.QuoteMeta("SELECT id AS id, COUNT(*) AS total_count FROM users WHERE first_name = $1 GROUP BY id ORDER BY id ASC")).
   313  			WithArgs("Peter").WillReturnRows(sqlmock.NewRows([]string{"id", "total_count"}).AddRow(peterID, 1))
   314  		ctx := persistence.SaveToContext(context.TODO(), db)
   315  		var dest UserCollection
   316  
   317  		counts, err := sut.ListGlobal(ctx, []string{peterID, homerID}, "id", 10, "", repo.OrderByParams{repo.NewAscOrderBy("id")}, &dest, repo.NewEqualCondition("first_name", "Peter"))
   318  		require.NoError(t, err)
   319  		assert.Equal(t, 1, len(counts))
   320  		assert.Equal(t, 1, counts[peterID])
   321  		assert.Len(t, dest, 1)
   322  		assert.Equal(t, peter, dest[0])
   323  	})
   324  
   325  	t.Run("error when union list fails", func(t *testing.T) {
   326  		db, mock := testdb.MockDatabase(t)
   327  		ctx := persistence.SaveToContext(context.TODO(), db)
   328  		defer mock.AssertExpectations(t)
   329  
   330  		mock.ExpectQuery(regexp.QuoteMeta("(SELECT id, tenant_id, first_name, last_name, age FROM users WHERE id = $1 ORDER BY id ASC LIMIT $2 OFFSET $3) UNION (SELECT id, tenant_id, first_name, last_name, age FROM users WHERE id = $4 ORDER BY id ASC LIMIT $5 OFFSET $6)")).
   331  			WithArgs(peterID, 10, 0, homerID, 10, 0).WillReturnError(someError())
   332  		var dest UserCollection
   333  
   334  		counts, err := sut.ListGlobal(ctx, []string{peterID, homerID}, "id", 10, "", repo.OrderByParams{repo.NewAscOrderBy("id")}, &dest)
   335  		require.Error(t, err)
   336  		require.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query")
   337  		require.Nil(t, counts)
   338  	})
   339  
   340  	t.Run("error when count fails", func(t *testing.T) {
   341  		db, mock := testdb.MockDatabase(t)
   342  		defer mock.AssertExpectations(t)
   343  
   344  		rows := sqlmock.NewRows([]string{"id", "tenant_id", "first_name", "last_name", "age"}).
   345  			AddRow(peterRow...).
   346  			AddRow(homerRow...)
   347  
   348  		mock.ExpectQuery(regexp.QuoteMeta("(SELECT id, tenant_id, first_name, last_name, age FROM users WHERE id = $1 ORDER BY id ASC LIMIT $2 OFFSET $3) UNION (SELECT id, tenant_id, first_name, last_name, age FROM users WHERE id = $4 ORDER BY id ASC LIMIT $5 OFFSET $6)")).
   349  			WithArgs(peterID, 10, 0, homerID, 10, 0).WillReturnRows(rows)
   350  		mock.ExpectQuery(regexp.QuoteMeta("SELECT id AS id, COUNT(*) AS total_count FROM users GROUP BY id ORDER BY id ASC")).WillReturnError(someError())
   351  		ctx := persistence.SaveToContext(context.TODO(), db)
   352  		var dest UserCollection
   353  
   354  		counts, err := sut.ListGlobal(ctx, []string{peterID, homerID}, "id", 10, "", repo.OrderByParams{repo.NewAscOrderBy("id")}, &dest)
   355  		require.Error(t, err)
   356  		require.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query")
   357  		require.Nil(t, counts)
   358  	})
   359  
   360  	t.Run("returns error if missing persistence context", func(t *testing.T) {
   361  		ctx := context.TODO()
   362  		_, err := sut.ListGlobal(ctx, []string{peterID, homerID}, "id", 10, "", repo.OrderByParams{repo.NewAscOrderBy("id")}, nil)
   363  		require.EqualError(t, err, apperrors.NewInternalError("unable to fetch database from context").Error())
   364  	})
   365  
   366  	t.Run("returns error if wrong cursor", func(t *testing.T) {
   367  		ctx := persistence.SaveToContext(context.TODO(), &sqlx.Tx{})
   368  		_, err := sut.ListGlobal(ctx, []string{peterID, homerID}, "id", 10, "zzz", repo.OrderByParams{repo.NewAscOrderBy("id")}, nil)
   369  		require.EqualError(t, err, "while decoding page cursor: cursor is not correct: illegal base64 data at input byte 0")
   370  	})
   371  
   372  	t.Run("returns error on db operation", func(t *testing.T) {
   373  		db, mock := testdb.MockDatabase(t)
   374  		defer mock.AssertExpectations(t)
   375  
   376  		mock.ExpectQuery(`SELECT .*`).WillReturnError(someError())
   377  		ctx := persistence.SaveToContext(context.TODO(), db)
   378  		var dest UserCollection
   379  
   380  		_, err := sut.ListGlobal(ctx, []string{peterID, homerID}, "id", 10, "", repo.OrderByParams{repo.NewAscOrderBy("id")}, &dest)
   381  
   382  		require.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query")
   383  	})
   384  }