Add path constructor that takes a category (#743)

## Description

Will be useful for parts of graph connector code that are abstracted to
take a category and return collections. Does not work for exchange
events or contacts yet as those paths haven't been defined.

## Type of change

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

## Issue(s)
<!-- Can reference multiple issues. Use one of the following "magic words" - "closes, fixes" to auto-close the Github issue. -->

part of:
* #671 
* #456 

## Test Plan

<!-- How will this be tested prior to merging.-->

- [ ] 💪 Manual
- [x]  Unit test
- [ ] 💚 E2E
This commit is contained in:
ashmrtn 2022-09-02 13:18:05 -07:00 committed by GitHub
parent 12f61dd71c
commit 897a21ef0b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 84 additions and 11 deletions

View File

@ -198,6 +198,23 @@ func (pb Builder) ToDataLayerExchangeMailPath(tenant, user string, isItem bool)
}, nil }, nil
} }
func (pb Builder) ToDataLayerExchangePathForCategory(
tenant, user string,
category CategoryType,
isItem bool,
) (Path, error) {
if err := validateServiceAndCategory(ExchangeService, category); err != nil {
return nil, err
}
switch category {
case EmailCategory:
return pb.ToDataLayerExchangeMailPath(tenant, user, isItem)
default:
return nil, errors.New("not implemented")
}
}
// FromDataLayerPath parses the escaped path p, validates the elements in p // FromDataLayerPath parses the escaped path p, validates the elements in p
// match a resource-specific path format, and returns a Path struct for that // 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 // resource-specific type. If p does not match any resource-specific paths or
@ -219,7 +236,7 @@ func FromDataLayerPath(p string, isItem bool) (Path, error) {
return nil, errors.Errorf("path has too few segments: %s", p) return nil, errors.Errorf("path has too few segments: %s", p)
} }
service, category, err := validateServiceAndCategory( service, category, err := validateServiceAndCategoryStrings(
pb.elements[1], pb.elements[1],
pb.elements[3], pb.elements[3],
) )

View File

@ -4,8 +4,6 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
const unknownServiceCombination = "unknown service/category combination %q/%q"
type ServiceType int type ServiceType int
//go:generate stringer -type=ServiceType -linecomment //go:generate stringer -type=ServiceType -linecomment
@ -55,29 +53,39 @@ var serviceCategories = map[ServiceType]map[CategoryType]struct{}{
}, },
} }
func validateServiceAndCategory(s, c string) (ServiceType, CategoryType, error) { func validateServiceAndCategoryStrings(s, c string) (ServiceType, CategoryType, error) {
// Validity of service checked on first-level lookup to serviceCategories.
service := toServiceType(s) service := toServiceType(s)
if service == UnknownService {
return UnknownService, UnknownCategory, errors.Errorf("unknown service string %q", s)
}
category := ToCategoryType(c) category := ToCategoryType(c)
if category == UnknownCategory { if category == UnknownCategory {
return UnknownService, UnknownCategory, errors.Errorf("unknown category string %q", c) return UnknownService, UnknownCategory, errors.Errorf("unknown category string %q", c)
} }
if err := validateServiceAndCategory(service, category); err != nil {
return UnknownService, UnknownCategory, err
}
return service, category, nil
}
func validateServiceAndCategory(service ServiceType, category CategoryType) error {
cats, ok := serviceCategories[service] cats, ok := serviceCategories[service]
if !ok { if !ok {
return UnknownService, UnknownCategory, errors.Errorf("unknown service string %q", s) return errors.New("unsupported service")
} }
if _, ok := cats[category]; !ok { if _, ok := cats[category]; !ok {
return UnknownService, UnknownCategory, errors.Errorf( return errors.Errorf(
unknownServiceCombination, "unknown service/category combination %q/%q",
service, service,
category, category,
) )
} }
return service, category, nil return nil
} }
// dataLayerResourcePath allows callers to extract information from a // dataLayerResourcePath allows callers to extract information from a

View File

@ -122,6 +122,54 @@ func (suite *PopulatedDataLayerResourcePath) SetupSuite() {
suite.b = path.Builder{}.Append(rest...) suite.b = path.Builder{}.Append(rest...)
} }
func (suite *PopulatedDataLayerResourcePath) TestToExchangeMailPathForCategory() {
table := []struct {
category path.CategoryType
check assert.ErrorAssertionFunc
}{
{
category: path.UnknownCategory,
check: assert.Error,
},
{
category: path.CategoryType(-1),
check: assert.Error,
},
{
category: path.EmailCategory,
check: assert.NoError,
},
}
for _, m := range modes {
suite.T().Run(m.name, func(t1 *testing.T) {
for _, test := range table {
t1.Run(test.category.String(), func(t *testing.T) {
p, err := suite.b.ToDataLayerExchangePathForCategory(
testTenant,
testUser,
test.category,
m.isItem,
)
test.check(t, err)
if err != nil {
return
}
assert.Equal(t, testTenant, p.Tenant())
assert.Equal(t, path.ExchangeService, p.Service())
assert.Equal(t, test.category, p.Category())
assert.Equal(t, testUser, p.ResourceOwner())
assert.Equal(t, m.expectedFolder, p.Folder())
assert.Equal(t, m.expectedItem, p.Item())
})
}
})
}
}
func (suite *PopulatedDataLayerResourcePath) TestTenant() { func (suite *PopulatedDataLayerResourcePath) TestTenant() {
for _, m := range modes { for _, m := range modes {
suite.T().Run(m.name, func(t *testing.T) { suite.T().Run(m.name, func(t *testing.T) {

View File

@ -34,7 +34,7 @@ func (suite *ServiceCategoryUnitSuite) TestValidateServiceAndCategoryBadStringEr
} }
for _, test := range table { for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) { suite.T().Run(test.name, func(t *testing.T) {
_, _, err := validateServiceAndCategory(test.service, test.category) _, _, err := validateServiceAndCategoryStrings(test.service, test.category)
assert.Error(suite.T(), err) assert.Error(suite.T(), err)
}) })
} }
@ -100,7 +100,7 @@ func (suite *ServiceCategoryUnitSuite) TestValidateServiceAndCategory() {
} }
for _, test := range table { for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) { suite.T().Run(test.name, func(t *testing.T) {
s, c, err := validateServiceAndCategory(test.service, test.category) s, c, err := validateServiceAndCategoryStrings(test.service, test.category)
test.check(t, err) test.check(t, err)
if err != nil { if err != nil {