Add EndTime to Exchange events (#1446)

## Description

Add EndTime to Exchange events. Also fixes a testcase around start time.

## Type of change

<!--- Please check the type of change your PR introduces: --->
- [x] 🌻 Feature
- [ ] 🐛 Bugfix
- [ ] 🗺️ Documentation
- [ ] 🤖 Test
- [ ] 💻 CI/Deployment
- [ ] 🐹 Trivial/Minor

## Issue(s)

<!-- Can reference multiple issues. Use one of the following "magic words" - "closes, fixes" to auto-close the Github issue. -->
* https://github.com/alcionai/corso/issues/1366

## Test Plan

<!-- How will this be tested prior to merging.-->
- [ ] 💪 Manual
- [x]  Unit test
- [ ] 💚 E2E
This commit is contained in:
Abin Simon 2022-11-07 14:58:27 +05:30 committed by GitHub
parent f197396455
commit 5089f9d949
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 86 additions and 29 deletions

View File

@ -38,6 +38,10 @@ const (
// SimpleTimeTesting is used for testing restore destination folders. // SimpleTimeTesting is used for testing restore destination folders.
// Microsecond granularity prevents collisions in parallel package or workflow runs. // Microsecond granularity prevents collisions in parallel package or workflow runs.
SimpleTimeTesting TimeFormat = SimpleDateTimeOneDrive + ".000000" SimpleTimeTesting TimeFormat = SimpleDateTimeOneDrive + ".000000"
// M365dateTimeTimeZoneTimeFormat is the format used by M365 for datetimetimezone resource
// https://learn.microsoft.com/en-us/graph/api/resources/datetimetimezone?view=graph-rest-1.0
M365DateTimeTimeZone TimeFormat = "2006-01-02T15:04:05.000000"
) )
// these regexes are used to extract time formats from strings. Their primary purpose is to // these regexes are used to extract time formats from strings. Their primary purpose is to

View File

@ -15,6 +15,7 @@ func EventInfo(evt models.Eventable) *details.ExchangeInfo {
organizer, subject string organizer, subject string
recurs bool recurs bool
start = time.Time{} start = time.Time{}
end = time.Time{}
) )
if evt.GetOrganizer() != nil && if evt.GetOrganizer() != nil &&
@ -37,19 +38,32 @@ func EventInfo(evt models.Eventable) *details.ExchangeInfo {
evt.GetStart().GetDateTime() != nil { evt.GetStart().GetDateTime() != nil {
// timeString has 'Z' literal added to ensure the stored // timeString has 'Z' literal added to ensure the stored
// DateTime is not: time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC) // DateTime is not: time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC)
timeString := *evt.GetStart().GetDateTime() + "Z" startTime := *evt.GetStart().GetDateTime() + "Z"
output, err := common.ParseTime(timeString) output, err := common.ParseTime(startTime)
if err == nil { if err == nil {
start = output start = output
} }
} }
if evt.GetEnd() != nil &&
evt.GetEnd().GetDateTime() != nil {
// timeString has 'Z' literal added to ensure the stored
// DateTime is not: time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC)
endTime := *evt.GetEnd().GetDateTime() + "Z"
output, err := common.ParseTime(endTime)
if err == nil {
end = output
}
}
return &details.ExchangeInfo{ return &details.ExchangeInfo{
ItemType: details.ExchangeEvent, ItemType: details.ExchangeEvent,
Organizer: organizer, Organizer: organizer,
Subject: subject, Subject: subject,
EventStart: start, EventStart: start,
EventEnd: end,
EventRecurs: recurs, EventRecurs: recurs,
} }
} }

View File

