mirror of
https://github.com/mattermost/mattermost.git
synced 2026-02-03 20:40:00 -05:00
* [MM-59089] Add a compliance export constant (#27919) * add a useful constant * i18n * another constant * another i18n * [MM-60422] Add GetChannelsWithActivityDuring (#28301) * modify GetUsersInChannelDuring to accept a slice of channelIds * add GetChannelsWithActivityDuring * add compliance export progress message; remove unused custom status * linting * tests running too fast * add batch size config settings * add store tests * linting * empty commit * i18n changes * fix i18n ordering * MM-60570 - Server-side changes consolidating the export CLI with server/ent code (#28640) * add an i18n field; add the CLI's export directory * int64 -> int * Add UntilUpdateAt for MessageExport and AnalyticsPostCount to merge * remove now-unused i18n strings * add TranslationsPreInitFromBuffer to allow CLI to use i18n * use GetBuilder to simplify; rename TranslationsPreInitFromFileBytes * [MM-59089] Improve compliance export timings (#1733 - Enterprise repo) * MM-60422 - Performance and logic fixes for Compliance Exports (#1757 - Enterprise repo) * MM-60570 - Enterprise-side changes consolidating the export CLI with server/ent code (#1769 - Enterprise repo) * merge conflicts; missed file from ent branch * MM-61038 - Add an option to sqlstore.New (#28702) remove useless comment add test add an option to sqlstore.New * MM-60976: Remove RunExport command from Mattermost binary (#28805) * remove RunExport command from mattermost binary * remove the code it was calling * fix i18n * remove test (was only testing license, not functionality) * empty commit * fix flaky GetChannelsWithActivityDuring test * MM-60063: Dedicated Export Filestore fix, redo of #1772 (enterprise) (#28803) * redo filestore fix #1772 (enterprise repo) on top of MM-59966 feature * add new e2e tests for export filestore * golint * ok, note to self: shadowing bad, actually (when there's a defer) * empty commit * MM-61137 - Message export: Support 7.8.11 era dbs (#28824) * support 7.8.11 era dbs by wrapping the store using only what we need * fix flaky GetChannelsWithActivityDuring test * add a comment * only need to define the MEFileInfoStore (the one that'll be overridden) * blank commit * MM-60974 - Message Export: Add performance metrics (#28836) * support 7.8.11 era dbs by wrapping the store using only what we need * fix flaky GetChannelsWithActivityDuring test * add a comment * only need to define the MEFileInfoStore (the one that'll be overridden) * performance metrics * cleanup unneeded named returns * blank commit * MM-60975 - Message export: Add startTime and endTime to export folder name (#28840) * support 7.8.11 era dbs by wrapping the store using only what we need * fix flaky GetChannelsWithActivityDuring test * add a comment * only need to define the MEFileInfoStore (the one that'll be overridden) * performance metrics * output startTime and endTime in export folder * empty commit * merge conflict * MM-60978 - Message export: Improve xml fields; fix delete semantics (#28873) * support 7.8.11 era dbs by wrapping the store using only what we need * fix flaky GetChannelsWithActivityDuring test * add a comment * only need to define the MEFileInfoStore (the one that'll be overridden) * performance metrics * output startTime and endTime in export folder * empty commit * add xml fields, omit when empty, tests * fix delete semantics; test (and test for update semantics) * clarify comments * simplify edited post detection, now there's no edge case. * add some spacing to help fast running tests * merge conflicts/updates needed for new deleted post semantics * linting; fixing tests from upstream merge * use SafeDereference * linting * stronger typing; better wrapped errors; better formatting * blank commit * goimports formatting * fix merge mistake * minor fixes due to changes in master * MM-61755 - Simplifying and Support reporting to the db from the CLI (#29281) * finally clean up JobData struct and stringMap; prep for CLI using db * and now simplify using StringMapToJobDataWithZeroValues * remove unused fn * create JobDataExported; clean up errors * MM-60176 - Message Export: Global relay cleanup (#29168) * move global relay logic into global_relay_export * blank commit * blank commit * improve errors * MM-60693 - Refactor CSV to use same codepath as Actiance (#29191) * move global relay logic into global_relay_export * blank commit * refactor (and simplify) ExportParams into shared * blank commit * remove unused fn * csv now uses pre-calculated joins/leaves like actiance * improve errors * remove nil post check; remove ignoredPosts metric * remove unneeded copy * MM-61696 - Refactor GlobalRelay to use same codepath as Actiance (#29225) * move global relay logic into global_relay_export * blank commit * refactor (and simplify) ExportParams into shared * blank commit * remove unused fn * csv now uses pre-calculated joins/leaves like actiance * remove newly unneeded function and its test. goodbye. * refactor GetPostAttachments for csv + global relay to share * refactor global_relay_export and fix tests (no changes to output) * improve errors * remove nil post check; remove ignoredPosts metric * remove unneeded copy * remove unneeded nil check * PR comments * MM-61715 - Generalize e2e to all export types 🤖 (#29369) * move global relay logic into global_relay_export * blank commit * refactor (and simplify) ExportParams into shared * blank commit * remove unused fn * csv now uses pre-calculated joins/leaves like actiance * remove newly unneeded function and its test. goodbye. * refactor GetPostAttachments for csv + global relay to share * refactor global_relay_export and fix tests (no changes to output) * improve errors * remove nil post check; remove ignoredPosts metric * remove unneeded copy * remove unneeded nil check * PR comments * refactor isDeletedMsg for all export types * fix start and endtime, nasty csv createAt bug; bring closer to Actiance * align unit tests with new logic (e.g. starttime / endtime) * refactor a TimestampConvert fn for code + tests * bug: pass templates to global relay (hurray for e2e tests, otherwise...) * add global relay zip to allowed list (only for tests) * test helpers * new templates for e2e tests * e2e tests... phew. * linting * merge conflicts * unexport PostToRow; add test helper marker * cleanup, shortening, thanks to PR comments * MM-61972 - Generalize export data path - Actiance (#29399) * extract and generalize the export data generation functions * finish moving test (bc of previous extraction) * lift a function from common -> shared (to break an import cycle) * actiance now takes general export data, processes it into actiance data * bring tests in line with correct sorting rules (upadateAt, messageId) * fixups, PR comments * turn strings.Repeat into a more descriptive const amended: one letter fix; bad rebase * MM-62009 - e2e clock heisenbug (#29434) * consolidate assertions; output debuggable diffs (keeping for future) * refactor test output generator to generators file * waitUntilZeroPosts + pass through until to job = fix all clock issues * simplify messages to model.NewId(); remove unneeded waitUntilZeroPosts * model.NewId() -> storetest.NewTestID() * MM-61980 - Generalize export data path - CSV (#29482) * simple refactoring * increase sleep times for (very) rare test failures * add extra information to the generic export for CSV * adj Actiance to handle new generic export (no difference in its output) * no longer need mergePosts (yay), move getJoinLeavePosts for everyone * adjust tests for new csv semantics (detailed in summary) * and need to add the new exported data to the export_data_tests * rearrange csv writing to happen after data export (more logical) * linting * remove debug statements * figured out what was wrong with global relay e2e test 3; solid now * PR comments * MM-61718 - Generalize export data path - Global Relay (#29508) * move global relay over to using the generalized export data * performance pass -- not much can be done * Update server/enterprise/message_export/global_relay_export/global_relay_export.go Co-authored-by: Claudio Costa <cstcld91@gmail.com> --------- Co-authored-by: Claudio Costa <cstcld91@gmail.com> * MM-62058 - Align CSV with Actiance (#29551) * refactoring actiance files and var names for clarity * bug found in exported attachments (we used to miss some start/ends) * changes needed for actiance due to new generic exports * bringing CSV up to actiance standards * fixing global relay b/c of new semantics (adding a note on an edge case) * aligning e2e tests, adding comments to clarify what is expected/tested * necessary changes; 1 more test for added functionality (ignoreDeleted) * comment style * MM-62059 - Align Global Relay with Actiance/CSV; many fixes (#29665) * core logic changes to general export_data and the specific export paths * unit tests and e2e tests, covering all new edge cases and all logic * linting * better var naming, const value, and cleaning up functions calls * MM-62436 - Temporarily skip cypress tests that require download link (#29772) --------- Co-authored-by: Claudio Costa <cstcld91@gmail.com>
286 lines
9.4 KiB
Go
286 lines
9.4 KiB
Go
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.enterprise for license information.
|
|
|
|
package shared
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/mattermost/mattermost/server/public/model"
|
|
)
|
|
|
|
func TestGetJoinsAndLeavesForChannel(t *testing.T) {
|
|
channel := MetadataChannel{
|
|
StartTime: 100,
|
|
EndTime: 200,
|
|
ChannelId: "good-request-1",
|
|
TeamId: model.NewPointer("test"),
|
|
TeamName: model.NewPointer("test"),
|
|
TeamDisplayName: model.NewPointer("test"),
|
|
ChannelName: "test",
|
|
ChannelDisplayName: "test",
|
|
ChannelType: "O",
|
|
}
|
|
|
|
tt := []struct {
|
|
name string
|
|
channel MetadataChannel
|
|
membersHistory []*model.ChannelMemberHistoryResult
|
|
usersInPosts map[string]ChannelMember
|
|
expectedJoins int
|
|
expectedLeaves int
|
|
}{
|
|
{
|
|
name: "no-joins-no-leaves",
|
|
channel: channel,
|
|
membersHistory: nil,
|
|
usersInPosts: nil,
|
|
expectedJoins: 0,
|
|
expectedLeaves: 0,
|
|
},
|
|
{
|
|
name: "joins-and-leaves-outside-the-range",
|
|
channel: channel,
|
|
membersHistory: []*model.ChannelMemberHistoryResult{
|
|
{JoinTime: 1, LeaveTime: model.NewPointer(int64(10)), UserId: "test", UserEmail: "test", Username: "test"},
|
|
{JoinTime: 250, LeaveTime: model.NewPointer(int64(260)), UserId: "test", UserEmail: "test", Username: "test"},
|
|
{JoinTime: 300, UserId: "test", UserEmail: "test", Username: "test"},
|
|
},
|
|
usersInPosts: nil,
|
|
expectedJoins: 0,
|
|
expectedLeaves: 0,
|
|
},
|
|
{
|
|
name: "join-and-leave-during-the-range",
|
|
channel: channel,
|
|
membersHistory: []*model.ChannelMemberHistoryResult{
|
|
{JoinTime: 100, LeaveTime: model.NewPointer(int64(150)), UserId: "test", UserEmail: "test", Username: "test"},
|
|
},
|
|
usersInPosts: nil,
|
|
expectedJoins: 1,
|
|
expectedLeaves: 1,
|
|
},
|
|
{
|
|
name: "join-during-and-leave-after-the-range",
|
|
channel: channel,
|
|
membersHistory: []*model.ChannelMemberHistoryResult{
|
|
{JoinTime: 150, LeaveTime: model.NewPointer(int64(300)), UserId: "test", UserEmail: "test", Username: "test"},
|
|
},
|
|
usersInPosts: nil,
|
|
expectedJoins: 1,
|
|
expectedLeaves: 0,
|
|
},
|
|
{
|
|
name: "join-before-and-leave-during-the-range",
|
|
channel: channel,
|
|
membersHistory: []*model.ChannelMemberHistoryResult{
|
|
{JoinTime: 99, LeaveTime: model.NewPointer(int64(150)), UserId: "test", UserEmail: "test", Username: "test"},
|
|
},
|
|
usersInPosts: nil,
|
|
expectedJoins: 1,
|
|
expectedLeaves: 1,
|
|
},
|
|
{
|
|
name: "join-before-and-leave-after-the-range",
|
|
channel: channel,
|
|
membersHistory: []*model.ChannelMemberHistoryResult{
|
|
{JoinTime: 99, LeaveTime: model.NewPointer(int64(350)), UserId: "test", UserEmail: "test", Username: "test"},
|
|
},
|
|
usersInPosts: nil,
|
|
expectedJoins: 1,
|
|
expectedLeaves: 0,
|
|
},
|
|
{
|
|
name: "implicit-joins",
|
|
channel: channel,
|
|
membersHistory: nil,
|
|
usersInPosts: map[string]ChannelMember{
|
|
"test1": {UserId: "test1", Email: "test1", Username: "test1"},
|
|
"test2": {UserId: "test2", Email: "test2", Username: "test2"},
|
|
},
|
|
expectedJoins: 2,
|
|
expectedLeaves: 0,
|
|
},
|
|
{
|
|
name: "implicit-joins-with-explicit-joins",
|
|
channel: channel,
|
|
membersHistory: []*model.ChannelMemberHistoryResult{
|
|
{JoinTime: 130, LeaveTime: model.NewPointer(int64(150)), UserId: "test1", UserEmail: "test1", Username: "test1"},
|
|
{JoinTime: 130, LeaveTime: model.NewPointer(int64(150)), UserId: "test3", UserEmail: "test3", Username: "test3"},
|
|
},
|
|
usersInPosts: map[string]ChannelMember{
|
|
"test1": {UserId: "test1", Email: "test1", Username: "test1"},
|
|
"test2": {UserId: "test2", Email: "test2", Username: "test2"},
|
|
},
|
|
expectedJoins: 3,
|
|
expectedLeaves: 2,
|
|
},
|
|
{
|
|
name: "join-leave-and-join-again",
|
|
channel: channel,
|
|
membersHistory: []*model.ChannelMemberHistoryResult{
|
|
{JoinTime: 130, LeaveTime: model.NewPointer(int64(150)), UserId: "test1", UserEmail: "test1", Username: "test1"},
|
|
{JoinTime: 160, LeaveTime: model.NewPointer(int64(180)), UserId: "test1", UserEmail: "test1", Username: "test1"},
|
|
},
|
|
usersInPosts: nil,
|
|
expectedJoins: 2,
|
|
expectedLeaves: 2,
|
|
},
|
|
{
|
|
name: "deactivated-members-dont-show",
|
|
channel: channel,
|
|
membersHistory: []*model.ChannelMemberHistoryResult{
|
|
{JoinTime: 130, LeaveTime: model.NewPointer(int64(150)), UserId: "test1", UserEmail: "test1", Username: "test1", UserDeleteAt: 50},
|
|
{JoinTime: 160, LeaveTime: model.NewPointer(int64(180)), UserId: "test1", UserEmail: "test1", Username: "test1", UserDeleteAt: 50},
|
|
},
|
|
usersInPosts: nil,
|
|
expectedJoins: 0,
|
|
expectedLeaves: 0,
|
|
},
|
|
{
|
|
name: "deactivated-members-show-if-deleted-after-latest-export",
|
|
channel: channel,
|
|
membersHistory: []*model.ChannelMemberHistoryResult{
|
|
{JoinTime: 130, LeaveTime: model.NewPointer(int64(150)), UserId: "test1", UserEmail: "test1", Username: "test1", UserDeleteAt: 150},
|
|
{JoinTime: 160, LeaveTime: model.NewPointer(int64(180)), UserId: "test1", UserEmail: "test1", Username: "test1", UserDeleteAt: 150},
|
|
},
|
|
usersInPosts: nil,
|
|
expectedJoins: 2,
|
|
expectedLeaves: 2,
|
|
},
|
|
{
|
|
name: "deactivated-members-show-and-dont-show",
|
|
channel: channel,
|
|
membersHistory: []*model.ChannelMemberHistoryResult{
|
|
{JoinTime: 130, LeaveTime: model.NewPointer(int64(150)), UserId: "test1", UserEmail: "test1", Username: "test1", UserDeleteAt: 50},
|
|
{JoinTime: 160, LeaveTime: model.NewPointer(int64(180)), UserId: "test1", UserEmail: "test1", Username: "test1", UserDeleteAt: 150},
|
|
},
|
|
usersInPosts: nil,
|
|
expectedJoins: 1,
|
|
expectedLeaves: 1,
|
|
},
|
|
}
|
|
|
|
for _, tc := range tt {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
joins, leaves := GetJoinsAndLeavesForChannel(tc.channel.StartTime, tc.channel.EndTime, tc.membersHistory, tc.usersInPosts)
|
|
assert.Len(t, joins, tc.expectedJoins)
|
|
assert.Len(t, leaves, tc.expectedLeaves)
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_GetBatchPath(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
exportDir string
|
|
prevPostUpdateAt int64
|
|
lastPostUpdateAt int64
|
|
batchNumber int
|
|
want string
|
|
}{
|
|
{
|
|
name: "all args given",
|
|
exportDir: "/export/test_dir",
|
|
prevPostUpdateAt: 123,
|
|
lastPostUpdateAt: 456,
|
|
batchNumber: 21,
|
|
want: "/export/test_dir/batch021-123-456.zip",
|
|
},
|
|
{
|
|
name: "exportDir blank",
|
|
exportDir: "",
|
|
prevPostUpdateAt: 12345,
|
|
lastPostUpdateAt: 456789,
|
|
batchNumber: 921,
|
|
want: model.ComplianceExportPath + "/" + time.Now().Format(model.ComplianceExportDirectoryFormat) + "/batch921-12345-456789.zip",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
assert.Equalf(t, tt.want, GetBatchPath(tt.exportDir, tt.prevPostUpdateAt, tt.lastPostUpdateAt, tt.batchNumber), "GetBatchPath(%v, %v, %v, %v)", tt.exportDir, tt.prevPostUpdateAt, tt.lastPostUpdateAt, tt.batchNumber)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestJobDataToStringMap_and_StringMapToJobData(t *testing.T) {
|
|
jd := JobData{
|
|
JobDataExported: JobDataExported{
|
|
ExportType: "cli_message_export",
|
|
ExportDir: "/here/there/34234-123",
|
|
BatchStartTime: 45,
|
|
BatchStartId: "34arsitenaorsten",
|
|
JobStartTime: 99,
|
|
JobEndTime: 1234,
|
|
JobStartId: "99abcdef34",
|
|
BatchSize: 2000,
|
|
ChannelBatchSize: 30000,
|
|
ChannelHistoryBatchSize: 30,
|
|
BatchNumber: 4,
|
|
TotalPostsExpected: 999999,
|
|
MessagesExported: 343499,
|
|
WarningCount: 39,
|
|
},
|
|
ExportPeriodStartTime: 123456, // not exported
|
|
BatchEndTime: 999999999, // not exported
|
|
BatchPath: "/another/path/123-123", // not exported
|
|
}
|
|
|
|
strMap := JobDataToStringMap(jd)
|
|
|
|
expected := make(map[string]string)
|
|
expected[JobDataExportType] = "cli_message_export"
|
|
expected[JobDataExportDir] = "/here/there/34234-123"
|
|
expected[JobDataBatchStartTime] = "45"
|
|
expected[JobDataBatchStartId] = "34arsitenaorsten"
|
|
expected[JobDataJobStartTime] = "99"
|
|
expected[JobDataJobEndTime] = "1234"
|
|
expected[JobDataJobStartId] = "99abcdef34"
|
|
expected[JobDataBatchSize] = "2000"
|
|
expected[JobDataChannelBatchSize] = "30000"
|
|
expected[JobDataChannelHistoryBatchSize] = "30"
|
|
expected[JobDataBatchNumber] = "4"
|
|
expected[JobDataTotalPostsExpected] = "999999"
|
|
expected[JobDataMessagesExported] = "343499"
|
|
expected[JobDataWarningCount] = "39"
|
|
expected[JobDataIsDownloadable] = "false"
|
|
|
|
for k, v := range expected {
|
|
val, ok := strMap[k]
|
|
assert.True(t, ok)
|
|
assert.Equal(t, v, val)
|
|
}
|
|
|
|
// not exported:
|
|
for _, k := range []string{"export_period_start_time", "batch_end_time", "batch_path"} {
|
|
_, ok := strMap[k]
|
|
assert.False(t, ok)
|
|
}
|
|
|
|
// zero the fields that weren't exported:
|
|
jd.ExportPeriodStartTime = 0
|
|
jd.BatchEndTime = 0
|
|
jd.BatchPath = ""
|
|
|
|
// now convert back
|
|
jd2, err := StringMapToJobDataWithZeroValues(strMap)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, jd, jd2)
|
|
|
|
// and test bad conversion (just a couple):
|
|
badStrMap := map[string]string{JobDataJobStartTime: "56aaa"}
|
|
_, err = StringMapToJobDataWithZeroValues(badStrMap)
|
|
assert.Error(t, err)
|
|
badStrMap = map[string]string{JobDataJobEndTime: "blah blah"}
|
|
_, err = StringMapToJobDataWithZeroValues(badStrMap)
|
|
assert.Error(t, err)
|
|
|
|
// test that zero values are used when not present
|
|
emptyStrMap := make(map[string]string)
|
|
emptyJd, err := StringMapToJobDataWithZeroValues(emptyStrMap)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, JobData{}, emptyJd)
|
|
}
|