Simplify test utilities (#532)

This commit is contained in:
Vaibhav Kamra 2022-08-11 19:49:22 -07:00 committed by GitHub
parent 79e7be71bf
commit 88bcd053e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 122 additions and 161 deletions

View File

@ -42,8 +42,7 @@ func (suite *S3IntegrationSuite) TestInitS3Cmd() {
ctx := tester.NewContext()
t := suite.T()
st, err := tester.NewPrefixedS3Storage(t)
require.NoError(t, err)
st := tester.NewPrefixedS3Storage(t)
cfg, err := st.S3Config()
require.NoError(t, err)
@ -66,8 +65,7 @@ func (suite *S3IntegrationSuite) TestInitS3Cmd_missingBucket() {
ctx := tester.NewContext()
t := suite.T()
st, err := tester.NewPrefixedS3Storage(t)
require.NoError(t, err)
st := tester.NewPrefixedS3Storage(t)
cfg, err := st.S3Config()
require.NoError(t, err)
@ -89,8 +87,7 @@ func (suite *S3IntegrationSuite) TestConnectS3Cmd() {
ctx := tester.NewContext()
t := suite.T()
st, err := tester.NewPrefixedS3Storage(t)
require.NoError(t, err)
st := tester.NewPrefixedS3Storage(t)
cfg, err := st.S3Config()
require.NoError(t, err)
@ -123,8 +120,7 @@ func (suite *S3IntegrationSuite) TestConnectS3Cmd_BadBucket() {
ctx := tester.NewContext()
t := suite.T()
st, err := tester.NewPrefixedS3Storage(t)
require.NoError(t, err)
st := tester.NewPrefixedS3Storage(t)
cfg, err := st.S3Config()
require.NoError(t, err)
@ -147,8 +143,7 @@ func (suite *S3IntegrationSuite) TestConnectS3Cmd_BadPrefix() {
ctx := tester.NewContext()
t := suite.T()
st, err := tester.NewPrefixedS3Storage(t)
require.NoError(t, err)
st := tester.NewPrefixedS3Storage(t)
cfg, err := st.S3Config()
require.NoError(t, err)

View File

@ -96,8 +96,7 @@ func (suite *ExchangeServiceSuite) TestExchangeService_optionsForFolders() {
// NOTE the requirements are in PR 475
func (suite *ExchangeServiceSuite) TestExchangeService_SetupExchangeCollection() {
userID, err := tester.M365UserID()
require.NoError(suite.T(), err)
userID := tester.M365UserID(suite.T())
sel := selectors.NewExchangeBackup()
sel.Include(sel.Users([]string{userID}))
eb, err := sel.ToExchangeBackup()

View File

@ -45,8 +45,7 @@ func (suite *GraphConnectorIntegrationSuite) SetupSuite() {
_, err := tester.GetRequiredEnvVars(tester.M365AcctCredEnvs...)
require.NoError(suite.T(), err)
a, err := tester.NewM365Account()
require.NoError(suite.T(), err)
a := tester.NewM365Account(suite.T())
suite.connector, err = NewGraphConnector(a)
suite.NoError(err)
@ -65,8 +64,7 @@ func (suite *GraphConnectorIntegrationSuite) TestGraphConnector_setTenantUsers()
}
func (suite *GraphConnectorIntegrationSuite) TestGraphConnector_ExchangeDataCollection() {
userID, err := tester.M365UserID()
require.NoError(suite.T(), err)
userID := tester.M365UserID(suite.T())
sel := selectors.NewExchangeBackup()
sel.Include(sel.Users([]string{userID}))
collectionList, err := suite.connector.ExchangeDataCollection(context.Background(), sel.Selector)
@ -90,8 +88,7 @@ func (suite *GraphConnectorIntegrationSuite) TestGraphConnector_ExchangeDataColl
func (suite *GraphConnectorIntegrationSuite) TestGraphConnector_MailRegressionTest() {
t := suite.T()
user, err := tester.M365UserID()
require.NoError(t, err)
user := tester.M365UserID(suite.T())
sel := selectors.NewExchangeBackup()
sel.Include(sel.Users([]string{user}))
eb, err := sel.ToExchangeBackup()
@ -128,8 +125,7 @@ func (suite *GraphConnectorIntegrationSuite) TestGraphConnector_MailRegressionTe
// TestGraphConnector_TestContactSequence verifies retrieval sequence
func (suite *GraphConnectorIntegrationSuite) TestGraphConnector_TestContactSequence() {
userID, err := tester.M365UserID()
require.NoError(suite.T(), err)
userID := tester.M365UserID(suite.T())
sel := selectors.NewExchangeBackup()
sel.Include(sel.Users([]string{userID}))
eb, err := sel.ToExchangeBackup()
@ -212,8 +208,7 @@ func (suite *GraphConnectorIntegrationSuite) TestGraphConnector_SingleMailFolder
// TestGraphConnector_CreateAndDeleteFolder ensures msgraph application has the ability
// to create and remove folders within the tenant
func (suite *GraphConnectorIntegrationSuite) TestGraphConnector_CreateAndDeleteFolder() {
userID, err := tester.M365UserID()
require.NoError(suite.T(), err)
userID := tester.M365UserID(suite.T())
now := time.Now()
folderName := "TestFolder: " + common.FormatSimpleDateTime(now)
aFolder, err := exchange.CreateMailFolder(&suite.connector.graphService, userID, folderName)
@ -227,8 +222,7 @@ func (suite *GraphConnectorIntegrationSuite) TestGraphConnector_CreateAndDeleteF
// TestGraphConnector_GetMailFolderID verifies the ability to retrieve folder ID of folders
// at the top level of the file tree
func (suite *GraphConnectorIntegrationSuite) TestGraphConnector_GetMailFolderID() {
userID, err := tester.M365UserID()
require.NoError(suite.T(), err)
userID := tester.M365UserID(suite.T())
folderName := "Inbox"
folderID, err := exchange.GetMailFolderID(&suite.connector.graphService, folderName, userID)
assert.NoError(suite.T(), err)

View File

@ -9,7 +9,6 @@ import (
"github.com/alcionai/corso/internal/common"
"github.com/alcionai/corso/internal/data"
"github.com/alcionai/corso/internal/tester"
"github.com/alcionai/corso/pkg/backup/details"
)
@ -88,10 +87,7 @@ func (med *MockExchangeData) Info() details.ItemInfo {
// GetMockMessageBytes returns bytes for Messageable item.
// Contents verified as working with sample data from kiota-serialization-json-go v0.5.5
func GetMockMessageBytes(subject string) []byte {
userID, err := tester.M365UserID()
if err != nil {
userID = "lidiah@8qzvrj.onmicrosoft.com"
}
userID := "foobar@8qzvrj.onmicrosoft.com"
message := "{\n \"@odata.etag\": \"W/\\\"CQAAABYAAAB8wYc0thTTTYl3RpEYIUq+AAAZ0f0I\\\"\",\n \"id\": \"AAMkAGQ1NzViZTdhLTEwMTMtNGJjNi05YWI2LTg4NWRlZDA2Y2UxOABGAAAAAAAPvVwUramXT7jlSGpVU8_7BwB8wYc0thTTTYl3RpEYIUq_AAAAAAEMAAB8wYc0thTTTYl3RpEYIUq_AAAZ3wG3AAA=\",\n \"createdDateTime\": \"2022-04-08T18:08:02Z\",\n \"lastModifiedDateTime\": \"2022-05-17T13:46:55Z\",\n \"changeKey\": \"CQAAABYAAAB8wYc0thTTTYl3RpEYIUq+AAAZ0f0I\",\n \"categories\": [],\n \"receivedDateTime\": \"2022-04-08T18:08:02Z\",\n \"sentDateTime\": \"2022-04-08T18:07:53Z\",\n \"hasAttachments\": false,\n \"internetMessageId\": \"<MWHPR1401MB1952C46D4A46B6398F562B0FA6E99@MWHPR1401MB1952.namprd14.prod.outlook.com>\",\n \"subject\": \"" +
subject + " " + common.FormatNow(common.SimpleDateTimeFormat) + " Different\",\n \"bodyPreview\": \"Who is coming to next week's party? I cannot imagine it is July soon\",\n \"importance\": \"normal\",\n \"parentFolderId\": \"AQMkAGQ1NzViZTdhLTEwMTMtNGJjNi05YWI2LTg4ADVkZWQwNmNlMTgALgAAAw_9XBStqZdPuOVIalVTz7sBAHzBhzS2FNNNiXdGkRghSr4AAAIBDAAAAA==\",\n \"conversationId\": \"AAQkAGQ1NzViZTdhLTEwMTMtNGJjNi05YWI2LTg4NWRlZDA2Y2UxOAAQAI7SSzmEPaRJsY-TWIALn1g=\",\n \"conversationIndex\": \"AQHYS3N3jtJLOYQ9pEmxj9NYgAufWA==\",\n \"isDeliveryReceiptRequested\": null,\n \"isReadReceiptRequested\": false,\n \"isRead\": true,\n \"isDraft\": false,\n \"webLink\": \"https://outlook.office365.com/owa/?ItemID=AAMkAGQ1NzViZTdhLTEwMTMtNGJjNi05YWI2LTg4NWRlZDA2Y2UxOABGAAAAAAAPvVwUramXT7jlSGpVU8%2B7BwB8wYc0thTTTYl3RpEYIUq%2BAAAAAAEMAAB8wYc0thTTTYl3RpEYIUq%2BAAAZ3wG3AAA%3D&exvsurl=1&viewmodel=ReadMessageItem\",\n \"inferenceClassification\": \"focused\",\n \"body\": {\n \"contentType\": \"html\",\n \"content\": \"<html><head><meta http-equiv=\\\"Content-Type\\\" content=\\\"text/html; charset=utf-8\\\"><meta name=\\\"Generator\\\" content=\\\"Microsoft Word 15 (filtered medium)\\\"><style><!--@font-face{font-family:\\\"Cambria Math\\\"}@font-face{font-family:Calibri}p.MsoNormal, li.MsoNormal, div.MsoNormal{margin:0in;font-size:11.0pt;font-family:\\\"Calibri\\\",sans-serif}span.EmailStyle17{font-family:\\\"Calibri\\\",sans-serif;color:windowtext}.MsoChpDefault{font-family:\\\"Calibri\\\",sans-serif}@page WordSection1{margin:1.0in 1.0in 1.0in 1.0in}div.WordSection1{}--></style></head><body lang=\\\"EN-US\\\" link=\\\"#0563C1\\\" vlink=\\\"#954F72\\\" style=\\\"word-wrap:break-word\\\"><div class=\\\"WordSection1\\\"><p class=\\\"MsoNormal\\\">I've been going through with the changing of messages. It shouldn't have the same calls, right? Call Me? </p><p class=\\\"MsoNormal\\\">&nbsp;</p><p class=\\\"MsoNormal\\\">We want to be able to send multiple messages and we want to be able to respond and do other things that make sense for our users. In this case. Lets consider a Mailbox</p></div></body></html>\"\n },\n \"sender\": {\n \"emailAddress\": {\n \"name\": \"Lidia Holloway\",\n \"address\": \"" + userID + "\"\n }\n },\n \"from\": {\n \"emailAddress\": {\n \"name\": \"Lidia Holloway\",\n \"address\": \"lidiah@8qzvrj.onmicrosoft.com\"\n }\n },\n \"toRecipients\": [\n {\n \"emailAddress\": {\n \"name\": \"Dustin Abbot\",\n \"address\": \"dustina@8qzvrj.onmicrosoft.com\"\n }\n }\n ],\n \"ccRecipients\": [],\n \"bccRecipients\": [],\n \"replyTo\": [],\n \"flag\": {\n \"flagStatus\": \"notFlagged\"\n }\n}\n"

View File

@ -13,13 +13,10 @@ import (
//revive:disable:context-as-argument
func openKopiaRepo(t *testing.T, ctx context.Context) (*conn, error) {
storage, err := tester.NewPrefixedS3Storage(t)
if err != nil {
return nil, err
}
storage := tester.NewPrefixedS3Storage(t)
k := NewConn(storage)
if err = k.Initialize(ctx); err != nil {
if err := k.Initialize(ctx); err != nil {
return nil, err
}

View File

@ -94,8 +94,7 @@ func (suite *BackupOpIntegrationSuite) SetupSuite() {
func (suite *BackupOpIntegrationSuite) TestNewBackupOperation() {
kw := &kopia.Wrapper{}
sw := &store.Wrapper{}
acct, err := tester.NewM365Account()
require.NoError(suite.T(), err)
acct := tester.NewM365Account(suite.T())
table := []struct {
name string
@ -128,14 +127,11 @@ func (suite *BackupOpIntegrationSuite) TestBackup_Run() {
t := suite.T()
ctx := context.Background()
m365UserID, err := tester.M365UserID()
require.NoError(suite.T(), err)
acct, err := tester.NewM365Account()
require.NoError(t, err)
m365UserID := tester.M365UserID(t)
acct := tester.NewM365Account(t)
// need to initialize the repository before we can test connecting to it.
st, err := tester.NewPrefixedS3Storage(t)
require.NoError(t, err)
st := tester.NewPrefixedS3Storage(t)
k := kopia.NewConn(st)
require.NoError(t, k.Initialize(ctx))

View File

@ -14,6 +14,7 @@ import (
"github.com/alcionai/corso/internal/connector/support"
"github.com/alcionai/corso/internal/data"
"github.com/alcionai/corso/internal/kopia"
"github.com/alcionai/corso/internal/model"
"github.com/alcionai/corso/internal/tester"
"github.com/alcionai/corso/pkg/account"
"github.com/alcionai/corso/pkg/control"
@ -74,6 +75,13 @@ func (suite *RestoreOpSuite) TestRestoreOperation_PersistResults() {
type RestoreOpIntegrationSuite struct {
suite.Suite
backupID model.StableID
numItems int
kopiaCloser func(ctx context.Context)
kw *kopia.Wrapper
sw *store.Wrapper
ms *kopia.ModelStore
}
func TestRestoreOpIntegrationSuite(t *testing.T) {
@ -89,13 +97,68 @@ func TestRestoreOpIntegrationSuite(t *testing.T) {
func (suite *RestoreOpIntegrationSuite) SetupSuite() {
_, err := tester.GetRequiredEnvVars(tester.M365AcctCredEnvs...)
require.NoError(suite.T(), err)
t := suite.T()
ctx := context.Background()
m365UserID := tester.M365UserID(t)
acct := tester.NewM365Account(t)
// need to initialize the repository before we can test connecting to it.
st := tester.NewPrefixedS3Storage(t)
k := kopia.NewConn(st)
require.NoError(t, k.Initialize(ctx))
suite.kopiaCloser = func(ctx context.Context) {
k.Close(ctx)
}
kw, err := kopia.NewWrapper(k)
require.NoError(t, err)
suite.kw = kw
ms, err := kopia.NewModelStore(k)
require.NoError(t, err)
suite.ms = ms
sw := store.NewKopiaStore(ms)
suite.sw = sw
bsel := selectors.NewExchangeBackup()
bsel.Include(bsel.MailFolders([]string{m365UserID}, []string{"Inbox"}))
bo, err := NewBackupOperation(
ctx,
control.Options{},
kw,
sw,
acct,
bsel.Selector)
require.NoError(t, err)
require.NoError(t, bo.Run(ctx))
require.NotEmpty(t, bo.Results.BackupID)
suite.backupID = bo.Results.BackupID
suite.numItems = bo.Results.ItemsWritten
}
func (suite *RestoreOpIntegrationSuite) TearDownSuite() {
ctx := context.Background()
if suite.ms != nil {
suite.ms.Close(ctx)
}
if suite.kw != nil {
suite.kw.Close(ctx)
}
if suite.kopiaCloser != nil {
suite.kopiaCloser(ctx)
}
}
func (suite *RestoreOpIntegrationSuite) TestNewRestoreOperation() {
kw := &kopia.Wrapper{}
sw := &store.Wrapper{}
acct, err := tester.NewM365Account()
require.NoError(suite.T(), err)
acct := tester.NewM365Account(suite.T())
table := []struct {
name string
@ -129,53 +192,16 @@ func (suite *RestoreOpIntegrationSuite) TestRestore_Run() {
t := suite.T()
ctx := context.Background()
m365UserID, err := tester.M365UserID()
require.NoError(suite.T(), err)
acct, err := tester.NewM365Account()
require.NoError(t, err)
// need to initialize the repository before we can test connecting to it.
st, err := tester.NewPrefixedS3Storage(t)
require.NoError(t, err)
k := kopia.NewConn(st)
require.NoError(t, k.Initialize(ctx))
defer k.Close(ctx)
w, err := kopia.NewWrapper(k)
require.NoError(t, err)
defer w.Close(ctx)
ms, err := kopia.NewModelStore(k)
require.NoError(t, err)
defer ms.Close(ctx)
sw := store.NewKopiaStore(ms)
bsel := selectors.NewExchangeBackup()
bsel.Include(bsel.Users([]string{m365UserID}))
bo, err := NewBackupOperation(
ctx,
control.Options{},
w,
sw,
acct,
bsel.Selector)
require.NoError(t, err)
require.NoError(t, bo.Run(ctx))
require.NotEmpty(t, bo.Results.BackupID)
rsel := selectors.NewExchangeRestore()
rsel.Include(rsel.Users([]string{m365UserID}))
rsel.Include(rsel.Users([]string{tester.M365UserID(t)}))
ro, err := NewRestoreOperation(
ctx,
control.Options{},
w,
sw,
acct,
bo.Results.BackupID,
suite.kw,
suite.sw,
tester.NewM365Account(t),
suite.backupID,
rsel.Selector)
require.NoError(t, err)
@ -186,60 +212,23 @@ func (suite *RestoreOpIntegrationSuite) TestRestore_Run() {
assert.Greater(t, ro.Results.ItemsWritten, 0, "restored items written")
assert.Zero(t, ro.Results.ReadErrors, "errors while reading restore data")
assert.Zero(t, ro.Results.WriteErrors, "errors while writing restore data")
assert.Equal(t, bo.Results.ItemsWritten, ro.Results.ItemsWritten, "backup and restore wrote the same num of items")
assert.Equal(t, suite.numItems, ro.Results.ItemsWritten, "backup and restore wrote the same num of items")
}
func (suite *RestoreOpIntegrationSuite) TestRestore_Run_ErrorNoResults() {
t := suite.T()
ctx := context.Background()
m365UserID, err := tester.M365UserID()
require.NoError(suite.T(), err)
acct, err := tester.NewM365Account()
require.NoError(t, err)
// need to initialize the repository before we can test connecting to it.
st, err := tester.NewPrefixedS3Storage(t)
require.NoError(t, err)
k := kopia.NewConn(st)
require.NoError(t, k.Initialize(ctx))
defer k.Close(ctx)
w, err := kopia.NewWrapper(k)
require.NoError(t, err)
defer w.Close(ctx)
ms, err := kopia.NewModelStore(k)
require.NoError(t, err)
defer ms.Close(ctx)
sw := store.NewKopiaStore(ms)
bsel := selectors.NewExchangeBackup()
bsel.Include(bsel.Users([]string{m365UserID}))
bo, err := NewBackupOperation(
ctx,
control.Options{},
w,
sw,
acct,
bsel.Selector)
require.NoError(t, err)
require.NoError(t, bo.Run(ctx))
require.NotEmpty(t, bo.Results.BackupID)
rsel := selectors.NewExchangeRestore()
rsel.Include(rsel.Users(selectors.None()))
ro, err := NewRestoreOperation(
ctx,
control.Options{},
w,
sw,
acct,
bo.Results.BackupID,
suite.kw,
suite.sw,
tester.NewM365Account(t),
suite.backupID,
rsel.Selector)
require.NoError(t, err)
require.Error(t, ro.Run(ctx), "restoreOp.Run() should have 0 results")

View File

@ -1,7 +1,9 @@
package tester
import (
"github.com/pkg/errors"
"testing"
"github.com/stretchr/testify/require"
"github.com/alcionai/corso/pkg/account"
"github.com/alcionai/corso/pkg/credentials"
@ -14,17 +16,17 @@ var M365AcctCredEnvs = []string{
// NewM365Account returns an account.Account object initialized with environment
// variables used for integration tests that use Graph Connector.
func NewM365Account() (account.Account, error) {
func NewM365Account(t *testing.T) account.Account {
cfg, err := readTestConfig()
if err != nil {
return account.Account{}, errors.Wrap(err, "configuring m365 account from test configuration")
}
require.NoError(t, err, "configuring m365 account from test configuration")
return account.NewAccount(
acc, err := account.NewAccount(
account.ProviderM365,
account.M365Config{
M365: credentials.GetM365(),
TenantID: cfg[TestCfgTenantID],
},
)
require.NoError(t, err, "initializing account")
return acc
}

View File

@ -3,7 +3,7 @@ package tester
import (
"testing"
"github.com/pkg/errors"
"github.com/stretchr/testify/require"
"github.com/alcionai/corso/pkg/credentials"
"github.com/alcionai/corso/pkg/storage"
@ -18,14 +18,12 @@ var AWSStorageCredEnvs = []string{
// NewPrefixedS3Storage returns a storage.Storage object initialized with environment
// variables used for integration tests that use S3. The prefix for the storage
// path will be unique.
func NewPrefixedS3Storage(t *testing.T) (storage.Storage, error) {
func NewPrefixedS3Storage(t *testing.T) storage.Storage {
now := LogTimeOfTest(t)
cfg, err := readTestConfig()
if err != nil {
return storage.Storage{}, errors.Wrap(err, "configuring storage from test file")
}
require.NoError(t, err, "configuring storage from test file")
return storage.NewStorage(
st, err := storage.NewStorage(
storage.ProviderS3,
storage.S3Config{
AWS: credentials.GetAWS(nil),
@ -36,4 +34,6 @@ func NewPrefixedS3Storage(t *testing.T) (storage.Storage, error) {
Corso: credentials.GetCorso(),
},
)
require.NoError(t, err, "creating storage")
return st
}

View File

@ -1,18 +1,17 @@
package tester
import (
"github.com/pkg/errors"
"testing"
"github.com/stretchr/testify/require"
)
// M365UserID returns an userID string representing the m365UserID described
// by either the env var CORSO_M356_TEST_USER_ID, the corso_test.toml config
// file or the default value (in that order of priority). The default is a
// last-attempt fallback that will only work on alcion's testing org.
func M365UserID() (string, error) {
func M365UserID(t *testing.T) string {
cfg, err := readTestConfig()
if err != nil {
return "", errors.Wrap(err, "retrieving m365 user id from test configuration")
}
return cfg[TestCfgUserID], nil
require.NoError(t, err, "retrieving m365 user id from test configuration")
return cfg[TestCfgUserID]
}

View File

@ -114,7 +114,7 @@ func (suite *RepositoryIntegrationSuite) TestInitialize() {
table := []struct {
name string
account account.Account
storage func(*testing.T) (storage.Storage, error)
storage func(*testing.T) storage.Storage
errCheck assert.ErrorAssertionFunc
}{
{
@ -125,8 +125,7 @@ func (suite *RepositoryIntegrationSuite) TestInitialize() {
}
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
st, err := test.storage(t)
assert.NoError(t, err)
st := test.storage(t)
r, err := repository.Initialize(ctx, test.account, st)
if err == nil {
defer func() {
@ -144,10 +143,9 @@ func (suite *RepositoryIntegrationSuite) TestConnect() {
ctx := context.Background()
// need to initialize the repository before we can test connecting to it.
st, err := tester.NewPrefixedS3Storage(t)
require.NoError(t, err)
st := tester.NewPrefixedS3Storage(t)
_, err = repository.Initialize(ctx, account.Account{}, st)
_, err := repository.Initialize(ctx, account.Account{}, st)
require.NoError(t, err)
// now re-connect
@ -159,12 +157,10 @@ func (suite *RepositoryIntegrationSuite) TestNewBackup() {
t := suite.T()
ctx := context.Background()
acct, err := tester.NewM365Account()
require.NoError(t, err)
acct := tester.NewM365Account(t)
// need to initialize the repository before we can test connecting to it.
st, err := tester.NewPrefixedS3Storage(t)
require.NoError(t, err)
st := tester.NewPrefixedS3Storage(t)
r, err := repository.Initialize(ctx, acct, st)
require.NoError(t, err)
@ -178,12 +174,10 @@ func (suite *RepositoryIntegrationSuite) TestNewRestore() {
t := suite.T()
ctx := context.Background()
acct, err := tester.NewM365Account()
require.NoError(t, err)
acct := tester.NewM365Account(t)
// need to initialize the repository before we can test connecting to it.
st, err := tester.NewPrefixedS3Storage(t)
require.NoError(t, err)
st := tester.NewPrefixedS3Storage(t)
r, err := repository.Initialize(ctx, acct, st)
require.NoError(t, err)