introduce idnamer (#2934)
Adds a common interface: idNamer, which is used to pass around tuples of an id and a name for some resource. Also adds compliance to this iface in selectors, where a selector's ID and Name are the DiscreteOwner values. --- #### Does this PR need a docs update or release note? - [x] ⛔ No #### Type of change - [x] 🌻 Feature #### Issue(s) * #2825 #### Test Plan - [x] ⚡ Unit test - [x] 💚 E2E
This commit is contained in:
parent
9a8ec2505f
commit
99774e754b
9
src/internal/common/idname.go
Normal file
9
src/internal/common/idname.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
type IDNamer interface {
|
||||||
|
// the canonical id of the thing, generated and usable
|
||||||
|
// by whichever system has ownership of it.
|
||||||
|
ID() string
|
||||||
|
// the human-readable name of the thing.
|
||||||
|
Name() string
|
||||||
|
}
|
||||||
@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/alcionai/clues"
|
"github.com/alcionai/clues"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/internal/common"
|
||||||
"github.com/alcionai/corso/src/internal/connector/discovery"
|
"github.com/alcionai/corso/src/internal/connector/discovery"
|
||||||
"github.com/alcionai/corso/src/internal/connector/discovery/api"
|
"github.com/alcionai/corso/src/internal/connector/discovery/api"
|
||||||
"github.com/alcionai/corso/src/internal/connector/exchange"
|
"github.com/alcionai/corso/src/internal/connector/exchange"
|
||||||
@ -34,7 +35,7 @@ import (
|
|||||||
// prior history (ie, incrementals) and run a full backup.
|
// prior history (ie, incrementals) and run a full backup.
|
||||||
func (gc *GraphConnector) ProduceBackupCollections(
|
func (gc *GraphConnector) ProduceBackupCollections(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
ownerID, ownerName string,
|
owner common.IDNamer,
|
||||||
sels selectors.Selector,
|
sels selectors.Selector,
|
||||||
metadata []data.RestoreCollection,
|
metadata []data.RestoreCollection,
|
||||||
ctrlOpts control.Options,
|
ctrlOpts control.Options,
|
||||||
|
|||||||
@ -208,7 +208,7 @@ func (suite *ConnectorDataCollectionIntegrationSuite) TestDataCollections_invali
|
|||||||
|
|
||||||
collections, excludes, err := connector.ProduceBackupCollections(
|
collections, excludes, err := connector.ProduceBackupCollections(
|
||||||
ctx,
|
ctx,
|
||||||
owners[0], owners[0],
|
test.getSelector(t),
|
||||||
test.getSelector(t),
|
test.getSelector(t),
|
||||||
nil,
|
nil,
|
||||||
control.Options{},
|
control.Options{},
|
||||||
@ -340,7 +340,7 @@ func (suite *ConnectorCreateSharePointCollectionIntegrationSuite) TestCreateShar
|
|||||||
|
|
||||||
cols, excludes, err := gc.ProduceBackupCollections(
|
cols, excludes, err := gc.ProduceBackupCollections(
|
||||||
ctx,
|
ctx,
|
||||||
siteIDs[0], siteIDs[0],
|
sel.Selector,
|
||||||
sel.Selector,
|
sel.Selector,
|
||||||
nil,
|
nil,
|
||||||
control.Options{},
|
control.Options{},
|
||||||
@ -379,7 +379,7 @@ func (suite *ConnectorCreateSharePointCollectionIntegrationSuite) TestCreateShar
|
|||||||
|
|
||||||
cols, excludes, err := gc.ProduceBackupCollections(
|
cols, excludes, err := gc.ProduceBackupCollections(
|
||||||
ctx,
|
ctx,
|
||||||
siteIDs[0], siteIDs[0],
|
sel.Selector,
|
||||||
sel.Selector,
|
sel.Selector,
|
||||||
nil,
|
nil,
|
||||||
control.Options{},
|
control.Options{},
|
||||||
|
|||||||
@ -459,8 +459,7 @@ func runBackupAndCompare(
|
|||||||
start := time.Now()
|
start := time.Now()
|
||||||
dcs, excludes, err := backupGC.ProduceBackupCollections(
|
dcs, excludes, err := backupGC.ProduceBackupCollections(
|
||||||
ctx,
|
ctx,
|
||||||
backupSel.DiscreteOwner,
|
backupSel,
|
||||||
backupSel.DiscreteOwner,
|
|
||||||
backupSel,
|
backupSel,
|
||||||
nil,
|
nil,
|
||||||
config.opts,
|
config.opts,
|
||||||
@ -1000,8 +999,7 @@ func (suite *GraphConnectorIntegrationSuite) TestMultiFolderBackupDifferentNames
|
|||||||
|
|
||||||
dcs, excludes, err := backupGC.ProduceBackupCollections(
|
dcs, excludes, err := backupGC.ProduceBackupCollections(
|
||||||
ctx,
|
ctx,
|
||||||
backupSel.DiscreteOwner,
|
backupSel,
|
||||||
backupSel.DiscreteOwner,
|
|
||||||
backupSel,
|
backupSel,
|
||||||
nil,
|
nil,
|
||||||
control.Options{
|
control.Options{
|
||||||
@ -1154,8 +1152,7 @@ func (suite *GraphConnectorIntegrationSuite) TestBackup_CreatesPrefixCollections
|
|||||||
|
|
||||||
dcs, excludes, err := backupGC.ProduceBackupCollections(
|
dcs, excludes, err := backupGC.ProduceBackupCollections(
|
||||||
ctx,
|
ctx,
|
||||||
backupSel.DiscreteOwner,
|
backupSel,
|
||||||
backupSel.DiscreteOwner,
|
|
||||||
backupSel,
|
backupSel,
|
||||||
nil,
|
nil,
|
||||||
control.Options{
|
control.Options{
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package mockconnector
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/internal/common"
|
||||||
"github.com/alcionai/corso/src/internal/data"
|
"github.com/alcionai/corso/src/internal/data"
|
||||||
"github.com/alcionai/corso/src/pkg/account"
|
"github.com/alcionai/corso/src/pkg/account"
|
||||||
"github.com/alcionai/corso/src/pkg/backup/details"
|
"github.com/alcionai/corso/src/pkg/backup/details"
|
||||||
@ -24,7 +25,7 @@ type GraphConnector struct {
|
|||||||
|
|
||||||
func (gc GraphConnector) ProduceBackupCollections(
|
func (gc GraphConnector) ProduceBackupCollections(
|
||||||
_ context.Context,
|
_ context.Context,
|
||||||
_, _ string,
|
_ common.IDNamer,
|
||||||
_ selectors.Selector,
|
_ selectors.Selector,
|
||||||
_ []data.RestoreCollection,
|
_ []data.RestoreCollection,
|
||||||
_ control.Options,
|
_ control.Options,
|
||||||
|
|||||||
@ -33,8 +33,7 @@ import (
|
|||||||
type BackupOperation struct {
|
type BackupOperation struct {
|
||||||
operation
|
operation
|
||||||
|
|
||||||
ResourceOwner string `json:"resourceOwner"`
|
ResourceOwner common.IDNamer
|
||||||
ResourceOwnerName string `json:"resourceOwnerName"`
|
|
||||||
|
|
||||||
Results BackupResults `json:"results"`
|
Results BackupResults `json:"results"`
|
||||||
Selectors selectors.Selector `json:"selectors"`
|
Selectors selectors.Selector `json:"selectors"`
|
||||||
@ -63,22 +62,17 @@ func NewBackupOperation(
|
|||||||
bp inject.BackupProducer,
|
bp inject.BackupProducer,
|
||||||
acct account.Account,
|
acct account.Account,
|
||||||
selector selectors.Selector,
|
selector selectors.Selector,
|
||||||
ownerName string,
|
owner common.IDNamer,
|
||||||
bus events.Eventer,
|
bus events.Eventer,
|
||||||
) (BackupOperation, error) {
|
) (BackupOperation, error) {
|
||||||
op := BackupOperation{
|
op := BackupOperation{
|
||||||
operation: newOperation(opts, bus, kw, sw),
|
operation: newOperation(opts, bus, kw, sw),
|
||||||
ResourceOwner: selector.DiscreteOwner,
|
ResourceOwner: owner,
|
||||||
ResourceOwnerName: ownerName,
|
Selectors: selector,
|
||||||
Selectors: selector,
|
Version: "v0",
|
||||||
Version: "v0",
|
account: acct,
|
||||||
account: acct,
|
incremental: useIncrementalBackup(selector, opts),
|
||||||
incremental: useIncrementalBackup(selector, opts),
|
bp: bp,
|
||||||
bp: bp,
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(ownerName) == 0 {
|
|
||||||
op.ResourceOwnerName = op.ResourceOwner
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := op.validate(); err != nil {
|
if err := op.validate(); err != nil {
|
||||||
@ -89,10 +83,14 @@ func NewBackupOperation(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (op BackupOperation) validate() error {
|
func (op BackupOperation) validate() error {
|
||||||
if len(op.ResourceOwner) == 0 {
|
if op.ResourceOwner == nil {
|
||||||
return clues.New("backup requires a resource owner")
|
return clues.New("backup requires a resource owner")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(op.ResourceOwner.ID()) == 0 {
|
||||||
|
return clues.New("backup requires a resource owner with a populated ID")
|
||||||
|
}
|
||||||
|
|
||||||
if op.bp == nil {
|
if op.bp == nil {
|
||||||
return clues.New("missing backup producer")
|
return clues.New("missing backup producer")
|
||||||
}
|
}
|
||||||
@ -165,7 +163,7 @@ func (op *BackupOperation) Run(ctx context.Context) (err error) {
|
|||||||
// Execution
|
// Execution
|
||||||
// -----
|
// -----
|
||||||
|
|
||||||
observe.Message(ctx, "Backing Up", observe.Bullet, clues.Hide(op.ResourceOwner))
|
observe.Message(ctx, "Backing Up", observe.Bullet, clues.Hide(op.ResourceOwner.Name()))
|
||||||
|
|
||||||
deets, err := op.do(
|
deets, err := op.do(
|
||||||
ctx,
|
ctx,
|
||||||
@ -253,7 +251,6 @@ func (op *BackupOperation) do(
|
|||||||
ctx,
|
ctx,
|
||||||
op.bp,
|
op.bp,
|
||||||
op.ResourceOwner,
|
op.ResourceOwner,
|
||||||
op.ResourceOwnerName,
|
|
||||||
op.Selectors,
|
op.Selectors,
|
||||||
mdColls,
|
mdColls,
|
||||||
op.Options,
|
op.Options,
|
||||||
@ -327,7 +324,7 @@ func useIncrementalBackup(sel selectors.Selector, opts control.Options) bool {
|
|||||||
func produceBackupDataCollections(
|
func produceBackupDataCollections(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
bp inject.BackupProducer,
|
bp inject.BackupProducer,
|
||||||
ownerID, ownerName string,
|
resourceOwner common.IDNamer,
|
||||||
sel selectors.Selector,
|
sel selectors.Selector,
|
||||||
metadata []data.RestoreCollection,
|
metadata []data.RestoreCollection,
|
||||||
ctrlOpts control.Options,
|
ctrlOpts control.Options,
|
||||||
@ -340,7 +337,7 @@ func produceBackupDataCollections(
|
|||||||
closer()
|
closer()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return bp.ProduceBackupCollections(ctx, ownerID, ownerName, sel, metadata, ctrlOpts, errs)
|
return bp.ProduceBackupCollections(ctx, resourceOwner, sel, metadata, ctrlOpts, errs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@ -717,8 +714,8 @@ func (op *BackupOperation) createBackupModels(
|
|||||||
op.Status.String(),
|
op.Status.String(),
|
||||||
backupID,
|
backupID,
|
||||||
op.Selectors,
|
op.Selectors,
|
||||||
op.ResourceOwner,
|
op.ResourceOwner.ID(),
|
||||||
op.ResourceOwnerName,
|
op.ResourceOwner.Name(),
|
||||||
op.Results.ReadWrites,
|
op.Results.ReadWrites,
|
||||||
op.Results.StartAndEndTime,
|
op.Results.StartAndEndTime,
|
||||||
op.Errors.Errors())
|
op.Errors.Errors())
|
||||||
|
|||||||
@ -154,7 +154,7 @@ func newTestBackupOp(
|
|||||||
|
|
||||||
opts.ToggleFeatures = featureToggles
|
opts.ToggleFeatures = featureToggles
|
||||||
|
|
||||||
bo, err := NewBackupOperation(ctx, opts, kw, sw, gc, acct, sel, sel.DiscreteOwner, bus)
|
bo, err := NewBackupOperation(ctx, opts, kw, sw, gc, acct, sel, sel, bus)
|
||||||
if !assert.NoError(t, err, clues.ToCore(err)) {
|
if !assert.NoError(t, err, clues.ToCore(err)) {
|
||||||
closer()
|
closer()
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
@ -566,6 +566,8 @@ func (suite *BackupOpIntegrationSuite) TestNewBackupOperation() {
|
|||||||
ctx, flush := tester.NewContext()
|
ctx, flush := tester.NewContext()
|
||||||
defer flush()
|
defer flush()
|
||||||
|
|
||||||
|
sel := selectors.Selector{DiscreteOwner: "test"}
|
||||||
|
|
||||||
_, err := NewBackupOperation(
|
_, err := NewBackupOperation(
|
||||||
ctx,
|
ctx,
|
||||||
test.opts,
|
test.opts,
|
||||||
@ -573,8 +575,8 @@ func (suite *BackupOpIntegrationSuite) TestNewBackupOperation() {
|
|||||||
test.sw,
|
test.sw,
|
||||||
test.bp,
|
test.bp,
|
||||||
test.acct,
|
test.acct,
|
||||||
selectors.Selector{DiscreteOwner: "test"},
|
sel,
|
||||||
"test-name",
|
sel,
|
||||||
evmock.NewBus())
|
evmock.NewBus())
|
||||||
test.errCheck(suite.T(), err, clues.ToCore(err))
|
test.errCheck(suite.T(), err, clues.ToCore(err))
|
||||||
})
|
})
|
||||||
|
|||||||
@ -415,7 +415,7 @@ func (suite *BackupOpUnitSuite) TestBackupOperation_PersistResults() {
|
|||||||
gc,
|
gc,
|
||||||
acct,
|
acct,
|
||||||
sel,
|
sel,
|
||||||
sel.DiscreteOwner,
|
sel,
|
||||||
evmock.NewBus())
|
evmock.NewBus())
|
||||||
require.NoError(t, err, clues.ToCore(err))
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package inject
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/internal/common"
|
||||||
"github.com/alcionai/corso/src/internal/data"
|
"github.com/alcionai/corso/src/internal/data"
|
||||||
"github.com/alcionai/corso/src/internal/kopia"
|
"github.com/alcionai/corso/src/internal/kopia"
|
||||||
"github.com/alcionai/corso/src/pkg/account"
|
"github.com/alcionai/corso/src/pkg/account"
|
||||||
@ -17,7 +18,7 @@ type (
|
|||||||
BackupProducer interface {
|
BackupProducer interface {
|
||||||
ProduceBackupCollections(
|
ProduceBackupCollections(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
ownerID, ownerName string,
|
resourceOwner common.IDNamer,
|
||||||
sels selectors.Selector,
|
sels selectors.Selector,
|
||||||
metadata []data.RestoreCollection,
|
metadata []data.RestoreCollection,
|
||||||
ctrlOpts control.Options,
|
ctrlOpts control.Options,
|
||||||
|
|||||||
@ -293,7 +293,7 @@ func setupExchangeBackup(
|
|||||||
gc,
|
gc,
|
||||||
acct,
|
acct,
|
||||||
bsel.Selector,
|
bsel.Selector,
|
||||||
bsel.Selector.DiscreteOwner,
|
bsel.Selector,
|
||||||
evmock.NewBus())
|
evmock.NewBus())
|
||||||
require.NoError(t, err, clues.ToCore(err))
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
|
|
||||||
@ -350,7 +350,7 @@ func setupSharePointBackup(
|
|||||||
gc,
|
gc,
|
||||||
acct,
|
acct,
|
||||||
spsel.Selector,
|
spsel.Selector,
|
||||||
spsel.Selector.DiscreteOwner,
|
spsel.Selector,
|
||||||
evmock.NewBus())
|
evmock.NewBus())
|
||||||
require.NoError(t, err, clues.ToCore(err))
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
|
|
||||||
|
|||||||
@ -296,6 +296,9 @@ func (r repository) NewBackup(
|
|||||||
return operations.BackupOperation{}, errors.Wrap(err, "connecting to m365")
|
return operations.BackupOperation{}, errors.Wrap(err, "connecting to m365")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: retrieve display name from gc
|
||||||
|
sel = sel.SetDiscreteOwnerIDName(sel.DiscreteOwner, "")
|
||||||
|
|
||||||
return operations.NewBackupOperation(
|
return operations.NewBackupOperation(
|
||||||
ctx,
|
ctx,
|
||||||
r.Opts,
|
r.Opts,
|
||||||
@ -304,7 +307,7 @@ func (r repository) NewBackup(
|
|||||||
gc,
|
gc,
|
||||||
r.Account,
|
r.Account,
|
||||||
sel,
|
sel,
|
||||||
sel.DiscreteOwner,
|
sel,
|
||||||
r.Bus)
|
r.Bus)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -112,6 +112,8 @@ type Selector struct {
|
|||||||
// iterate over the results, where each one will populate this field
|
// iterate over the results, where each one will populate this field
|
||||||
// with a different owner.
|
// with a different owner.
|
||||||
DiscreteOwner string `json:"discreteOwner,omitempty"`
|
DiscreteOwner string `json:"discreteOwner,omitempty"`
|
||||||
|
// display name for the DiscreteOwner.
|
||||||
|
DiscreteOwnerName string `json:"discreteOwnerName,omitempty"`
|
||||||
|
|
||||||
// A slice of exclusion scopes. Exclusions apply globally to all
|
// A slice of exclusion scopes. Exclusions apply globally to all
|
||||||
// inclusions/filters, with any-match behavior.
|
// inclusions/filters, with any-match behavior.
|
||||||
@ -146,6 +148,48 @@ func (s Selector) DiscreteResourceOwners() []string {
|
|||||||
return split(s.ResourceOwners.Target)
|
return split(s.ResourceOwners.Target)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetDiscreteOwnerIDName ensures the selector has the correct discrete owner
|
||||||
|
// id and name. Assumes that these values are sourced using the current
|
||||||
|
// s.DiscreteOwner as input. The reason for taking in both the id and name, and
|
||||||
|
// not just the name, is so that constructors can input owner aliases in place
|
||||||
|
// of ids, with the expectation that the two will get sorted and re-written
|
||||||
|
// later on with this setter.
|
||||||
|
//
|
||||||
|
// If the id is empty, the original DiscreteOwner value is retained.
|
||||||
|
// If the name is empty, the id is duplicated as the name.
|
||||||
|
func (s Selector) SetDiscreteOwnerIDName(id, name string) Selector {
|
||||||
|
r := s
|
||||||
|
|
||||||
|
if len(id) == 0 {
|
||||||
|
// assume a the discreteOwner is already set, and don't replace anything.
|
||||||
|
id = s.DiscreteOwner
|
||||||
|
}
|
||||||
|
|
||||||
|
r.DiscreteOwner = id
|
||||||
|
r.DiscreteOwnerName = name
|
||||||
|
|
||||||
|
if len(name) == 0 {
|
||||||
|
r.DiscreteOwnerName = id
|
||||||
|
}
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID returns s.discreteOwner, which is assumed to be a stable ID.
|
||||||
|
func (s Selector) ID() string {
|
||||||
|
return s.DiscreteOwner
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name returns s.discreteOwnerName. If that value is empty, it returns
|
||||||
|
// s.DiscreteOwner instead.
|
||||||
|
func (s Selector) Name() string {
|
||||||
|
if len(s.DiscreteOwnerName) == 0 {
|
||||||
|
return s.DiscreteOwner
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.DiscreteOwnerName
|
||||||
|
}
|
||||||
|
|
||||||
// isAnyResourceOwner returns true if the selector includes all resource owners.
|
// isAnyResourceOwner returns true if the selector includes all resource owners.
|
||||||
func isAnyResourceOwner(s Selector) bool {
|
func isAnyResourceOwner(s Selector) bool {
|
||||||
return s.ResourceOwners.Comparator == filters.Passes
|
return s.ResourceOwners.Comparator == filters.Passes
|
||||||
@ -336,7 +380,7 @@ func pathCategoriesIn[T scopeT, C categoryT](ss []scope) []path.CategoryType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// scope helpers
|
// scope constructors
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
type scopeConfig struct {
|
type scopeConfig struct {
|
||||||
|
|||||||
@ -248,6 +248,49 @@ func (suite *SelectorSuite) TestSplitByResourceOnwer() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *SelectorSuite) TestIDName() {
|
||||||
|
table := []struct {
|
||||||
|
title string
|
||||||
|
id, name string
|
||||||
|
expectID, expectName string
|
||||||
|
}{
|
||||||
|
{"empty", "", "", "", ""},
|
||||||
|
{"only id", "id", "", "id", "id"},
|
||||||
|
{"only name", "", "name", "", "name"},
|
||||||
|
{"both", "id", "name", "id", "name"},
|
||||||
|
}
|
||||||
|
for _, test := range table {
|
||||||
|
suite.Run(test.title, func() {
|
||||||
|
sel := Selector{DiscreteOwner: test.id, DiscreteOwnerName: test.name}
|
||||||
|
assert.Equal(suite.T(), test.expectID, sel.ID())
|
||||||
|
assert.Equal(suite.T(), test.expectName, sel.Name())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *SelectorSuite) TestSetDiscreteOwnerIDName() {
|
||||||
|
table := []struct {
|
||||||
|
title string
|
||||||
|
initID, initName string
|
||||||
|
id, name string
|
||||||
|
expectID, expectName string
|
||||||
|
}{
|
||||||
|
{"empty", "", "", "", "", "", ""},
|
||||||
|
{"only id", "", "", "id", "", "id", "id"},
|
||||||
|
{"only name", "", "", "", "", "", ""},
|
||||||
|
{"both", "", "", "id", "name", "id", "name"},
|
||||||
|
{"both", "init-id", "", "", "name", "init-id", "name"},
|
||||||
|
}
|
||||||
|
for _, test := range table {
|
||||||
|
suite.Run(test.title, func() {
|
||||||
|
sel := Selector{DiscreteOwner: test.initID, DiscreteOwnerName: test.initName}
|
||||||
|
sel = sel.SetDiscreteOwnerIDName(test.id, test.name)
|
||||||
|
assert.Equal(suite.T(), test.expectID, sel.ID())
|
||||||
|
assert.Equal(suite.T(), test.expectName, sel.Name())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestPathCategories verifies that no scope produces a `path.UnknownCategory`
|
// TestPathCategories verifies that no scope produces a `path.UnknownCategory`
|
||||||
func (suite *SelectorSuite) TestPathCategories_includes() {
|
func (suite *SelectorSuite) TestPathCategories_includes() {
|
||||||
users := []string{"someuser@onmicrosoft.com"}
|
users := []string{"someuser@onmicrosoft.com"}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user