@ -27,7 +27,7 @@ func TestEventSuite(t *testing.T) {
// can be properly retrieved from a models.Eventable object // can be properly retrieved from a models.Eventable object
func (suite *EventSuite) TestEventInfo() { func (suite *EventSuite) TestEventInfo() {
initial := time.Now() initial := time.Now()
now := common.FormatTime(initial) now := common.FormatTimeWith(initial, common.M365DateTimeTimeZone)
suite.T().Logf("Initial: %v\nFormatted: %v\n", initial, now) suite.T().Logf("Initial: %v\nFormatted: %v\n", initial, now)
@ -47,19 +47,41 @@ func (suite *EventSuite) TestEventInfo() {
name: "Start time only", name: "Start time only",
evtAndRP: func() (models.Eventable, *details.ExchangeInfo) { evtAndRP: func() (models.Eventable, *details.ExchangeInfo) {
var ( var (
event = models.NewEvent() event = models.NewEvent()
dateTime = models.NewDateTimeTimeZone() dateTime = models.NewDateTimeTimeZone()
full, err = common.ParseTime(now)
) )
require.NoError(suite.T(), err)
dateTime.SetDateTime(&now) dateTime.SetDateTime(&now)
event.SetStart(dateTime) event.SetStart(dateTime)
return event, &details.ExchangeInfo{ return event, &details.ExchangeInfo{
ItemType: details.ExchangeEvent, ItemType: details.ExchangeEvent,
Received: full, Received: initial,
EventStart: initial,
}
},
},
{
name: "Start and end time only",
evtAndRP: func() (models.Eventable, *details.ExchangeInfo) {
var (
event = models.NewEvent()
startTime = models.NewDateTimeTimeZone()
endTime = models.NewDateTimeTimeZone()
)
startTime.SetDateTime(&now)
event.SetStart(startTime)
nowp30m := common.FormatTimeWith(initial.Add(30*time.Minute), common.M365DateTimeTimeZone)
endTime.SetDateTime(&nowp30m)
event.SetEnd(endTime)
return event, &details.ExchangeInfo{
ItemType: details.ExchangeEvent,
Received: initial,
EventStart: initial,
EventEnd: initial.Add(30 * time.Minute),
} }
}, },
}, },
@ -83,12 +105,13 @@ func (suite *EventSuite) TestEventInfo() {
name: "Using mockable", name: "Using mockable",
evtAndRP: func() (models.Eventable, *details.ExchangeInfo) { evtAndRP: func() (models.Eventable, *details.ExchangeInfo) {
var ( var (
organizer = "foobar3@8qzvrj.onmicrosoft.com" organizer = "foobar3@8qzvrj.onmicrosoft.com"
subject = " Test Mock Review + Lunch" subject = " Test Mock Review + Lunch"
bytes = mockconnector.GetDefaultMockEventBytes("Test Mock") bytes = mockconnector.GetDefaultMockEventBytes("Test Mock")
future = time.Now().UTC().AddDate(0, 0, 1) future = time.Now().UTC().AddDate(0, 0, 1)
eventTime = time.Date(future.Year(), future.Month(), future.Day(), future.Hour(), 0, 0, 0, time.UTC) eventTime = time.Date(future.Year(), future.Month(), future.Day(), future.Hour(), 0, 0, 0, time.UTC)
event, err = support.CreateEventFromBytes(bytes) eventEndTime = eventTime.Add(30 * time.Minute)
event, err = support.CreateEventFromBytes(bytes)
) )
require.NoError(suite.T(), err) require.NoError(suite.T(), err)
@ -98,6 +121,7 @@ func (suite *EventSuite) TestEventInfo() {
Subject: subject, Subject: subject,
Organizer: organizer, Organizer: organizer,
EventStart: eventTime, EventStart: eventTime,
EventEnd: eventEndTime,
} }
}, },
}, },
@ -110,16 +134,27 @@ func (suite *EventSuite) TestEventInfo() {
assert.Equal(t, expected.Subject, result.Subject, "subject") assert.Equal(t, expected.Subject, result.Subject, "subject")
assert.Equal(t, expected.Sender, result.Sender, "sender") assert.Equal(t, expected.Sender, result.Sender, "sender")
expYear, expMonth, _ := expected.EventStart.Date() // Day not used at certain times of the day expStartYear, expStartMonth, _ := expected.EventStart.Date() // Day not used at certain times of the day
expHr, expMin, expSec := expected.EventStart.Clock() expStartHr, expStartMin, expStartSec := expected.EventStart.Clock()
recvYear, recvMonth, _ := result.EventStart.Date() recvStartYear, recvStartMonth, _ := result.EventStart.Date()
recvHr, recvMin, recvSec := result.EventStart.Clock() recvStartHr, recvStartMin, recvStartSec := result.EventStart.Clock()
assert.Equal(t, expYear, recvYear, "year") assert.Equal(t, expStartYear, recvStartYear, "year")
assert.Equal(t, expMonth, recvMonth, "month") assert.Equal(t, expStartMonth, recvStartMonth, "month")
assert.Equal(t, expHr, recvHr, "hour") assert.Equal(t, expStartHr, recvStartHr, "hour")
assert.Equal(t, expMin, recvMin, "minute") assert.Equal(t, expStartMin, recvStartMin, "minute")
assert.Equal(t, expSec, recvSec, "second") assert.Equal(t, expStartSec, recvStartSec, "second")
expEndYear, expEndMonth, _ := expected.EventEnd.Date() // Day not used at certain times of the day
expEndHr, expEndMin, expEndSec := expected.EventEnd.Clock()
recvEndYear, recvEndMonth, _ := result.EventEnd.Date()
recvEndHr, recvEndMin, recvEndSec := result.EventEnd.Clock()
assert.Equal(t, expEndYear, recvEndYear, "year")
assert.Equal(t, expEndMonth, recvEndMonth, "month")
assert.Equal(t, expEndHr, recvEndHr, "hour")
assert.Equal(t, expEndMin, recvEndMin, "minute")
assert.Equal(t, expEndSec, recvEndSec, "second")
}) })
} }
} }

