add export support to teamschats service layer
This commit is contained in:
parent
7ab1276d61
commit
b9f71280bf
@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/alcionai/corso/src/internal/m365/service/groups"
|
"github.com/alcionai/corso/src/internal/m365/service/groups"
|
||||||
"github.com/alcionai/corso/src/internal/m365/service/onedrive"
|
"github.com/alcionai/corso/src/internal/m365/service/onedrive"
|
||||||
"github.com/alcionai/corso/src/internal/m365/service/sharepoint"
|
"github.com/alcionai/corso/src/internal/m365/service/sharepoint"
|
||||||
|
"github.com/alcionai/corso/src/internal/m365/service/teamschats"
|
||||||
"github.com/alcionai/corso/src/internal/operations/inject"
|
"github.com/alcionai/corso/src/internal/operations/inject"
|
||||||
"github.com/alcionai/corso/src/pkg/path"
|
"github.com/alcionai/corso/src/pkg/path"
|
||||||
)
|
)
|
||||||
@ -30,6 +31,9 @@ func (ctrl *Controller) NewServiceHandler(
|
|||||||
|
|
||||||
case path.ExchangeService:
|
case path.ExchangeService:
|
||||||
return exchange.NewExchangeHandler(ctrl.AC, ctrl.resourceHandler), nil
|
return exchange.NewExchangeHandler(ctrl.AC, ctrl.resourceHandler), nil
|
||||||
|
|
||||||
|
case path.TeamsChatsService:
|
||||||
|
return teamschats.NewTeamsChatsHandler(ctrl.AC, ctrl.resourceHandler), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, clues.New("unrecognized service").
|
return nil, clues.New("unrecognized service").
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/alcionai/clues"
|
"github.com/alcionai/clues"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
||||||
"github.com/alcionai/corso/src/internal/data"
|
"github.com/alcionai/corso/src/internal/data"
|
||||||
@ -79,7 +80,7 @@ func (suite *ExportUnitSuite) TestExportRestoreCollections_messages() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
p, err := path.Build("t", "pr", path.GroupsService, path.ChannelMessagesCategory, false, containerName)
|
p, err := path.Build("t", "pr", path.GroupsService, path.ChannelMessagesCategory, false, containerName)
|
||||||
assert.NoError(t, err, "build path")
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
|
|
||||||
dcs := []data.RestoreCollection{
|
dcs := []data.RestoreCollection{
|
||||||
data.FetchRestoreCollection{
|
data.FetchRestoreCollection{
|
||||||
@ -106,7 +107,7 @@ func (suite *ExportUnitSuite) TestExportRestoreCollections_messages() {
|
|||||||
dcs,
|
dcs,
|
||||||
stats,
|
stats,
|
||||||
fault.New(true))
|
fault.New(true))
|
||||||
assert.NoError(t, err, "export collections error")
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
assert.Len(t, ecs, 1, "num of collections")
|
assert.Len(t, ecs, 1, "num of collections")
|
||||||
|
|
||||||
assert.Equal(t, expectedPath, ecs[0].BasePath(), "base dir")
|
assert.Equal(t, expectedPath, ecs[0].BasePath(), "base dir")
|
||||||
@ -117,7 +118,7 @@ func (suite *ExportUnitSuite) TestExportRestoreCollections_messages() {
|
|||||||
|
|
||||||
for item := range ecs[0].Items(ctx) {
|
for item := range ecs[0].Items(ctx) {
|
||||||
b, err := io.ReadAll(item.Body)
|
b, err := io.ReadAll(item.Body)
|
||||||
assert.NoError(t, err, clues.ToCore(err))
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
|
|
||||||
// count up size for tests
|
// count up size for tests
|
||||||
size += len(b)
|
size += len(b)
|
||||||
@ -181,7 +182,7 @@ func (suite *ExportUnitSuite) TestExportRestoreCollections_libraries() {
|
|||||||
false,
|
false,
|
||||||
odConsts.SitesPathDir,
|
odConsts.SitesPathDir,
|
||||||
siteID)
|
siteID)
|
||||||
assert.NoError(t, err, "build path")
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
|
|
||||||
dcs := []data.RestoreCollection{
|
dcs := []data.RestoreCollection{
|
||||||
data.FetchRestoreCollection{
|
data.FetchRestoreCollection{
|
||||||
@ -210,7 +211,7 @@ func (suite *ExportUnitSuite) TestExportRestoreCollections_libraries() {
|
|||||||
dcs,
|
dcs,
|
||||||
stats,
|
stats,
|
||||||
fault.New(true))
|
fault.New(true))
|
||||||
assert.NoError(t, err, "export collections error")
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
assert.Len(t, ecs, 1, "num of collections")
|
assert.Len(t, ecs, 1, "num of collections")
|
||||||
|
|
||||||
assert.Equal(t, expectedPath, ecs[0].BasePath(), "base dir")
|
assert.Equal(t, expectedPath, ecs[0].BasePath(), "base dir")
|
||||||
@ -222,7 +223,7 @@ func (suite *ExportUnitSuite) TestExportRestoreCollections_libraries() {
|
|||||||
for item := range ecs[0].Items(ctx) {
|
for item := range ecs[0].Items(ctx) {
|
||||||
// unwrap the body from stats reader
|
// unwrap the body from stats reader
|
||||||
b, err := io.ReadAll(item.Body)
|
b, err := io.ReadAll(item.Body)
|
||||||
assert.NoError(t, err, clues.ToCore(err))
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
|
|
||||||
size += len(b)
|
size += len(b)
|
||||||
bitem := io.NopCloser(bytes.NewBuffer(b))
|
bitem := io.NopCloser(bytes.NewBuffer(b))
|
||||||
|
|||||||
119
src/internal/m365/service/teamschats/export.go
Normal file
119
src/internal/m365/service/teamschats/export.go
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
package teamschats
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/alcionai/clues"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/internal/common/idname"
|
||||||
|
"github.com/alcionai/corso/src/internal/data"
|
||||||
|
"github.com/alcionai/corso/src/internal/m365/collection/teamschats"
|
||||||
|
"github.com/alcionai/corso/src/internal/m365/resource"
|
||||||
|
"github.com/alcionai/corso/src/internal/operations/inject"
|
||||||
|
"github.com/alcionai/corso/src/pkg/backup/details"
|
||||||
|
"github.com/alcionai/corso/src/pkg/control"
|
||||||
|
"github.com/alcionai/corso/src/pkg/export"
|
||||||
|
"github.com/alcionai/corso/src/pkg/fault"
|
||||||
|
"github.com/alcionai/corso/src/pkg/metrics"
|
||||||
|
"github.com/alcionai/corso/src/pkg/path"
|
||||||
|
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ inject.ServiceHandler = &teamsChatsHandler{}
|
||||||
|
|
||||||
|
func NewTeamsChatsHandler(
|
||||||
|
apiClient api.Client,
|
||||||
|
resourceGetter idname.GetResourceIDAndNamer,
|
||||||
|
) *teamsChatsHandler {
|
||||||
|
return &teamsChatsHandler{
|
||||||
|
baseTeamsChatsHandler: baseTeamsChatsHandler{},
|
||||||
|
apiClient: apiClient,
|
||||||
|
resourceGetter: resourceGetter,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================================================== //
|
||||||
|
// baseTeamsChatsHandler
|
||||||
|
// ========================================================================== //
|
||||||
|
|
||||||
|
// baseTeamsChatsHandler contains logic for tracking data and doing operations
|
||||||
|
// (e.x. export) that don't require contact with external M356 services.
|
||||||
|
type baseTeamsChatsHandler struct{}
|
||||||
|
|
||||||
|
func (h *baseTeamsChatsHandler) CacheItemInfo(v details.ItemInfo) {}
|
||||||
|
|
||||||
|
// ProduceExportCollections will create the export collections for the
|
||||||
|
// given restore collections.
|
||||||
|
func (h *baseTeamsChatsHandler) ProduceExportCollections(
|
||||||
|
ctx context.Context,
|
||||||
|
backupVersion int,
|
||||||
|
exportCfg control.ExportConfig,
|
||||||
|
dcs []data.RestoreCollection,
|
||||||
|
stats *metrics.ExportStats,
|
||||||
|
errs *fault.Bus,
|
||||||
|
) ([]export.Collectioner, error) {
|
||||||
|
var (
|
||||||
|
el = errs.Local()
|
||||||
|
ec = make([]export.Collectioner, 0, len(dcs))
|
||||||
|
)
|
||||||
|
|
||||||
|
for _, dc := range dcs {
|
||||||
|
category := dc.FullPath().Category()
|
||||||
|
|
||||||
|
switch category {
|
||||||
|
case path.ChatsCategory:
|
||||||
|
folders := dc.FullPath().Folders()
|
||||||
|
pth := path.Builder{}.Append(category.HumanString()).Append(folders...)
|
||||||
|
|
||||||
|
ec = append(
|
||||||
|
ec,
|
||||||
|
teamschats.NewExportCollection(
|
||||||
|
pth.String(),
|
||||||
|
[]data.RestoreCollection{dc},
|
||||||
|
backupVersion,
|
||||||
|
exportCfg,
|
||||||
|
stats))
|
||||||
|
default:
|
||||||
|
return nil, clues.NewWC(ctx, "data category not supported").
|
||||||
|
With("category", category)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ec, el.Failure()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================================================== //
|
||||||
|
// teamschatsHandler
|
||||||
|
// ========================================================================== //
|
||||||
|
|
||||||
|
// teamsChatsHandler contains logic for handling data and performing operations
|
||||||
|
// (e.x. restore) regardless of whether they require contact with external M365
|
||||||
|
// services or not.
|
||||||
|
type teamsChatsHandler struct {
|
||||||
|
baseTeamsChatsHandler
|
||||||
|
apiClient api.Client
|
||||||
|
resourceGetter idname.GetResourceIDAndNamer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *teamsChatsHandler) IsServiceEnabled(
|
||||||
|
ctx context.Context,
|
||||||
|
resourceID string,
|
||||||
|
) (bool, error) {
|
||||||
|
// TODO(ashmrtn): Move free function implementation to this function.
|
||||||
|
res, err := IsServiceEnabled(ctx, h.apiClient.Users(), resourceID)
|
||||||
|
return res, clues.Stack(err).OrNil()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *teamsChatsHandler) PopulateProtectedResourceIDAndName(
|
||||||
|
ctx context.Context,
|
||||||
|
resourceID string, // Can be either ID or name.
|
||||||
|
ins idname.Cacher,
|
||||||
|
) (idname.Provider, error) {
|
||||||
|
if h.resourceGetter == nil {
|
||||||
|
return nil, clues.StackWC(ctx, resource.ErrNoResourceLookup)
|
||||||
|
}
|
||||||
|
|
||||||
|
pr, err := h.resourceGetter.GetResourceIDAndNameFrom(ctx, resourceID, ins)
|
||||||
|
|
||||||
|
return pr, clues.Wrap(err, "identifying resource owner").OrNil()
|
||||||
|
}
|
||||||
140
src/internal/m365/service/teamschats/export_test.go
Normal file
140
src/internal/m365/service/teamschats/export_test.go
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
package teamschats
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"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/data"
|
||||||
|
dataMock "github.com/alcionai/corso/src/internal/data/mock"
|
||||||
|
teamschatMock "github.com/alcionai/corso/src/internal/m365/service/teamschats/mock"
|
||||||
|
"github.com/alcionai/corso/src/internal/tester"
|
||||||
|
"github.com/alcionai/corso/src/internal/version"
|
||||||
|
"github.com/alcionai/corso/src/pkg/control"
|
||||||
|
"github.com/alcionai/corso/src/pkg/export"
|
||||||
|
"github.com/alcionai/corso/src/pkg/fault"
|
||||||
|
"github.com/alcionai/corso/src/pkg/metrics"
|
||||||
|
"github.com/alcionai/corso/src/pkg/path"
|
||||||
|
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ExportUnitSuite struct {
|
||||||
|
tester.Suite
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExportUnitSuite(t *testing.T) {
|
||||||
|
suite.Run(t, &ExportUnitSuite{Suite: tester.NewUnitSuite(t)})
|
||||||
|
}
|
||||||
|
|
||||||
|
type finD struct {
|
||||||
|
id string
|
||||||
|
key string
|
||||||
|
name string
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fd finD) FetchItemByName(ctx context.Context, name string) (data.Item, error) {
|
||||||
|
if fd.err != nil {
|
||||||
|
return nil, fd.err
|
||||||
|
}
|
||||||
|
|
||||||
|
if name == fd.id {
|
||||||
|
return &dataMock.Item{
|
||||||
|
ItemID: fd.id,
|
||||||
|
Reader: io.NopCloser(bytes.NewBufferString(`{"` + fd.key + `": "` + fd.name + `"}`)),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, assert.AnError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *ExportUnitSuite) TestExportRestoreCollections_chats() {
|
||||||
|
t := suite.T()
|
||||||
|
|
||||||
|
ctx, flush := tester.NewContext(t)
|
||||||
|
defer flush()
|
||||||
|
|
||||||
|
var (
|
||||||
|
category = path.ChatsCategory
|
||||||
|
itemID = "itemID"
|
||||||
|
dii = teamschatMock.ItemInfo()
|
||||||
|
content = `{"topic": "` + dii.TeamsChats.Chat.Topic + `"}`
|
||||||
|
body = io.NopCloser(bytes.NewBufferString(content))
|
||||||
|
exportCfg = control.ExportConfig{}
|
||||||
|
expectedPath = category.HumanString()
|
||||||
|
expectedItems = []export.Item{
|
||||||
|
{
|
||||||
|
ID: itemID,
|
||||||
|
Name: itemID + ".json",
|
||||||
|
// Body: body, not checked
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
p, err := path.BuildPrefix("t", "pr", path.TeamsChatsService, category)
|
||||||
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
|
|
||||||
|
dcs := []data.RestoreCollection{
|
||||||
|
data.FetchRestoreCollection{
|
||||||
|
Collection: dataMock.Collection{
|
||||||
|
Path: p,
|
||||||
|
ItemData: []data.Item{
|
||||||
|
&dataMock.Item{
|
||||||
|
ItemID: itemID,
|
||||||
|
Reader: body,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
FetchItemByNamer: finD{
|
||||||
|
id: itemID,
|
||||||
|
key: "id",
|
||||||
|
name: itemID,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
stats := metrics.NewExportStats()
|
||||||
|
|
||||||
|
ecs, err := NewTeamsChatsHandler(api.Client{}, nil).
|
||||||
|
ProduceExportCollections(
|
||||||
|
ctx,
|
||||||
|
int(version.Backup),
|
||||||
|
exportCfg,
|
||||||
|
dcs,
|
||||||
|
stats,
|
||||||
|
fault.New(true))
|
||||||
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
|
assert.Len(t, ecs, 1, "num of collections")
|
||||||
|
|
||||||
|
assert.Equal(t, expectedPath, ecs[0].BasePath(), "base dir")
|
||||||
|
|
||||||
|
fitems := []export.Item{}
|
||||||
|
|
||||||
|
size := 0
|
||||||
|
|
||||||
|
for item := range ecs[0].Items(ctx) {
|
||||||
|
b, err := io.ReadAll(item.Body)
|
||||||
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
|
|
||||||
|
// count up size for tests
|
||||||
|
size += len(b)
|
||||||
|
|
||||||
|
// have to nil out body, otherwise assert fails due to
|
||||||
|
// pointer memory location differences
|
||||||
|
item.Body = nil
|
||||||
|
fitems = append(fitems, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, expectedItems, fitems, "items")
|
||||||
|
|
||||||
|
expectedStats := metrics.NewExportStats()
|
||||||
|
expectedStats.UpdateBytes(category, int64(size))
|
||||||
|
expectedStats.UpdateResourceCount(category)
|
||||||
|
assert.Equal(t, expectedStats.GetStats(), stats.GetStats(), "stats")
|
||||||
|
}
|
||||||
84
src/pkg/backup/details/testdata/testdata.go
vendored
84
src/pkg/backup/details/testdata/testdata.go
vendored
@ -16,11 +16,13 @@ import (
|
|||||||
// mustParsePath takes a string representing a resource path and returns a path
|
// mustParsePath takes a string representing a resource path and returns a path
|
||||||
// instance. Panics if the path cannot be parsed. Useful for simple variable
|
// instance. Panics if the path cannot be parsed. Useful for simple variable
|
||||||
// assignments.
|
// assignments.
|
||||||
func mustParsePath(ref string, isItem, isSharepointList bool) path.Path {
|
func mustParsePath(ref string, isItem, allowPrefix bool) path.Path {
|
||||||
var p path.Path
|
var (
|
||||||
var err error
|
p path.Path
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
if isSharepointList {
|
if allowPrefix {
|
||||||
p, err = path.PrefixOrPathFromDataLayerPath(ref, isItem)
|
p, err = path.PrefixOrPathFromDataLayerPath(ref, isItem)
|
||||||
} else {
|
} else {
|
||||||
p, err = path.FromDataLayerPath(ref, isItem)
|
p, err = path.FromDataLayerPath(ref, isItem)
|
||||||
@ -126,9 +128,9 @@ func (p repoRefAndLocRef) locationAsRepoRef() path.Path {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func mustPathRep(ref string, isItem, isSharepointList bool) repoRefAndLocRef {
|
func mustPathRep(ref string, isItem, allowPrefix bool) repoRefAndLocRef {
|
||||||
res := repoRefAndLocRef{}
|
res := repoRefAndLocRef{}
|
||||||
tmp := mustParsePath(ref, isItem, isSharepointList)
|
tmp := mustParsePath(ref, isItem, allowPrefix)
|
||||||
|
|
||||||
// Now append stuff to the RepoRef elements so we have distinct LocationRef
|
// Now append stuff to the RepoRef elements so we have distinct LocationRef
|
||||||
// and RepoRef elements to simulate using IDs in the path instead of display
|
// and RepoRef elements to simulate using IDs in the path instead of display
|
||||||
@ -969,6 +971,68 @@ var (
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TeamsChatsRootPath = mustPathRep("tenant-id/"+path.TeamsChatsService.String()+"/user-id/chats", false, true)
|
||||||
|
|
||||||
|
TeamsChatsChatItemPath1 = TeamsChatsRootPath.MustAppend(ItemName1, true)
|
||||||
|
TeamsChatsChatItemPath2 = TeamsChatsRootPath.MustAppend(ItemName2, true)
|
||||||
|
TeamsChatsChatItemPath3 = TeamsChatsRootPath.MustAppend(ItemName3, true)
|
||||||
|
|
||||||
|
teamsChatsChatItemsByVersion = map[int][]details.Entry{
|
||||||
|
version.Groups9Update: {
|
||||||
|
{
|
||||||
|
RepoRef: TeamsChatsChatItemPath1.locationAsRepoRef().String(),
|
||||||
|
ShortRef: TeamsChatsChatItemPath1.locationAsRepoRef().ShortRef(),
|
||||||
|
ParentRef: TeamsChatsChatItemPath1.locationAsRepoRef().ToBuilder().Dir().ShortRef(),
|
||||||
|
ItemRef: TeamsChatsChatItemPath1.ItemLocation(),
|
||||||
|
LocationRef: "",
|
||||||
|
ItemInfo: details.ItemInfo{
|
||||||
|
TeamsChats: &details.TeamsChatsInfo{
|
||||||
|
ItemType: details.TeamsChat,
|
||||||
|
Modified: Time4,
|
||||||
|
ParentPath: "",
|
||||||
|
Chat: details.ChatInfo{
|
||||||
|
Topic: "item 1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RepoRef: TeamsChatsChatItemPath2.locationAsRepoRef().String(),
|
||||||
|
ShortRef: TeamsChatsChatItemPath2.locationAsRepoRef().ShortRef(),
|
||||||
|
ParentRef: TeamsChatsChatItemPath2.locationAsRepoRef().ToBuilder().Dir().ShortRef(),
|
||||||
|
ItemRef: TeamsChatsChatItemPath2.ItemLocation(),
|
||||||
|
LocationRef: "",
|
||||||
|
ItemInfo: details.ItemInfo{
|
||||||
|
TeamsChats: &details.TeamsChatsInfo{
|
||||||
|
ItemType: details.TeamsChat,
|
||||||
|
Modified: Time3,
|
||||||
|
ParentPath: "",
|
||||||
|
Chat: details.ChatInfo{
|
||||||
|
Topic: "item 2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RepoRef: TeamsChatsChatItemPath3.locationAsRepoRef().String(),
|
||||||
|
ShortRef: TeamsChatsChatItemPath3.locationAsRepoRef().ShortRef(),
|
||||||
|
ParentRef: TeamsChatsChatItemPath3.locationAsRepoRef().ToBuilder().Dir().ShortRef(),
|
||||||
|
ItemRef: TeamsChatsChatItemPath3.ItemLocation(),
|
||||||
|
LocationRef: "",
|
||||||
|
ItemInfo: details.ItemInfo{
|
||||||
|
TeamsChats: &details.TeamsChatsInfo{
|
||||||
|
ItemType: details.TeamsChat,
|
||||||
|
ParentPath: "",
|
||||||
|
Modified: Time4,
|
||||||
|
Chat: details.ChatInfo{
|
||||||
|
Topic: "item 3",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetDetailsSetForVersion(t *testing.T, wantedVersion int) *details.Details {
|
func GetDetailsSetForVersion(t *testing.T, wantedVersion int) *details.Details {
|
||||||
@ -987,6 +1051,9 @@ func GetDetailsSetForVersion(t *testing.T, wantedVersion int) *details.Details {
|
|||||||
path.SharePointService: {
|
path.SharePointService: {
|
||||||
path.LibrariesCategory,
|
path.LibrariesCategory,
|
||||||
},
|
},
|
||||||
|
path.TeamsChatsService: {
|
||||||
|
path.ChatsCategory,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for s, cats := range dataTypes {
|
for s, cats := range dataTypes {
|
||||||
@ -1060,6 +1127,11 @@ func GetDeetsForVersion(
|
|||||||
if cat == path.LibrariesCategory {
|
if cat == path.LibrariesCategory {
|
||||||
input = sharePointLibraryItemsByVersion
|
input = sharePointLibraryItemsByVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case path.TeamsChatsService:
|
||||||
|
if cat == path.ChatsCategory {
|
||||||
|
input = teamsChatsChatItemsByVersion
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
require.NotNil(
|
require.NotNil(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user