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.
This commit is contained in:
Danny 2022-07-29 15:08:36 -04:00 committed by GitHub
parent 7e60ec5073
commit da9a22271d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 67 additions and 36 deletions

View File

@ -11,6 +11,14 @@ func FormatTime(t time.Time) string {
return t.UTC().Format(time.RFC3339Nano) 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 // ParseTime makes a best attempt to produce a time value from
// the provided string. Always returns a UTC timezone value. // the provided string. Always returns a UTC timezone value.
func ParseTime(s string) (time.Time, error) { func ParseTime(s string) (time.Time, error) {

View File

@ -9,11 +9,10 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite" "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/connector/support"
"github.com/alcionai/corso/internal/data" "github.com/alcionai/corso/internal/data"
ctesting "github.com/alcionai/corso/internal/testing" ctesting "github.com/alcionai/corso/internal/testing"
"github.com/alcionai/corso/pkg/backup/details"
"github.com/alcionai/corso/pkg/selectors" "github.com/alcionai/corso/pkg/selectors"
) )
@ -73,25 +72,16 @@ func (suite *GraphConnectorIntegrationSuite) TestGraphConnector_ExchangeDataColl
suite.Greater(len(exchangeData.FullPath()), 2) 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() { func (suite *GraphConnectorIntegrationSuite) TestGraphConnector_restoreMessages() {
user := "TEST_GRAPH_USER" // user.GetId() 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)
evs, err := ctesting.GetRequiredEnvVars(user, file)
if err != nil { if err != nil {
suite.T().Skipf("Environment not configured: %v\n", err) 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 mdc := mockconnector.NewMockExchangeCollection([]string{"tenant", evs[user], mailCategory, "Inbox"}, 1)
if err != nil { err = suite.connector.RestoreMessages(context.Background(), []data.Collection{mdc})
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})
assert.NoError(suite.T(), err) assert.NoError(suite.T(), err)
} }

View File

@ -7,6 +7,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/alcionai/corso/internal/common"
"github.com/alcionai/corso/internal/data" "github.com/alcionai/corso/internal/data"
"github.com/alcionai/corso/pkg/backup/details" "github.com/alcionai/corso/pkg/backup/details"
) )
@ -26,8 +27,8 @@ var (
) )
// NewMockExchangeDataCollection creates an data collection that will return the specified number of // NewMockExchangeDataCollection creates an data collection that will return the specified number of
// mock messages when iterated // mock messages when iterated. Exchange type mail
func NewMockExchangeDataCollection(pathRepresentation []string, numMessagesToReturn int) *MockExchangeDataCollection { func NewMockExchangeCollection(pathRepresentation []string, numMessagesToReturn int) *MockExchangeDataCollection {
c := &MockExchangeDataCollection{ c := &MockExchangeDataCollection{
fullPath: pathRepresentation, fullPath: pathRepresentation,
messageCount: numMessagesToReturn, messageCount: numMessagesToReturn,
@ -37,7 +38,7 @@ func NewMockExchangeDataCollection(pathRepresentation []string, numMessagesToRet
for i := 0; i < c.messageCount; i++ { 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) // 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()) c.Names = append(c.Names, uuid.NewString())
} }
return c return c
@ -82,3 +83,13 @@ func (med *MockExchangeData) ToReader() io.ReadCloser {
func (med *MockExchangeData) Info() details.ItemInfo { func (med *MockExchangeData) Info() details.ItemInfo {
return details.ItemInfo{Exchange: &details.ExchangeInfo{Sender: "foo@bar.com", Subject: "Hello world!", Received: time.Now()}} 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\": \"<MWHPR1401MB1952C46D4A46B6398F562B0FA6E99@MWHPR1401MB1952.namprd14.prod.outlook.com>\",\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\": \"<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\": \"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)
}

View File

@ -1,25 +1,28 @@
package mockconnector_test package mockconnector_test
import ( import (
"bytes"
"io/ioutil" "io/ioutil"
"testing" "testing"
"github.com/microsoftgraph/msgraph-sdk-go/models"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
"github.com/alcionai/corso/internal/connector/mockconnector" "github.com/alcionai/corso/internal/connector/mockconnector"
"github.com/alcionai/corso/internal/connector/support"
) )
type MockExchangeDataCollectionSuite struct { type MockExchangeCollectionSuite struct {
suite.Suite suite.Suite
} }
func TestMockExchangeDataCollectionSuite(t *testing.T) { func TestMockExchangeCollectionSuite(t *testing.T) {
suite.Run(t, new(MockExchangeDataCollectionSuite)) suite.Run(t, new(MockExchangeCollectionSuite))
} }
func (suite *MockExchangeDataCollectionSuite) TestMockExchangeDataCollection() { func (suite *MockExchangeCollectionSuite) TestMockExchangeCollection() {
mdc := mockconnector.NewMockExchangeDataCollection([]string{"foo", "bar"}, 2) mdc := mockconnector.NewMockExchangeCollection([]string{"foo", "bar"}, 2)
messagesRead := 0 messagesRead := 0
@ -30,3 +33,22 @@ func (suite *MockExchangeDataCollectionSuite) TestMockExchangeDataCollection() {
} }
assert.Equal(suite.T(), 2, messagesRead) 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)
}
}

View File

@ -120,11 +120,11 @@ func (suite *KopiaUnitSuite) TestBuildDirectoryTree() {
details := &details.Details{} details := &details.Details{}
collections := []data.Collection{ collections := []data.Collection{
mockconnector.NewMockExchangeDataCollection( mockconnector.NewMockExchangeCollection(
[]string{tenant, user1, emails}, []string{tenant, user1, emails},
expectedFileCount[user1], expectedFileCount[user1],
), ),
mockconnector.NewMockExchangeDataCollection( mockconnector.NewMockExchangeCollection(
[]string{tenant, user2, emails}, []string{tenant, user2, emails},
expectedFileCount[user2], expectedFileCount[user2],
), ),
@ -182,7 +182,7 @@ func (suite *KopiaUnitSuite) TestBuildDirectoryTree_NoAncestorDirs() {
details := &details.Details{} details := &details.Details{}
collections := []data.Collection{ collections := []data.Collection{
mockconnector.NewMockExchangeDataCollection( mockconnector.NewMockExchangeCollection(
[]string{emails}, []string{emails},
expectedFileCount, expectedFileCount,
), ),
@ -215,11 +215,11 @@ func (suite *KopiaUnitSuite) TestBuildDirectoryTree_Fails() {
// - emails // - emails
// - 42 separate files // - 42 separate files
[]data.Collection{ []data.Collection{
mockconnector.NewMockExchangeDataCollection( mockconnector.NewMockExchangeCollection(
[]string{"user1", "emails"}, []string{"user1", "emails"},
5, 5,
), ),
mockconnector.NewMockExchangeDataCollection( mockconnector.NewMockExchangeCollection(
[]string{"user2", "emails"}, []string{"user2", "emails"},
42, 42,
), ),
@ -228,7 +228,7 @@ func (suite *KopiaUnitSuite) TestBuildDirectoryTree_Fails() {
{ {
"NoCollectionPath", "NoCollectionPath",
[]data.Collection{ []data.Collection{
mockconnector.NewMockExchangeDataCollection( mockconnector.NewMockExchangeCollection(
nil, nil,
5, 5,
), ),
@ -243,11 +243,11 @@ func (suite *KopiaUnitSuite) TestBuildDirectoryTree_Fails() {
// - 5 separate files // - 5 separate files
// - 42 separate files // - 42 separate files
[]data.Collection{ []data.Collection{
mockconnector.NewMockExchangeDataCollection( mockconnector.NewMockExchangeCollection(
[]string{"a-tenant", "user1", "emails"}, []string{"a-tenant", "user1", "emails"},
5, 5,
), ),
mockconnector.NewMockExchangeDataCollection( mockconnector.NewMockExchangeCollection(
[]string{"a-tenant", "user1"}, []string{"a-tenant", "user1"},
42, 42,
), ),
@ -402,11 +402,11 @@ func (suite *KopiaIntegrationSuite) TestBackupCollections() {
t := suite.T() t := suite.T()
collections := []data.Collection{ collections := []data.Collection{
mockconnector.NewMockExchangeDataCollection( mockconnector.NewMockExchangeCollection(
[]string{"a-tenant", "user1", "emails"}, []string{"a-tenant", "user1", "emails"},
5, 5,
), ),
mockconnector.NewMockExchangeDataCollection( mockconnector.NewMockExchangeCollection(
[]string{"a-tenant", "user2", "emails"}, []string{"a-tenant", "user2", "emails"},
42, 42,
), ),
@ -683,8 +683,8 @@ func (suite *KopiaSimpleRepoIntegrationSuite) TestRestoreMultipleItems() {
tid := uuid.NewString() tid := uuid.NewString()
p1 := []string{tid, "uid", "emails", "fid"} p1 := []string{tid, "uid", "emails", "fid"}
p2 := []string{tid, "uid2", "emails", "fid"} p2 := []string{tid, "uid2", "emails", "fid"}
dc1 := mockconnector.NewMockExchangeDataCollection(p1, 1) dc1 := mockconnector.NewMockExchangeCollection(p1, 1)
dc2 := mockconnector.NewMockExchangeDataCollection(p2, 1) dc2 := mockconnector.NewMockExchangeCollection(p2, 1)
fp1 := append(p1, dc1.Names[0]) fp1 := append(p1, dc1.Names[0])
fp2 := append(p2, dc2.Names[0]) fp2 := append(p2, dc2.Names[0])