View File

@ -176,11 +176,12 @@ func GetMockEventWithSubjectBytes(subject string) []byte {
tomorrow := time.Now().UTC().AddDate(0, 0, 1) tomorrow := time.Now().UTC().AddDate(0, 0, 1)
at := time.Date(tomorrow.Year(), tomorrow.Month(), tomorrow.Day(), tomorrow.Hour(), 0, 0, 0, time.UTC) at := time.Date(tomorrow.Year(), tomorrow.Month(), tomorrow.Day(), tomorrow.Hour(), 0, 0, 0, time.UTC)
atTime := common.FormatTime(at) atTime := common.FormatTime(at)
endTime := common.FormatTime(at.Add(30 * time.Minute))
return GetMockEventWith( return GetMockEventWith(
defaultEventOrganizer, subject, defaultEventOrganizer, subject,
defaultEventBody, defaultEventBodyPreview, defaultEventBody, defaultEventBodyPreview,
atTime, atTime, false, atTime, endTime, false,
) )
} }

View File

@ -298,6 +298,7 @@ type ExchangeInfo struct {
Subject string `json:"subject,omitempty"` Subject string `json:"subject,omitempty"`
Received time.Time `json:"received,omitempty"` Received time.Time `json:"received,omitempty"`
EventStart time.Time `json:"eventStart,omitempty"` EventStart time.Time `json:"eventStart,omitempty"`
EventEnd time.Time `json:"eventEnd,omitempty"`
Organizer string `json:"organizer,omitempty"` Organizer string `json:"organizer,omitempty"`
ContactName string `json:"contactName,omitempty"` ContactName string `json:"contactName,omitempty"`
EventRecurs bool `json:"eventRecurs,omitempty"` EventRecurs bool `json:"eventRecurs,omitempty"`
@ -308,7 +309,7 @@ type ExchangeInfo struct {
func (i ExchangeInfo) Headers() []string { func (i ExchangeInfo) Headers() []string {
switch i.ItemType { switch i.ItemType {
case ExchangeEvent: case ExchangeEvent:
return []string{"Organizer", "Subject", "Starts", "Recurring"} return []string{"Organizer", "Subject", "Starts", "Ends", "Recurring"}
case ExchangeContact: case ExchangeContact:
return []string{"Contact Name"} return []string{"Contact Name"}
@ -329,6 +330,7 @@ func (i ExchangeInfo) Values() []string {
i.Organizer, i.Organizer,
i.Subject, i.Subject,
common.FormatTabularDisplayTime(i.EventStart), common.FormatTabularDisplayTime(i.EventStart),
common.FormatTabularDisplayTime(i.EventEnd),
strconv.FormatBool(i.EventRecurs), strconv.FormatBool(i.EventRecurs),
} }

View File

@ -52,14 +52,15 @@ func (suite *DetailsUnitSuite) TestDetailsEntry_HeadersValues() {
Exchange: &details.ExchangeInfo{ Exchange: &details.ExchangeInfo{
ItemType: details.ExchangeEvent, ItemType: details.ExchangeEvent,
EventStart: now, EventStart: now,
EventEnd: now,
Organizer: "organizer", Organizer: "organizer",
EventRecurs: true, EventRecurs: true,
Subject: "subject", Subject: "subject",
}, },
}, },
}, },
expectHs: []string{"ID", "Organizer", "Subject", "Starts", "Recurring"}, expectHs: []string{"ID", "Organizer", "Subject", "Starts", "Ends", "Recurring"},
expectVs: []string{"deadbeef", "organizer", "subject", nowStr, "true"}, expectVs: []string{"deadbeef", "organizer", "subject", nowStr, nowStr, "true"},
}, },
{ {
name: "exchange contact info", name: "exchange contact info",