corso/src/pkg/selectors/teamsChats_test.go
ryanfkeepers 14817de592 get details working (and other cleanup)
details wasn't properly listing backed up items.  This fixes
the details display, and contains some code clean-up that occurred
along the way.
2024-01-24 15:17:14 -07:00

844 lines
20 KiB
Go

package selectors
import (
"strings"
"testing"
"time"
"github.com/alcionai/clues"
"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/fault"
"github.com/alcionai/corso/src/pkg/filters"
"github.com/alcionai/corso/src/pkg/path"
)
type TeamsChatsSelectorSuite struct {
tester.Suite
}
func TestTeamsChatsSelectorSuite(t *testing.T) {
suite.Run(t, &TeamsChatsSelectorSuite{Suite: tester.NewUnitSuite(t)})
}
func (suite *TeamsChatsSelectorSuite) TestNewTeamsChatsBackup() {
t := suite.T()
eb := NewTeamsChatsBackup(nil)
assert.Equal(t, eb.Service, ServiceTeamsChats)
assert.NotZero(t, eb.Scopes())
}
func (suite *TeamsChatsSelectorSuite) TestToTeamsChatsBackup() {
t := suite.T()
eb := NewTeamsChatsBackup(nil)
s := eb.Selector
eb, err := s.ToTeamsChatsBackup()
require.NoError(t, err, clues.ToCore(err))
assert.Equal(t, eb.Service, ServiceTeamsChats)
assert.NotZero(t, eb.Scopes())
}
func (suite *TeamsChatsSelectorSuite) TestNewTeamsChatsRestore() {
t := suite.T()
er := NewTeamsChatsRestore(nil)
assert.Equal(t, er.Service, ServiceTeamsChats)
assert.NotZero(t, er.Scopes())
}
func (suite *TeamsChatsSelectorSuite) TestToTeamsChatsRestore() {
t := suite.T()
eb := NewTeamsChatsRestore(nil)
s := eb.Selector
eb, err := s.ToTeamsChatsRestore()
require.NoError(t, err, clues.ToCore(err))
assert.Equal(t, eb.Service, ServiceTeamsChats)
assert.NotZero(t, eb.Scopes())
}
func (suite *TeamsChatsSelectorSuite) TestTeamsChatsSelector_Exclude_TeamsChats() {
t := suite.T()
const (
user = "user"
folder = AnyTgt
c1 = "c1"
c2 = "c2"
)
sel := NewTeamsChatsBackup([]string{user})
sel.Exclude(sel.Chats([]string{c1, c2}))
scopes := sel.Excludes
require.Len(t, scopes, 1)
scopeMustHave(
t,
TeamsChatsScope(scopes[0]),
map[categorizer][]string{
TeamsChatsChat: {c1, c2},
})
}
func (suite *TeamsChatsSelectorSuite) TestTeamsChatsSelector_Include_TeamsChats() {
t := suite.T()
const (
user = "user"
folder = AnyTgt
c1 = "c1"
c2 = "c2"
)
sel := NewTeamsChatsBackup([]string{user})
sel.Include(sel.Chats([]string{c1, c2}))
scopes := sel.Includes
require.Len(t, scopes, 1)
scopeMustHave(
t,
TeamsChatsScope(scopes[0]),
map[categorizer][]string{
TeamsChatsChat: {c1, c2},
})
assert.Equal(t, sel.Scopes()[0].Category(), TeamsChatsChat)
}
func (suite *TeamsChatsSelectorSuite) TestTeamsChatsSelector_Exclude_AllData() {
t := suite.T()
const (
u1 = "u1"
u2 = "u2"
)
sel := NewTeamsChatsBackup([]string{u1, u2})
sel.Exclude(sel.AllData())
scopes := sel.Excludes
require.Len(t, scopes, 1)
for _, sc := range scopes {
if sc[scopeKeyCategory].Compare(TeamsChatsChat.String()) {
scopeMustHave(
t,
TeamsChatsScope(sc),
map[categorizer][]string{
TeamsChatsChat: Any(),
})
}
}
}
func (suite *TeamsChatsSelectorSuite) TestTeamsChatsSelector_Include_AllData() {
t := suite.T()
const (
u1 = "u1"
u2 = "u2"
)
sel := NewTeamsChatsBackup([]string{u1, u2})
sel.Include(sel.AllData())
scopes := sel.Includes
require.Len(t, scopes, 1)
for _, sc := range scopes {
if sc[scopeKeyCategory].Compare(TeamsChatsChat.String()) {
scopeMustHave(
t,
TeamsChatsScope(sc),
map[categorizer][]string{
TeamsChatsChat: Any(),
})
}
}
}
func (suite *TeamsChatsSelectorSuite) TestTeamsChatsBackup_Scopes() {
eb := NewTeamsChatsBackup(Any())
eb.Include(eb.AllData())
scopes := eb.Scopes()
assert.Len(suite.T(), scopes, 1)
for _, sc := range scopes {
cat := sc.Category()
suite.Run(cat.String(), func() {
t := suite.T()
switch sc.Category() {
case TeamsChatsChat:
assert.True(t, sc.IsAny(TeamsChatsChat))
}
})
}
}
func (suite *TeamsChatsSelectorSuite) TestTeamsChatsScope_Category() {
table := []struct {
is teamsChatsCategory
expect teamsChatsCategory
check assert.ComparisonAssertionFunc
}{
{TeamsChatsCategoryUnknown, TeamsChatsCategoryUnknown, assert.Equal},
{TeamsChatsCategoryUnknown, TeamsChatsUser, assert.NotEqual},
{TeamsChatsChat, TeamsChatsChat, assert.Equal},
{TeamsChatsUser, TeamsChatsUser, assert.Equal},
{TeamsChatsUser, TeamsChatsCategoryUnknown, assert.NotEqual},
}
for _, test := range table {
suite.Run(test.is.String()+test.expect.String(), func() {
eb := NewTeamsChatsBackup(Any())
eb.Includes = []scope{
{scopeKeyCategory: filters.Identity(test.is.String())},
}
scope := eb.Scopes()[0]
test.check(suite.T(), test.expect, scope.Category())
})
}
}
func (suite *TeamsChatsSelectorSuite) TestTeamsChatsScope_IncludesCategory() {
table := []struct {
is teamsChatsCategory
expect teamsChatsCategory
check assert.BoolAssertionFunc
}{
{TeamsChatsCategoryUnknown, TeamsChatsCategoryUnknown, assert.False},
{TeamsChatsCategoryUnknown, TeamsChatsUser, assert.True},
{TeamsChatsUser, TeamsChatsUser, assert.True},
{TeamsChatsUser, TeamsChatsCategoryUnknown, assert.True},
}
for _, test := range table {
suite.Run(test.is.String()+test.expect.String(), func() {
eb := NewTeamsChatsBackup(Any())
eb.Includes = []scope{
{scopeKeyCategory: filters.Identity(test.is.String())},
}
scope := eb.Scopes()[0]
test.check(suite.T(), scope.IncludesCategory(test.expect))
})
}
}
func (suite *TeamsChatsSelectorSuite) TestTeamsChatsScope_Get() {
eb := NewTeamsChatsBackup(Any())
eb.Include(eb.AllData())
scopes := eb.Scopes()
table := []teamsChatsCategory{
TeamsChatsChat,
}
for _, test := range table {
suite.Run(test.String(), func() {
t := suite.T()
for _, sc := range scopes {
switch sc.Category() {
case TeamsChatsChat:
assert.Equal(t, Any(), sc.Get(TeamsChatsChat))
}
assert.Equal(t, None(), sc.Get(TeamsChatsCategoryUnknown))
}
})
}
}
func (suite *TeamsChatsSelectorSuite) TestTeamsChatsScope_MatchesInfo() {
cs := NewTeamsChatsRestore(Any())
const (
name = "smarf mcfnords"
member = "cooks@2many.smarf"
subject = "I have seen the fnords!"
)
var (
now = time.Now()
future = now.Add(1 * time.Minute)
)
infoWith := func(itype details.ItemType) details.ItemInfo {
return details.ItemInfo{
TeamsChats: &details.TeamsChatsInfo{
ItemType: itype,
Chat: details.ChatInfo{
CreatedAt: now,
HasExternalMembers: false,
LastMessageAt: future,
LastMessagePreview: "preview",
Members: []string{member},
MessageCount: 1,
Topic: name,
},
},
}
}
table := []struct {
name string
itype details.ItemType
scope []TeamsChatsScope
expect assert.BoolAssertionFunc
}{
{"chat with a different member", details.TeamsChat, cs.ChatMember("blarps"), assert.False},
{"chat with the same member", details.TeamsChat, cs.ChatMember(member), assert.True},
{"chat with a member submatch search", details.TeamsChat, cs.ChatMember(member[2:5]), assert.True},
{"chat with a different name", details.TeamsChat, cs.ChatName("blarps"), assert.False},
{"chat with the same name", details.TeamsChat, cs.ChatName(name), assert.True},
{"chat with a subname search", details.TeamsChat, cs.ChatName(name[2:5]), assert.True},
}
for _, test := range table {
suite.Run(test.name, func() {
t := suite.T()
scopes := setScopesToDefault(test.scope)
for _, scope := range scopes {
test.expect(t, scope.matchesInfo(infoWith(test.itype)))
}
})
}
}
func (suite *TeamsChatsSelectorSuite) TestTeamsChatsScope_MatchesPath() {
const (
user = "userID"
chat = "chatID"
)
repoRef, err := path.Build("tid", user, path.TeamsChatsService, path.ChatsCategory, true, chat)
require.NoError(suite.T(), err, clues.ToCore(err))
var (
loc = strings.Join([]string{chat}, "/")
short = "thisisahashofsomekind"
cs = NewTeamsChatsRestore(Any())
ent = details.Entry{
RepoRef: repoRef.String(),
ShortRef: short,
ItemRef: chat,
LocationRef: loc,
}
)
table := []struct {
name string
scope []TeamsChatsScope
shortRef string
expect assert.BoolAssertionFunc
}{
{"all items", cs.AllData(), "", assert.True},
{"all chats", cs.Chats(Any()), "", assert.True},
{"no chats", cs.Chats(None()), "", assert.False},
{"matching chats", cs.Chats([]string{chat}), "", assert.True},
{"non-matching chats", cs.Chats([]string{"smarf"}), "", assert.False},
{"one of multiple chats", cs.Chats([]string{"smarf", chat}), "", assert.True},
{"chats short ref", cs.Chats([]string{short}), short, assert.True},
{"non-leaf short ref", cs.Chats([]string{"foo"}), short, assert.False},
}
for _, test := range table {
suite.Run(test.name, func() {
t := suite.T()
scopes := setScopesToDefault(test.scope)
var aMatch bool
for _, scope := range scopes {
pvs, err := TeamsChatsChat.pathValues(repoRef, ent, Config{})
require.NoError(t, err)
if matchesPathValues(scope, TeamsChatsChat, pvs) {
aMatch = true
break
}
}
test.expect(t, aMatch)
})
}
}
func (suite *TeamsChatsSelectorSuite) TestTeamsChatsRestore_Reduce() {
chat, err := path.Build("tid", "uid", path.TeamsChatsService, path.ChatsCategory, true, "cid")
require.NoError(suite.T(), err, clues.ToCore(err))
toRR := func(p path.Path) string {
newElems := []string{}
for _, e := range p.Folders() {
newElems = append(newElems, e+".d")
}
joinedFldrs := strings.Join(newElems, "/")
return stubRepoRef(p.Service(), p.Category(), p.ProtectedResource(), joinedFldrs, p.Item())
}
makeDeets := func(refs ...path.Path) *details.Details {
deets := &details.Details{
DetailsModel: details.DetailsModel{
Entries: []details.Entry{},
},
}
for _, r := range refs {
itype := details.UnknownType
switch r {
case chat:
itype = details.TeamsChat
}
deets.Entries = append(deets.Entries, details.Entry{
RepoRef: toRR(r),
// Don't escape because we assume nice paths.
LocationRef: r.Folder(false),
ItemInfo: details.ItemInfo{
TeamsChats: &details.TeamsChatsInfo{
ItemType: itype,
},
},
})
}
return deets
}
table := []struct {
name string
deets *details.Details
makeSelector func() *TeamsChatsRestore
expect []string
}{
{
"no refs",
makeDeets(),
func() *TeamsChatsRestore {
er := NewTeamsChatsRestore(Any())
er.Include(er.AllData())
return er
},
[]string{},
},
{
"chat only",
makeDeets(chat),
func() *TeamsChatsRestore {
er := NewTeamsChatsRestore(Any())
er.Include(er.AllData())
return er
},
[]string{toRR(chat)},
},
}
for _, test := range table {
suite.Run(test.name, func() {
t := suite.T()
ctx, flush := tester.NewContext(t)
defer flush()
sel := test.makeSelector()
results := sel.Reduce(ctx, test.deets, fault.New(true))
paths := results.Paths()
assert.Equal(t, test.expect, paths)
})
}
}
func (suite *TeamsChatsSelectorSuite) TestTeamsChatsRestore_Reduce_locationRef() {
var (
chat = stubRepoRef(path.TeamsChatsService, path.ChatsCategory, "uid", "", "cid")
chatLocation = "chatname"
)
makeDeets := func(refs ...string) *details.Details {
deets := &details.Details{
DetailsModel: details.DetailsModel{
Entries: []details.Entry{},
},
}
for _, r := range refs {
var (
location string
itype = details.UnknownType
)
switch r {
case chat:
itype = details.TeamsChat
location = chatLocation
}
deets.Entries = append(deets.Entries, details.Entry{
RepoRef: r,
LocationRef: location,
ItemInfo: details.ItemInfo{
TeamsChats: &details.TeamsChatsInfo{
ItemType: itype,
},
},
})
}
return deets
}
arr := func(s ...string) []string {
return s
}
table := []struct {
name string
deets *details.Details
makeSelector func() *TeamsChatsRestore
expect []string
}{
{
"no refs",
makeDeets(),
func() *TeamsChatsRestore {
er := NewTeamsChatsRestore(Any())
er.Include(er.AllData())
return er
},
[]string{},
},
{
"chat only",
makeDeets(chat),
func() *TeamsChatsRestore {
er := NewTeamsChatsRestore(Any())
er.Include(er.AllData())
return er
},
arr(chat),
},
}
for _, test := range table {
suite.Run(test.name, func() {
t := suite.T()
ctx, flush := tester.NewContext(t)
defer flush()
sel := test.makeSelector()
results := sel.Reduce(ctx, test.deets, fault.New(true))
paths := results.Paths()
assert.Equal(t, test.expect, paths)
})
}
}
func (suite *TeamsChatsSelectorSuite) TestScopesByCategory() {
var (
cs = NewTeamsChatsRestore(Any())
teamsChats = cs.Chats(Any())
)
type expect struct {
chat int
}
type input []scope
makeInput := func(cs ...[]TeamsChatsScope) []scope {
mss := []scope{}
for _, sl := range cs {
for _, s := range sl {
mss = append(mss, scope(s))
}
}
return mss
}
cats := map[path.CategoryType]teamsChatsCategory{
path.ChatsCategory: TeamsChatsChat,
}
table := []struct {
name string
scopes input
expect expect
}{
{"teamsChats only", makeInput(teamsChats), expect{1}},
}
for _, test := range table {
suite.Run(test.name, func() {
t := suite.T()
result := scopesByCategory[TeamsChatsScope](test.scopes, cats, false)
assert.Len(t, result[TeamsChatsChat], test.expect.chat)
})
}
}
func (suite *TeamsChatsSelectorSuite) TestPasses() {
const (
chatID = "chatID"
cat = TeamsChatsChat
)
short := "thisisahashofsomekind"
entry := details.Entry{
ShortRef: short,
ItemRef: chatID,
}
repoRef, err := path.Build("tid", "user", path.TeamsChatsService, path.ChatsCategory, true, chatID)
require.NoError(suite.T(), err, clues.ToCore(err))
var (
cs = NewTeamsChatsRestore(Any())
otherChat = setScopesToDefault(cs.Chats([]string{"smarf"}))
chat = setScopesToDefault(cs.Chats([]string{chatID}))
noChat = setScopesToDefault(cs.Chats(None()))
allChats = setScopesToDefault(cs.Chats(Any()))
ent = details.Entry{
RepoRef: repoRef.String(),
}
)
table := []struct {
name string
excludes, filters, includes []TeamsChatsScope
expect assert.BoolAssertionFunc
}{
{"empty", nil, nil, nil, assert.False},
{"in Chat", nil, nil, chat, assert.True},
{"in Other", nil, nil, otherChat, assert.False},
{"in no Chat", nil, nil, noChat, assert.False},
{"ex None filter chat", allChats, chat, nil, assert.False},
{"ex Chat", chat, nil, allChats, assert.False},
{"ex Other", otherChat, nil, allChats, assert.True},
{"in and ex Chat", chat, nil, chat, assert.False},
{"filter Chat", nil, chat, allChats, assert.True},
{"filter Other", nil, otherChat, allChats, assert.False},
}
for _, test := range table {
suite.Run(test.name, func() {
t := suite.T()
pvs, err := cat.pathValues(repoRef, ent, Config{})
require.NoError(t, err)
result := passes(
cat,
pvs,
entry,
test.excludes,
test.filters,
test.includes)
test.expect(t, result)
})
}
}
func (suite *TeamsChatsSelectorSuite) TestContains() {
target := "fnords"
var (
cs = NewTeamsChatsRestore(Any())
noChat = setScopesToDefault(cs.Chats(None()))
does = setScopesToDefault(cs.Chats([]string{target}))
doesNot = setScopesToDefault(cs.Chats([]string{"smarf"}))
)
table := []struct {
name string
scopes []TeamsChatsScope
expect assert.BoolAssertionFunc
}{
{"no chat", noChat, assert.False},
{"does contain", does, assert.True},
{"does not contain", doesNot, assert.False},
}
for _, test := range table {
suite.Run(test.name, func() {
t := suite.T()
var result bool
for _, scope := range test.scopes {
if scope.Matches(TeamsChatsChat, target) {
result = true
break
}
}
test.expect(t, result)
})
}
}
func (suite *TeamsChatsSelectorSuite) TestIsAny() {
var (
cs = NewTeamsChatsRestore(Any())
specificChat = setScopesToDefault(cs.Chats([]string{"chat"}))
anyChat = setScopesToDefault(cs.Chats(Any()))
)
table := []struct {
name string
scopes []TeamsChatsScope
cat teamsChatsCategory
expect assert.BoolAssertionFunc
}{
{"specific chat", specificChat, TeamsChatsChat, assert.False},
{"any chat", anyChat, TeamsChatsChat, assert.True},
{"wrong category", anyChat, TeamsChatsUser, assert.False},
}
for _, test := range table {
suite.Run(test.name, func() {
t := suite.T()
var result bool
for _, scope := range test.scopes {
if scope.IsAny(test.cat) {
result = true
break
}
}
test.expect(t, result)
})
}
}
func (suite *TeamsChatsSelectorSuite) TestTeamsChatsCategory_leafCat() {
table := []struct {
cat teamsChatsCategory
expect teamsChatsCategory
}{
{teamsChatsCategory("foo"), teamsChatsCategory("foo")},
{TeamsChatsCategoryUnknown, TeamsChatsCategoryUnknown},
{TeamsChatsUser, TeamsChatsUser},
{TeamsChatsChat, TeamsChatsChat},
}
for _, test := range table {
suite.Run(test.cat.String(), func() {
assert.Equal(suite.T(), test.expect, test.cat.leafCat(), test.cat.String())
})
}
}
func (suite *TeamsChatsSelectorSuite) TestTeamsChatsCategory_PathValues() {
t := suite.T()
chatPath, err := path.Build("tid", "u", path.TeamsChatsService, path.ChatsCategory, true, "chatitem.d")
require.NoError(t, err, clues.ToCore(err))
chatLoc, err := path.Build("tid", "u", path.TeamsChatsService, path.ChatsCategory, true, "chatitem")
require.NoError(t, err, clues.ToCore(err))
var (
chatMap = map[categorizer][]string{
TeamsChatsChat: {chatPath.Item(), "chat-short"},
}
chatOnlyNameMap = map[categorizer][]string{
TeamsChatsChat: {"chat-short"},
}
)
table := []struct {
cat teamsChatsCategory
path path.Path
loc path.Path
short string
expect map[categorizer][]string
expectOnlyName map[categorizer][]string
}{
{TeamsChatsChat, chatPath, chatLoc, "chat-short", chatMap, chatOnlyNameMap},
}
for _, test := range table {
suite.Run(string(test.cat), func() {
t := suite.T()
ent := details.Entry{
RepoRef: test.path.String(),
ShortRef: test.short,
LocationRef: test.loc.Folder(true),
ItemRef: test.path.Item(),
}
pvs, err := test.cat.pathValues(test.path, ent, Config{})
require.NoError(t, err)
for k := range test.expect {
assert.ElementsMatch(t, test.expect[k], pvs[k])
}
pvs, err = test.cat.pathValues(test.path, ent, Config{OnlyMatchItemNames: true})
require.NoError(t, err)
for k := range test.expectOnlyName {
assert.ElementsMatch(t, test.expectOnlyName[k], pvs[k], k)
}
})
}
}
func (suite *TeamsChatsSelectorSuite) TestTeamsChatsCategory_PathKeys() {
chat := []categorizer{TeamsChatsChat}
user := []categorizer{TeamsChatsUser}
var empty []categorizer
table := []struct {
cat teamsChatsCategory
expect []categorizer
}{
{TeamsChatsCategoryUnknown, empty},
{TeamsChatsChat, chat},
{TeamsChatsUser, user},
}
for _, test := range table {
suite.Run(string(test.cat), func() {
assert.Equal(suite.T(), test.cat.pathKeys(), test.expect)
})
}
}
func (suite *TeamsChatsSelectorSuite) TestCategoryFromItemType() {
table := []struct {
name string
input details.ItemType
expect teamsChatsCategory
}{
{
name: "chat",
input: details.TeamsChat,
expect: TeamsChatsChat,
},
{
name: "unknown",
input: details.UnknownType,
expect: TeamsChatsCategoryUnknown,
},
}
for _, test := range table {
suite.Run(test.name, func() {
t := suite.T()
result := teamsChatsCategoryFromItemType(test.input)
assert.Equal(t, test.expect, result)
})
}
}
func (suite *TeamsChatsSelectorSuite) TestCategory_PathType() {
table := []struct {
cat teamsChatsCategory
pathType path.CategoryType
}{
{TeamsChatsCategoryUnknown, path.UnknownCategory},
{TeamsChatsChat, path.ChatsCategory},
{TeamsChatsUser, path.UnknownCategory},
}
for _, test := range table {
suite.Run(test.cat.String(), func() {
assert.Equal(suite.T(), test.pathType, test.cat.PathType())
})
}
}