From da9a22271d4b6aa49201f8f3d138cec8ad263b28 Mon Sep 17 00:00:00 2001 From: Danny Date: Fri, 29 Jul 2022 15:08:36 -0400 Subject: [PATCH] Mock Connector expansion (#437) Mock Connector data collection is a Messageable item and has been changed to be utilized in other portions of the corso repo. --- src/internal/common/time.go | 8 +++++ .../connector/graph_connector_test.go | 22 ++++--------- .../mockconnector/mock_data_collection.go | 17 ++++++++-- .../mock_data_collection_test.go | 32 ++++++++++++++++--- src/internal/kopia/wrapper_test.go | 24 +++++++------- 5 files changed, 67 insertions(+), 36 deletions(-) diff --git a/src/internal/common/time.go b/src/internal/common/time.go index 5e4203ea6..0c14de171 100644 --- a/src/internal/common/time.go +++ b/src/internal/common/time.go @@ -11,6 +11,14 @@ func FormatTime(t time.Time) string { return t.UTC().Format(time.RFC3339Nano) } +// FormatSimpleDateTime produces standard format for +// GraphConnector. Format used on CI testing and default folder +// creation during the restore process +func FormatSimpleDateTime(t time.Time) string { + timeFolderFormat := "02-Jan-2006_15:04:05" + return t.UTC().Format(timeFolderFormat) +} + // ParseTime makes a best attempt to produce a time value from // the provided string. Always returns a UTC timezone value. func ParseTime(s string) (time.Time, error) { diff --git a/src/internal/connector/graph_connector_test.go b/src/internal/connector/graph_connector_test.go index 1886d2369..e32e09c2b 100644 --- a/src/internal/connector/graph_connector_test.go +++ b/src/internal/connector/graph_connector_test.go @@ -9,11 +9,10 @@ import ( "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" - "github.com/alcionai/corso/internal/connector/exchange" + "github.com/alcionai/corso/internal/connector/mockconnector" "github.com/alcionai/corso/internal/connector/support" "github.com/alcionai/corso/internal/data" ctesting "github.com/alcionai/corso/internal/testing" - "github.com/alcionai/corso/pkg/backup/details" "github.com/alcionai/corso/pkg/selectors" ) @@ -73,25 +72,16 @@ func (suite *GraphConnectorIntegrationSuite) TestGraphConnector_ExchangeDataColl suite.Greater(len(exchangeData.FullPath()), 2) } -//TODO add mockdata for this test... Will not pass as is +//TestGraphConnector_restoreMessages uses mock data to ensure GraphConnector +// is able to restore a messageable item to a Mailbox. func (suite *GraphConnectorIntegrationSuite) TestGraphConnector_restoreMessages() { user := "TEST_GRAPH_USER" // user.GetId() - file := "TEST_GRAPH_FILE" // Test file should be sent or received by the user - evs, err := ctesting.GetRequiredEnvVars(user, file) + evs, err := ctesting.GetRequiredEnvVars(user) if err != nil { suite.T().Skipf("Environment not configured: %v\n", err) } - bytes, err := ctesting.LoadAFile(evs[file]) // TEST_GRAPH_FILE should have a single Message && not present in target inbox - if err != nil { - suite.T().Skipf("Support file not accessible: %v\n", err) - } - - ds := exchange.NewStream("test", bytes, details.ExchangeInfo{}) - edc := exchange.NewCollection("tenant", []string{"tenantId", evs[user], mailCategory, "Inbox"}) - - edc.PopulateCollection(&ds) - //edc.FinishPopulation() - err = suite.connector.RestoreMessages(context.Background(), []data.Collection{&edc}) + mdc := mockconnector.NewMockExchangeCollection([]string{"tenant", evs[user], mailCategory, "Inbox"}, 1) + err = suite.connector.RestoreMessages(context.Background(), []data.Collection{mdc}) assert.NoError(suite.T(), err) } diff --git a/src/internal/connector/mockconnector/mock_data_collection.go b/src/internal/connector/mockconnector/mock_data_collection.go index a2b3e9833..2c46d80bc 100644 --- a/src/internal/connector/mockconnector/mock_data_collection.go +++ b/src/internal/connector/mockconnector/mock_data_collection.go @@ -7,6 +7,7 @@ import ( "github.com/google/uuid" + "github.com/alcionai/corso/internal/common" "github.com/alcionai/corso/internal/data" "github.com/alcionai/corso/pkg/backup/details" ) @@ -26,8 +27,8 @@ var ( ) // NewMockExchangeDataCollection creates an data collection that will return the specified number of -// mock messages when iterated -func NewMockExchangeDataCollection(pathRepresentation []string, numMessagesToReturn int) *MockExchangeDataCollection { +// mock messages when iterated. Exchange type mail +func NewMockExchangeCollection(pathRepresentation []string, numMessagesToReturn int) *MockExchangeDataCollection { c := &MockExchangeDataCollection{ fullPath: pathRepresentation, messageCount: numMessagesToReturn, @@ -37,7 +38,7 @@ func NewMockExchangeDataCollection(pathRepresentation []string, numMessagesToRet for i := 0; i < c.messageCount; i++ { // We can plug in whatever data we want here (can be an io.Reader to a test data file if needed) - c.Data = append(c.Data, []byte("test message")) + c.Data = append(c.Data, getMockMessageBytes("From: NewMockExchangeCollection")) c.Names = append(c.Names, uuid.NewString()) } return c @@ -82,3 +83,13 @@ func (med *MockExchangeData) ToReader() io.ReadCloser { func (med *MockExchangeData) Info() details.ItemInfo { return details.ItemInfo{Exchange: &details.ExchangeInfo{Sender: "foo@bar.com", Subject: "Hello world!", Received: time.Now()}} } + +// 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 { + + 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\": \"\",\n \"subject\": \"" + + subject + " " + common.FormatSimpleDateTime(time.Now()) + " 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\": \"

I've been going through with the changing of messages. It shouldn't have the same calls, right? Call Me?

 

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. Let’s consider a Mailbox

\"\n },\n \"sender\": {\n \"emailAddress\": {\n \"name\": \"Lidia Holloway\",\n \"address\": \"lidiah@8qzvrj.onmicrosoft.com\"\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" + + return []byte(message) +} diff --git a/src/internal/connector/mockconnector/mock_data_collection_test.go b/src/internal/connector/mockconnector/mock_data_collection_test.go index 3700dda0a..95243936d 100644 --- a/src/internal/connector/mockconnector/mock_data_collection_test.go +++ b/src/internal/connector/mockconnector/mock_data_collection_test.go @@ -1,25 +1,28 @@ package mockconnector_test import ( + "bytes" "io/ioutil" "testing" + "github.com/microsoftgraph/msgraph-sdk-go/models" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" "github.com/alcionai/corso/internal/connector/mockconnector" + "github.com/alcionai/corso/internal/connector/support" ) -type MockExchangeDataCollectionSuite struct { +type MockExchangeCollectionSuite struct { suite.Suite } -func TestMockExchangeDataCollectionSuite(t *testing.T) { - suite.Run(t, new(MockExchangeDataCollectionSuite)) +func TestMockExchangeCollectionSuite(t *testing.T) { + suite.Run(t, new(MockExchangeCollectionSuite)) } -func (suite *MockExchangeDataCollectionSuite) TestMockExchangeDataCollection() { - mdc := mockconnector.NewMockExchangeDataCollection([]string{"foo", "bar"}, 2) +func (suite *MockExchangeCollectionSuite) TestMockExchangeCollection() { + mdc := mockconnector.NewMockExchangeCollection([]string{"foo", "bar"}, 2) messagesRead := 0 @@ -30,3 +33,22 @@ func (suite *MockExchangeDataCollectionSuite) TestMockExchangeDataCollection() { } assert.Equal(suite.T(), 2, messagesRead) } + +// NewExchangeCollectionMail_Hydration tests that mock exchange mail data collection can be used for restoration +// functions by verifying no failures on (de)serializing steps using kiota serialization library +func (suite *MockExchangeCollectionSuite) TestMockExchangeCollection_NewExchangeCollectionMail_Hydration() { + t := suite.T() + mdc := mockconnector.NewMockExchangeCollection([]string{"foo", "bar"}, 3) + var ( + byteArray []byte + ) + buf := &bytes.Buffer{} + for stream := range mdc.Items() { + _, err := buf.ReadFrom(stream.ToReader()) + assert.NoError(t, err) + byteArray = buf.Bytes() + something, err := support.CreateFromBytes(byteArray, models.CreateMessageFromDiscriminatorValue) + assert.NoError(t, err) + assert.NotNil(t, something) + } +} diff --git a/src/internal/kopia/wrapper_test.go b/src/internal/kopia/wrapper_test.go index 3571ef4e4..5867a6be7 100644 --- a/src/internal/kopia/wrapper_test.go +++ b/src/internal/kopia/wrapper_test.go @@ -120,11 +120,11 @@ func (suite *KopiaUnitSuite) TestBuildDirectoryTree() { details := &details.Details{} collections := []data.Collection{ - mockconnector.NewMockExchangeDataCollection( + mockconnector.NewMockExchangeCollection( []string{tenant, user1, emails}, expectedFileCount[user1], ), - mockconnector.NewMockExchangeDataCollection( + mockconnector.NewMockExchangeCollection( []string{tenant, user2, emails}, expectedFileCount[user2], ), @@ -182,7 +182,7 @@ func (suite *KopiaUnitSuite) TestBuildDirectoryTree_NoAncestorDirs() { details := &details.Details{} collections := []data.Collection{ - mockconnector.NewMockExchangeDataCollection( + mockconnector.NewMockExchangeCollection( []string{emails}, expectedFileCount, ), @@ -215,11 +215,11 @@ func (suite *KopiaUnitSuite) TestBuildDirectoryTree_Fails() { // - emails // - 42 separate files []data.Collection{ - mockconnector.NewMockExchangeDataCollection( + mockconnector.NewMockExchangeCollection( []string{"user1", "emails"}, 5, ), - mockconnector.NewMockExchangeDataCollection( + mockconnector.NewMockExchangeCollection( []string{"user2", "emails"}, 42, ), @@ -228,7 +228,7 @@ func (suite *KopiaUnitSuite) TestBuildDirectoryTree_Fails() { { "NoCollectionPath", []data.Collection{ - mockconnector.NewMockExchangeDataCollection( + mockconnector.NewMockExchangeCollection( nil, 5, ), @@ -243,11 +243,11 @@ func (suite *KopiaUnitSuite) TestBuildDirectoryTree_Fails() { // - 5 separate files // - 42 separate files []data.Collection{ - mockconnector.NewMockExchangeDataCollection( + mockconnector.NewMockExchangeCollection( []string{"a-tenant", "user1", "emails"}, 5, ), - mockconnector.NewMockExchangeDataCollection( + mockconnector.NewMockExchangeCollection( []string{"a-tenant", "user1"}, 42, ), @@ -402,11 +402,11 @@ func (suite *KopiaIntegrationSuite) TestBackupCollections() { t := suite.T() collections := []data.Collection{ - mockconnector.NewMockExchangeDataCollection( + mockconnector.NewMockExchangeCollection( []string{"a-tenant", "user1", "emails"}, 5, ), - mockconnector.NewMockExchangeDataCollection( + mockconnector.NewMockExchangeCollection( []string{"a-tenant", "user2", "emails"}, 42, ), @@ -683,8 +683,8 @@ func (suite *KopiaSimpleRepoIntegrationSuite) TestRestoreMultipleItems() { tid := uuid.NewString() p1 := []string{tid, "uid", "emails", "fid"} p2 := []string{tid, "uid2", "emails", "fid"} - dc1 := mockconnector.NewMockExchangeDataCollection(p1, 1) - dc2 := mockconnector.NewMockExchangeDataCollection(p2, 1) + dc1 := mockconnector.NewMockExchangeCollection(p1, 1) + dc2 := mockconnector.NewMockExchangeCollection(p2, 1) fp1 := append(p1, dc1.Names[0]) fp2 := append(p2, dc2.Names[0])