Create path categories for metadata folders (#1718)
## Description Corso needs to store some transient information between backups so that it can perform more efficient incremental backups. This transient information will live at a path `tenant-id/service/user-id/categoryMetadata`. This patch adds an initializer, category enums, and tests for these new path locations ## Type of change <!--- Please check the type of change your PR introduces: ---> - [x] 🌻 Feature - [ ] 🐛 Bugfix - [ ] 🗺️ Documentation - [ ] 🤖 Test - [ ] 💻 CI/Deployment - [ ] 🐹 Trivial/Minor ## Issue(s) * #1685 ## Test Plan <!-- How will this be tested prior to merging.--> - [ ] 💪 Manual - [x] ⚡ Unit test - [ ] 💚 E2E
This commit is contained in:
parent
24f60af404
commit
5c7d2168fc
@ -250,7 +250,7 @@ func (pb Builder) join(start, end int) string {
|
|||||||
return join(pb.elements[start:end])
|
return join(pb.elements[start:end])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pb Builder) verifyPrefix(tenant, resourceOwner string) error {
|
func verifyInputValues(tenant, resourceOwner string) error {
|
||||||
if len(tenant) == 0 {
|
if len(tenant) == 0 {
|
||||||
return errors.Wrap(errMissingSegment, "tenant")
|
return errors.Wrap(errMissingSegment, "tenant")
|
||||||
}
|
}
|
||||||
@ -259,6 +259,14 @@ func (pb Builder) verifyPrefix(tenant, resourceOwner string) error {
|
|||||||
return errors.Wrap(errMissingSegment, "resourceOwner")
|
return errors.Wrap(errMissingSegment, "resourceOwner")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pb Builder) verifyPrefix(tenant, resourceOwner string) error {
|
||||||
|
if err := verifyInputValues(tenant, resourceOwner); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if len(pb.elements) == 0 {
|
if len(pb.elements) == 0 {
|
||||||
return errors.New("missing path beyond prefix")
|
return errors.New("missing path beyond prefix")
|
||||||
}
|
}
|
||||||
@ -273,6 +281,48 @@ func (pb Builder) withPrefix(elements ...string) *Builder {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pb Builder) ToServiceCategoryMetadataPath(
|
||||||
|
tenant, user string,
|
||||||
|
service ServiceType,
|
||||||
|
category CategoryType,
|
||||||
|
isItem bool,
|
||||||
|
) (Path, error) {
|
||||||
|
if err := validateServiceAndCategory(service, category); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := verifyInputValues(tenant, user); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if isItem && len(pb.elements) == 0 {
|
||||||
|
return nil, errors.New("missing path beyond prefix")
|
||||||
|
}
|
||||||
|
|
||||||
|
metadataService := UnknownService
|
||||||
|
|
||||||
|
switch service {
|
||||||
|
case ExchangeService:
|
||||||
|
metadataService = ExchangeMetadataService
|
||||||
|
case OneDriveService:
|
||||||
|
metadataService = OneDriveMetadataService
|
||||||
|
case SharePointService:
|
||||||
|
metadataService = SharePointMetadataService
|
||||||
|
}
|
||||||
|
|
||||||
|
return &dataLayerResourcePath{
|
||||||
|
Builder: *pb.withPrefix(
|
||||||
|
tenant,
|
||||||
|
metadataService.String(),
|
||||||
|
user,
|
||||||
|
category.String(),
|
||||||
|
),
|
||||||
|
service: metadataService,
|
||||||
|
category: category,
|
||||||
|
hasItem: isItem,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (pb Builder) ToDataLayerExchangePathForCategory(
|
func (pb Builder) ToDataLayerExchangePathForCategory(
|
||||||
tenant, user string,
|
tenant, user string,
|
||||||
category CategoryType,
|
category CategoryType,
|
||||||
|
|||||||
@ -6,14 +6,27 @@ import (
|
|||||||
|
|
||||||
var ErrorUnknownService = errors.New("unknown service string")
|
var ErrorUnknownService = errors.New("unknown service string")
|
||||||
|
|
||||||
|
// ServiceType denotes what service the path corresponds to. Metadata services
|
||||||
|
// are also included though they are only used for paths that house metadata for
|
||||||
|
// Corso backups.
|
||||||
|
//
|
||||||
|
// Metadata services are not considered valid service types for resource paths
|
||||||
|
// though they can be used for metadata paths.
|
||||||
|
//
|
||||||
|
// The order of the enums below can be changed, but the string representation of
|
||||||
|
// each enum must remain the same or migration code needs to be added to handle
|
||||||
|
// changes to the string format.
|
||||||
type ServiceType int
|
type ServiceType int
|
||||||
|
|
||||||
//go:generate stringer -type=ServiceType -linecomment
|
//go:generate stringer -type=ServiceType -linecomment
|
||||||
const (
|
const (
|
||||||
UnknownService ServiceType = iota
|
UnknownService ServiceType = iota
|
||||||
ExchangeService // exchange
|
ExchangeService // exchange
|
||||||
OneDriveService // onedrive
|
OneDriveService // onedrive
|
||||||
SharePointService // sharepoint
|
SharePointService // sharepoint
|
||||||
|
ExchangeMetadataService // exchangeMetadata
|
||||||
|
OneDriveMetadataService // onedriveMetadata
|
||||||
|
SharePointMetadataService // sharepointMetadata
|
||||||
)
|
)
|
||||||
|
|
||||||
func toServiceType(service string) ServiceType {
|
func toServiceType(service string) ServiceType {
|
||||||
@ -24,6 +37,12 @@ func toServiceType(service string) ServiceType {
|
|||||||
return OneDriveService
|
return OneDriveService
|
||||||
case SharePointService.String():
|
case SharePointService.String():
|
||||||
return SharePointService
|
return SharePointService
|
||||||
|
case ExchangeMetadataService.String():
|
||||||
|
return ExchangeMetadataService
|
||||||
|
case OneDriveMetadataService.String():
|
||||||
|
return OneDriveMetadataService
|
||||||
|
case SharePointMetadataService.String():
|
||||||
|
return SharePointMetadataService
|
||||||
default:
|
default:
|
||||||
return UnknownService
|
return UnknownService
|
||||||
}
|
}
|
||||||
@ -31,6 +50,10 @@ func toServiceType(service string) ServiceType {
|
|||||||
|
|
||||||
var ErrorUnknownCategory = errors.New("unknown category string")
|
var ErrorUnknownCategory = errors.New("unknown category string")
|
||||||
|
|
||||||
|
// CategoryType denotes what category of data the path corresponds to. The order
|
||||||
|
// of the enums below can be changed, but the string representation of each enum
|
||||||
|
// must remain the same or migration code needs to be added to handle changes to
|
||||||
|
// the string format.
|
||||||
type CategoryType int
|
type CategoryType int
|
||||||
|
|
||||||
//go:generate stringer -type=CategoryType -linecomment
|
//go:generate stringer -type=CategoryType -linecomment
|
||||||
@ -63,7 +86,8 @@ func ToCategoryType(category string) CategoryType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// serviceCategories is a mapping of all valid service/category pairs.
|
// serviceCategories is a mapping of all valid service/category pairs for
|
||||||
|
// non-metadata paths.
|
||||||
var serviceCategories = map[ServiceType]map[CategoryType]struct{}{
|
var serviceCategories = map[ServiceType]map[CategoryType]struct{}{
|
||||||
ExchangeService: {
|
ExchangeService: {
|
||||||
EmailCategory: {},
|
EmailCategory: {},
|
||||||
|
|||||||
@ -233,6 +233,101 @@ func (suite *DataLayerResourcePath) TestDir() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *DataLayerResourcePath) TestToServiceCategoryMetadataPath() {
|
||||||
|
tenant := "a-tenant"
|
||||||
|
user := "a-user"
|
||||||
|
table := []struct {
|
||||||
|
name string
|
||||||
|
service path.ServiceType
|
||||||
|
category path.CategoryType
|
||||||
|
postfix []string
|
||||||
|
expectedService path.ServiceType
|
||||||
|
check assert.ErrorAssertionFunc
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "NoPostfixPasses",
|
||||||
|
service: path.ExchangeService,
|
||||||
|
category: path.EmailCategory,
|
||||||
|
expectedService: path.ExchangeMetadataService,
|
||||||
|
check: assert.NoError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "PostfixPasses",
|
||||||
|
service: path.ExchangeService,
|
||||||
|
category: path.EmailCategory,
|
||||||
|
postfix: []string{"a", "b"},
|
||||||
|
expectedService: path.ExchangeMetadataService,
|
||||||
|
check: assert.NoError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Fails",
|
||||||
|
service: path.ExchangeService,
|
||||||
|
category: path.FilesCategory,
|
||||||
|
check: assert.Error,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Passes",
|
||||||
|
service: path.ExchangeService,
|
||||||
|
category: path.ContactsCategory,
|
||||||
|
expectedService: path.ExchangeMetadataService,
|
||||||
|
check: assert.NoError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Passes",
|
||||||
|
service: path.ExchangeService,
|
||||||
|
category: path.EventsCategory,
|
||||||
|
expectedService: path.ExchangeMetadataService,
|
||||||
|
check: assert.NoError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Passes",
|
||||||
|
service: path.OneDriveService,
|
||||||
|
category: path.FilesCategory,
|
||||||
|
expectedService: path.OneDriveMetadataService,
|
||||||
|
check: assert.NoError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Passes",
|
||||||
|
service: path.SharePointService,
|
||||||
|
category: path.LibrariesCategory,
|
||||||
|
expectedService: path.SharePointMetadataService,
|
||||||
|
check: assert.NoError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Passes",
|
||||||
|
service: path.SharePointService,
|
||||||
|
category: path.ListsCategory,
|
||||||
|
expectedService: path.SharePointMetadataService,
|
||||||
|
check: assert.NoError,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range table {
|
||||||
|
suite.T().Run(strings.Join([]string{
|
||||||
|
test.name,
|
||||||
|
test.service.String(),
|
||||||
|
test.category.String(),
|
||||||
|
}, "_"), func(t *testing.T) {
|
||||||
|
pb := path.Builder{}.Append(test.postfix...)
|
||||||
|
p, err := pb.ToServiceCategoryMetadataPath(
|
||||||
|
tenant,
|
||||||
|
user,
|
||||||
|
test.service,
|
||||||
|
test.category,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
|
||||||
|
test.check(t, err)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, test.expectedService, p.Service())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (suite *DataLayerResourcePath) TestToExchangePathForCategory() {
|
func (suite *DataLayerResourcePath) TestToExchangePathForCategory() {
|
||||||
b := path.Builder{}.Append(rest...)
|
b := path.Builder{}.Append(rest...)
|
||||||
table := []struct {
|
table := []struct {
|
||||||
|
|||||||
@ -12,11 +12,14 @@ func _() {
|
|||||||
_ = x[ExchangeService-1]
|
_ = x[ExchangeService-1]
|
||||||
_ = x[OneDriveService-2]
|
_ = x[OneDriveService-2]
|
||||||
_ = x[SharePointService-3]
|
_ = x[SharePointService-3]
|
||||||
|
_ = x[ExchangeMetadataService-4]
|
||||||
|
_ = x[OneDriveMetadataService-5]
|
||||||
|
_ = x[SharePointMetadataService-6]
|
||||||
}
|
}
|
||||||
|
|
||||||
const _ServiceType_name = "UnknownServiceexchangeonedrivesharepoint"
|
const _ServiceType_name = "UnknownServiceexchangeonedrivesharepointexchangeMetadataonedriveMetadatasharepointMetadata"
|
||||||
|
|
||||||
var _ServiceType_index = [...]uint8{0, 14, 22, 30, 40}
|
var _ServiceType_index = [...]uint8{0, 14, 22, 30, 40, 56, 72, 90}
|
||||||
|
|
||||||
func (i ServiceType) String() string {
|
func (i ServiceType) String() string {
|
||||||
if i < 0 || i >= ServiceType(len(_ServiceType_index)-1) {
|
if i < 0 || i >= ServiceType(len(_ServiceType_index)-1) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user