diff --git a/src/internal/connector/exchange/api/shared.go b/src/internal/connector/exchange/api/shared.go index 6e8a64f34..5db8a481f 100644 --- a/src/internal/connector/exchange/api/shared.go +++ b/src/internal/connector/exchange/api/shared.go @@ -3,6 +3,7 @@ package api import ( "context" "fmt" + "os" "github.com/alcionai/clues" @@ -104,6 +105,11 @@ func getItemsAddedAndRemovedFromContainer( } nextLink, delta := api.NextAndDeltaLink(resp) + if len(os.Getenv("CORSO_URL_LOGGING")) > 0 { + if !api.IsNextLinkValid(nextLink) || api.IsNextLinkValid(delta) { + logger.Ctx(ctx).Infof("Received invalid link from M365:\nNext Link: %s\nDelta Link: %s\n", nextLink, delta) + } + } // the deltaLink is kind of like a cursor for overall data state. // once we run through pages of nextLinks, the last query will diff --git a/src/internal/connector/graph/api/api.go b/src/internal/connector/graph/api/api.go index dff30bc4b..0870f9ea0 100644 --- a/src/internal/connector/graph/api/api.go +++ b/src/internal/connector/graph/api/api.go @@ -1,6 +1,10 @@ package api -import "github.com/alcionai/corso/src/internal/common/ptr" +import ( + "strings" + + "github.com/alcionai/corso/src/internal/common/ptr" +) type PageLinker interface { GetOdataNextLink() *string @@ -11,6 +15,11 @@ type DeltaPageLinker interface { GetOdataDeltaLink() *string } +// IsNextLinkValid separate check to investigate whether error is +func IsNextLinkValid(next string) bool { + return !strings.Contains(next, `users//`) +} + func NextLink(pl PageLinker) string { return ptr.Val(pl.GetOdataNextLink()) } diff --git a/src/internal/connector/graph/api/api_test.go b/src/internal/connector/graph/api/api_test.go index 37932396d..b0c1d5f5a 100644 --- a/src/internal/connector/graph/api/api_test.go +++ b/src/internal/connector/graph/api/api_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/suite" "github.com/alcionai/corso/src/internal/connector/graph/api" + "github.com/alcionai/corso/src/internal/tester" ) type mockNextLink struct { @@ -59,20 +60,14 @@ var ( ) type APIUnitSuite struct { - suite.Suite + tester.Suite } func TestAPIUnitSuite(t *testing.T) { - suite.Run(t, new(APIUnitSuite)) -} - -func (suite *APIUnitSuite) TestNextLink() { - for _, test := range nextLinkInputs { - suite.T().Run(test.name, func(t *testing.T) { - l := mockNextLink{nextLink: test.inputLink} - assert.Equal(t, test.expectedLink, api.NextLink(l)) - }) + s := &APIUnitSuite{ + Suite: tester.NewUnitSuite(t), } + suite.Run(t, s) } func (suite *APIUnitSuite) TestNextAndDeltaLink() { @@ -112,3 +107,39 @@ func (suite *APIUnitSuite) TestNextAndDeltaLink() { } } } + +// TestIsLinkValid check to verify is nextLink guard check for logging +// Related to: https://github.com/alcionai/corso/issues/2520 +// +//nolint:lll +func (suite *APIUnitSuite) TestIsLinkValid() { + invalidString := `https://graph.microsoft.com/v1.0/users//mailFolders//messages/microsoft.graph.delta()?$select=id%2CisRead` + tests := []struct { + name string + inputString string + isValid assert.BoolAssertionFunc + }{ + { + name: "Empty", + inputString: emptyLink, + isValid: assert.True, + }, + { + name: "Invalid", + inputString: invalidString, + isValid: assert.False, + }, + { + name: "Valid", + inputString: `https://graph.microsoft.com/v1.0/users/aPerson/mailFolders/AMessage/messages/microsoft.graph.delta()?$select=id%2CisRead`, + isValid: assert.True, + }, + } + + for _, test := range tests { + suite.T().Run(test.name, func(t *testing.T) { + got := api.IsNextLinkValid(test.inputString) + test.isValid(t, got) + }) + } +} diff --git a/src/internal/connector/onedrive/drive.go b/src/internal/connector/onedrive/drive.go index c058be93a..15b740a73 100644 --- a/src/internal/connector/onedrive/drive.go +++ b/src/internal/connector/onedrive/drive.go @@ -12,6 +12,7 @@ import ( "github.com/pkg/errors" "golang.org/x/exp/maps" + "github.com/alcionai/corso/src/internal/common/ptr" "github.com/alcionai/corso/src/internal/connector/graph" gapi "github.com/alcionai/corso/src/internal/connector/graph/api" "github.com/alcionai/corso/src/internal/connector/onedrive/api" @@ -126,7 +127,7 @@ func drives( drives = append(drives, tmp...) - nextLink := gapi.NextLink(page) + nextLink := ptr.Val(page.GetOdataNextLink()) if len(nextLink) == 0 { break }