add sharepoint to path (#1465)

Adds the sharepoint service to /pkg/path.  Currently uses the
"Files" category for its category type, which is just a placeholder
for kicking off development.

Additionally, uncomments selector tests that were dependent
upon the path service declaration.
This commit is contained in:
Keepers 2022-11-14 15:35:57 -07:00 committed by GitHub
parent 2f5df36c6a
commit 11371f6e94
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 238 additions and 191 deletions

View File

@ -177,7 +177,7 @@ func (suite *MockExchangeDataSuite) TestMockByteHydration() {
},
},
{
name: "Sharepoint: List",
name: "SharePoint: List",
transformation: func(t *testing.T) error {
bytes, err := mockconnector.GetMockListBytes(subject)
require.NoError(suite.T(), err)

View File

@ -69,7 +69,7 @@ func (sc *Collection) Items() <-chan data.Stream {
type Item struct {
id string
data io.ReadCloser
info *details.SharepointInfo
info *details.SharePointInfo
}
func (sd *Item) UUID() string {
@ -81,7 +81,7 @@ func (sd *Item) ToReader() io.ReadCloser {
}
func (sd *Item) Info() details.ItemInfo {
return details.ItemInfo{Sharepoint: sd.info}
return details.ItemInfo{SharePoint: sd.info}
}
func (sc *Collection) finishPopulation(ctx context.Context, success int, totalBytes int64, errs error) {

View File

@ -71,7 +71,7 @@ func (suite *SharePointCollectionSuite) TestSharePointListCollection() {
col.data <- &Item{
id: testName,
data: io.NopCloser(bytes.NewReader(byteArray)),
info: sharepointListInfo(listing),
info: sharePointListInfo(listing),
}
col.finishPopulation(ctx, 0, 0, nil)
@ -85,6 +85,6 @@ func (suite *SharePointCollectionSuite) TestSharePointListCollection() {
shareInfo, ok := item.(data.StreamInfo)
require.True(t, ok)
require.NotNil(t, shareInfo.Info())
require.NotNil(t, shareInfo.Info().Sharepoint)
assert.Equal(t, testName, shareInfo.Info().Sharepoint.ItemName)
require.NotNil(t, shareInfo.Info().SharePoint)
assert.Equal(t, testName, shareInfo.Info().SharePoint.ItemName)
}

View File

@ -8,9 +8,9 @@ import (
"github.com/alcionai/corso/src/pkg/backup/details"
)
// sharepointListInfo translates models.Listable metadata into searchable content
// sharePointListInfo translates models.Listable metadata into searchable content
// List Details: https://learn.microsoft.com/en-us/graph/api/resources/list?view=graph-rest-1.0
func sharepointListInfo(lst models.Listable) *details.SharepointInfo {
func sharePointListInfo(lst models.Listable) *details.SharePointInfo {
var (
name, webURL string
created, modified time.Time
@ -32,8 +32,8 @@ func sharepointListInfo(lst models.Listable) *details.SharepointInfo {
modified = *lst.GetLastModifiedDateTime()
}
return &details.SharepointInfo{
ItemType: details.SharepointItem,
return &details.SharePointInfo{
ItemType: details.SharePointItem,
ItemName: name,
Created: created,
Modified: modified,

View File

@ -21,22 +21,22 @@ func TestSharePointInfoSuite(t *testing.T) {
func (suite *SharePointInfoSuite) TestSharePointInfo() {
tests := []struct {
name string
listAndRP func() (models.Listable, *details.SharepointInfo)
listAndRP func() (models.Listable, *details.SharePointInfo)
}{
{
name: "Empty List",
listAndRP: func() (models.Listable, *details.SharepointInfo) {
i := &details.SharepointInfo{ItemType: details.SharepointItem}
listAndRP: func() (models.Listable, *details.SharePointInfo) {
i := &details.SharePointInfo{ItemType: details.SharePointItem}
return models.NewList(), i
},
}, {
name: "Only Name",
listAndRP: func() (models.Listable, *details.SharepointInfo) {
listAndRP: func() (models.Listable, *details.SharePointInfo) {
aTitle := "Whole List"
listing := models.NewList()
listing.SetDisplayName(&aTitle)
i := &details.SharepointInfo{
ItemType: details.SharepointItem,
i := &details.SharePointInfo{
ItemType: details.SharePointItem,
ItemName: aTitle,
}
return listing, i
@ -46,7 +46,7 @@ func (suite *SharePointInfoSuite) TestSharePointInfo() {
for _, test := range tests {
suite.T().Run(test.name, func(t *testing.T) {
list, expected := test.listAndRP()
info := sharepointListInfo(list)
info := sharePointListInfo(list)
assert.Equal(t, expected.ItemType, info.ItemType)
assert.Equal(t, expected.ItemName, info.ItemName)
assert.Equal(t, expected.WebURL, info.WebURL)

View File

@ -194,8 +194,8 @@ func (de DetailsEntry) Headers() []string {
hs = append(hs, de.ItemInfo.Exchange.Headers()...)
}
if de.ItemInfo.Sharepoint != nil {
hs = append(hs, de.ItemInfo.Sharepoint.Headers()...)
if de.ItemInfo.SharePoint != nil {
hs = append(hs, de.ItemInfo.SharePoint.Headers()...)
}
if de.ItemInfo.OneDrive != nil {
@ -217,8 +217,8 @@ func (de DetailsEntry) Values() []string {
vs = append(vs, de.ItemInfo.Exchange.Values()...)
}
if de.ItemInfo.Sharepoint != nil {
vs = append(vs, de.ItemInfo.Sharepoint.Values()...)
if de.ItemInfo.SharePoint != nil {
vs = append(vs, de.ItemInfo.SharePoint.Values()...)
}
if de.ItemInfo.OneDrive != nil {
@ -238,7 +238,7 @@ const (
ExchangeEvent
ExchangeMail
SharepointItem ItemType = iota + 100
SharePointItem ItemType = iota + 100
OneDriveItem ItemType = iota + 200
@ -250,7 +250,7 @@ const (
type ItemInfo struct {
Folder *FolderInfo `json:"folder,omitempty"`
Exchange *ExchangeInfo `json:"exchange,omitempty"`
Sharepoint *SharepointInfo `json:"sharepoint,omitempty"`
SharePoint *SharePointInfo `json:"sharePoint,omitempty"`
OneDrive *OneDriveInfo `json:"oneDrive,omitempty"`
}
@ -268,8 +268,8 @@ func (i ItemInfo) infoType() ItemType {
case i.Exchange != nil:
return i.Exchange.ItemType
case i.Sharepoint != nil:
return i.Sharepoint.ItemType
case i.SharePoint != nil:
return i.SharePoint.ItemType
case i.OneDrive != nil:
return i.OneDrive.ItemType
@ -344,8 +344,8 @@ func (i ExchangeInfo) Values() []string {
return []string{}
}
// SharepointInfo describes a sharepoint item
type SharepointInfo struct {
// SharePointInfo describes a sharepoint item
type SharePointInfo struct {
ItemType ItemType `json:"itemType,omitempty"`
ItemName string `json:"itemName,omitempty"`
Created time.Time `json:"created,omitempty"`
@ -353,15 +353,15 @@ type SharepointInfo struct {
WebURL string `json:"webUrl,omitempty"`
}
// Headers returns the human-readable names of properties in a SharepointInfo
// Headers returns the human-readable names of properties in a SharePointInfo
// for printing out to a terminal in a columnar display.
func (i SharepointInfo) Headers() []string {
func (i SharePointInfo) Headers() []string {
return []string{}
}
// Values returns the values matching the Headers list for printing
// out to a terminal in a columnar display.
func (i SharepointInfo) Values() []string {
func (i SharePointInfo) Values() []string {
return []string{}
}

View File

@ -100,7 +100,7 @@ func (suite *DetailsUnitSuite) TestDetailsEntry_HeadersValues() {
RepoRef: "reporef",
ShortRef: "deadbeef",
ItemInfo: details.ItemInfo{
Sharepoint: &details.SharepointInfo{},
SharePoint: &details.SharePointInfo{},
},
},
expectHs: []string{"ID"},

View File

@ -305,6 +305,27 @@ func (pb Builder) ToDataLayerOneDrivePath(
}, nil
}
func (pb Builder) ToDataLayerSharePointPath(
tenant, site string,
isItem bool,
) (Path, error) {
if err := pb.verifyPrefix(tenant, site); err != nil {
return nil, err
}
return &dataLayerResourcePath{
Builder: *pb.withPrefix(
tenant,
SharePointService.String(),
site,
FilesCategory.String(),
),
service: SharePointService,
category: FilesCategory,
hasItem: isItem,
}, nil
}
// FromDataLayerPath parses the escaped path p, validates the elements in p
// match a resource-specific path format, and returns a Path struct for that
// resource-specific type. If p does not match any resource-specific paths or

View File

@ -10,9 +10,10 @@ type ServiceType int
//go:generate stringer -type=ServiceType -linecomment
const (
UnknownService ServiceType = iota
ExchangeService // exchange
OneDriveService // onedrive
UnknownService ServiceType = iota
ExchangeService // exchange
OneDriveService // onedrive
SharePointService // sharepoint
)
func toServiceType(service string) ServiceType {
@ -21,6 +22,8 @@ func toServiceType(service string) ServiceType {
return ExchangeService
case OneDriveService.String():
return OneDriveService
case SharePointService.String():
return SharePointService
default:
return UnknownService
}
@ -64,6 +67,10 @@ var serviceCategories = map[ServiceType]map[CategoryType]struct{}{
OneDriveService: {
FilesCategory: {},
},
SharePointService: {
// TODO: need to figure out the service Category(s) for sharepoint.
FilesCategory: {},
},
}
func validateServiceAndCategoryStrings(s, c string) (ServiceType, CategoryType, error) {

View File

@ -102,6 +102,13 @@ var (
return pb.ToDataLayerOneDrivePath(tenant, user, isItem)
},
},
{
service: path.SharePointService,
category: path.FilesCategory,
pathFunc: func(pb *path.Builder, tenant, user string, isItem bool) (path.Path, error) {
return pb.ToDataLayerSharePointPath(tenant, user, isItem)
},
},
}
)

View File

@ -105,6 +105,14 @@ func (suite *ServiceCategoryUnitSuite) TestValidateServiceAndCategory() {
expectedCategory: FilesCategory,
check: assert.NoError,
},
{
name: "SharePointFiles",
service: SharePointService.String(),
category: FilesCategory.String(),
expectedService: SharePointService,
expectedCategory: FilesCategory,
check: assert.NoError,
},
}
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {

View File

@ -11,11 +11,12 @@ func _() {
_ = x[UnknownService-0]
_ = x[ExchangeService-1]
_ = x[OneDriveService-2]
_ = x[SharePointService-3]
}
const _ServiceType_name = "UnknownServiceexchangeonedrive"
const _ServiceType_name = "UnknownServiceexchangeonedrivesharepoint"
var _ServiceType_index = [...]uint8{0, 14, 22, 30}
var _ServiceType_index = [...]uint8{0, 14, 22, 30, 40}
func (i ServiceType) String() string {
if i < 0 || i >= ServiceType(len(_ServiceType_index)-1) {

View File

@ -24,10 +24,10 @@ const (
)
var serviceToPathType = map[service]path.ServiceType{
ServiceUnknown: path.UnknownService,
ServiceExchange: path.ExchangeService,
ServiceOneDrive: path.OneDriveService,
// ServiceSharePoint: path.SharePointService, TODO: add sharepoint to path
ServiceUnknown: path.UnknownService,
ServiceExchange: path.ExchangeService,
ServiceOneDrive: path.OneDriveService,
ServiceSharePoint: path.SharePointService,
}
var (
@ -78,7 +78,7 @@ type Reducer interface {
// The core selector. Has no api for setting or retrieving data.
// Is only used to pass along more specific selector instances.
type Selector struct {
// The service scope of the data. Exchange, Teams, Sharepoint, etc.
// The service scope of the data. Exchange, Teams, SharePoint, etc.
Service service `json:"service,omitempty"`
// A slice of exclusion scopes. Exclusions apply globally to all
// inclusions/filters, with any-match behavior.

View File

@ -11,11 +11,12 @@ func _() {
_ = x[ServiceUnknown-0]
_ = x[ServiceExchange-1]
_ = x[ServiceOneDrive-2]
_ = x[ServiceSharePoint-3]
}
const _service_name = "Unknown ServiceExchangeOneDrive"
const _service_name = "Unknown ServiceExchangeOneDriveSharePoint"
var _service_index = [...]uint8{0, 15, 23, 31}
var _service_index = [...]uint8{0, 15, 23, 31, 41}
func (i service) String() string {
if i < 0 || i >= service(len(_service_index)-1) {

View File

@ -240,7 +240,7 @@ var _ categorizer = SharePointCategoryUnknown
const (
SharePointCategoryUnknown sharePointCategory = ""
// types of data identified by SharePoint
SharePointSite sharePointCategory = "SharePointSitte"
SharePointSite sharePointCategory = "SharePointSite"
SharePointFolder sharePointCategory = "SharePointFolder"
SharePointItem sharePointCategory = "SharePointItem"
@ -428,7 +428,8 @@ func (s sharePoint) Reduce(ctx context.Context, deets *details.Details) *details
deets,
s.Selector,
map[path.CategoryType]sharePointCategory{
// path.FilesCategory: SharePointItem,
// TODO: need to figure out the path Category(s) for sharepoint.
path.FilesCategory: SharePointItem,
},
)
}

View File

@ -6,6 +6,10 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/alcionai/corso/src/internal/tester"
"github.com/alcionai/corso/src/pkg/backup/details"
"github.com/alcionai/corso/src/pkg/path"
)
type SharePointSelectorSuite struct {
@ -175,162 +179,159 @@ func (suite *SharePointSelectorSuite) TestToSharePointRestore() {
assert.NotZero(t, or.Scopes())
}
// TODO: enable when sharepoint has path and detail representation
// func (suite *SharePointSelectorSuite) TestSharePointRestore_Reduce() {
// var (
// item = stubRepoRef(path.SharePointService, path.SharePointItemsCategory, "uid", "/folderA/folderB", "item")
// item2 = stubRepoRef(path.SharePointService, path.SharePointItemsCategory, "uid", "/folderA/folderC", "item2")
// item3 = stubRepoRef(path.SharePointService, path.SharePointItemsCategory, "uid", "/folderD/folderE", "item3")
// )
func (suite *SharePointSelectorSuite) TestSharePointRestore_Reduce() {
var (
item = stubRepoRef(path.SharePointService, path.FilesCategory, "uid", "/folderA/folderB", "item")
item2 = stubRepoRef(path.SharePointService, path.FilesCategory, "uid", "/folderA/folderC", "item2")
item3 = stubRepoRef(path.SharePointService, path.FilesCategory, "uid", "/folderD/folderE", "item3")
)
// deets := &details.Details{
// DetailsModel: details.DetailsModel{
// Entries: []details.DetailsEntry{
// {
// RepoRef: item,
// ItemInfo: details.ItemInfo{
// SharePoint: &details.SharePointInfo{
// ItemType: details.SharePointItem,
// },
// },
// },
// {
// RepoRef: item2,
// ItemInfo: details.ItemInfo{
// SharePoint: &details.SharePointInfo{
// ItemType: details.SharePointItem,
// },
// },
// },
// {
// RepoRef: item3,
// ItemInfo: details.ItemInfo{
// SharePoint: &details.SharePointInfo{
// ItemType: details.SharePointItem,
// },
// },
// },
// },
// },
// }
deets := &details.Details{
DetailsModel: details.DetailsModel{
Entries: []details.DetailsEntry{
{
RepoRef: item,
ItemInfo: details.ItemInfo{
SharePoint: &details.SharePointInfo{
ItemType: details.SharePointItem,
},
},
},
{
RepoRef: item2,
ItemInfo: details.ItemInfo{
SharePoint: &details.SharePointInfo{
ItemType: details.SharePointItem,
},
},
},
{
RepoRef: item3,
ItemInfo: details.ItemInfo{
SharePoint: &details.SharePointInfo{
ItemType: details.SharePointItem,
},
},
},
},
},
}
// arr := func(s ...string) []string {
// return s
// }
arr := func(s ...string) []string {
return s
}
// table := []struct {
// name string
// deets *details.Details
// makeSelector func() *SharePointRestore
// expect []string
// }{
// {
// "all",
// deets,
// func() *SharePointRestore {
// odr := NewSharePointRestore()
// odr.Include(odr.Sites(Any()))
// return odr
// },
// arr(item, item2, item3),
// },
// {
// "only match item",
// deets,
// func() *SharePointRestore {
// odr := NewSharePointRestore()
// odr.Include(odr.Items(Any(), Any(), []string{"item2"}))
// return odr
// },
// arr(item2),
// },
// {
// "only match folder",
// deets,
// func() *SharePointRestore {
// odr := NewSharePointRestore()
// odr.Include(odr.Folders([]string{"uid"}, []string{"folderA/folderB", "folderA/folderC"}))
// return odr
// },
// arr(item, item2),
// },
// }
// for _, test := range table {
// suite.T().Run(test.name, func(t *testing.T) {
// ctx, flush := tester.NewContext()
// defer flush()
table := []struct {
name string
deets *details.Details
makeSelector func() *SharePointRestore
expect []string
}{
{
"all",
deets,
func() *SharePointRestore {
odr := NewSharePointRestore()
odr.Include(odr.Sites(Any()))
return odr
},
arr(item, item2, item3),
},
{
"only match item",
deets,
func() *SharePointRestore {
odr := NewSharePointRestore()
odr.Include(odr.Items(Any(), Any(), []string{"item2"}))
return odr
},
arr(item2),
},
{
"only match folder",
deets,
func() *SharePointRestore {
odr := NewSharePointRestore()
odr.Include(odr.Folders([]string{"uid"}, []string{"folderA/folderB", "folderA/folderC"}))
return odr
},
arr(item, item2),
},
}
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
ctx, flush := tester.NewContext()
defer flush()
// sel := test.makeSelector()
// results := sel.Reduce(ctx, test.deets)
// paths := results.Paths()
// assert.Equal(t, test.expect, paths)
// })
// }
// }
sel := test.makeSelector()
results := sel.Reduce(ctx, test.deets)
paths := results.Paths()
assert.Equal(t, test.expect, paths)
})
}
}
// func (suite *SharePointSelectorSuite) TestSharePointCategory_PathValues() {
// t := suite.T()
func (suite *SharePointSelectorSuite) TestSharePointCategory_PathValues() {
t := suite.T()
// pathBuilder := path.Builder{}.Append("dir1", "dir2", "item")
// itemPath, err := pathBuilder.ToDataLayerSharePointPath("tenant", "site", true)
// require.NoError(t, err)
pathBuilder := path.Builder{}.Append("dir1", "dir2", "item")
itemPath, err := pathBuilder.ToDataLayerSharePointPath("tenant", "site", true)
require.NoError(t, err)
// expected := map[categorizer]string{
// SharePointSite: "site",
// SharePointFolder: "dir1/dir2",
// SharePointItem: "item",
// }
expected := map[categorizer]string{
SharePointSite: "site",
SharePointFolder: "dir1/dir2",
SharePointItem: "item",
}
// assert.Equal(t, expected, SharePointItem.pathValues(itemPath))
// }
assert.Equal(t, expected, SharePointItem.pathValues(itemPath))
}
// func (suite *SharePointSelectorSuite) TestSharePointScope_MatchesInfo() {
// ods := NewSharePointRestore()
func (suite *SharePointSelectorSuite) TestSharePointScope_MatchesInfo() {
ods := NewSharePointRestore()
// var (
// url = "www.website.com"
// )
// var url = "www.website.com"
// itemInfo := details.ItemInfo{
// SharePoint: &details.SharepointInfo{
// ItemType: details.SharePointItem,
// WebURL: "www.website.com",
// },
// }
itemInfo := details.ItemInfo{
SharePoint: &details.SharePointInfo{
ItemType: details.SharePointItem,
// WebURL: "www.website.com",
},
}
// table := []struct {
// name string
// scope []SharePointScope
// expect assert.BoolAssertionFunc
// }{
// {"item webURL match", ods.WebURL(url), assert.True},
// {"item webURL substring", ods.WebURL("website"), assert.True},
// {"item webURL mismatch", ods.WebURL("google"), assert.False},
// }
// for _, test := range table {
// suite.T().Run(test.name, func(t *testing.T) {
// scopes := setScopesToDefault(test.scope)
// for _, scope := range scopes {
// test.expect(t, scope.matchesInfo(itemInfo))
// }
// })
// }
// }
table := []struct {
name string
scope []SharePointScope
expect assert.BoolAssertionFunc
}{
// {"item webURL match", ods.WebURL(url), assert.True},
// {"item webURL substring", ods.WebURL("website"), assert.True},
{"item webURL mismatch", ods.WebURL("google"), assert.False},
}
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
scopes := setScopesToDefault(test.scope)
for _, scope := range scopes {
test.expect(t, scope.matchesInfo(itemInfo))
}
})
}
}
// func (suite *SharePointSelectorSuite) TestCategory_PathType() {
// table := []struct {
// cat sharePointCategory
// pathType path.CategoryType
// }{
// {SharePointCategoryUnknown, path.UnknownCategory},
// {SharePointSite, path.UnknownCategory},
// {SharePointFolder, path.SharePointItemCategory},
// {SharePointItem, path.SharePointItemCategory},
// {SharePointFilterWebURL, path.SharePointItemCategory},
// }
// for _, test := range table {
// suite.T().Run(test.cat.String(), func(t *testing.T) {
// assert.Equal(t, test.pathType, test.cat.PathType())
// })
// }
// }
func (suite *SharePointSelectorSuite) TestCategory_PathType() {
table := []struct {
cat sharePointCategory
pathType path.CategoryType
}{
{SharePointCategoryUnknown, path.UnknownCategory},
{SharePointSite, path.UnknownCategory},
{SharePointFolder, path.FilesCategory},
{SharePointItem, path.FilesCategory},
{SharePointFilterWebURL, path.FilesCategory},
}
for _, test := range table {
suite.T().Run(test.cat.String(), func(t *testing.T) {
assert.Equal(t, test.pathType, test.cat.PathType())
})
}
}