mirror of
https://github.com/hanzoai/team.git
synced 2026-09-30 01:57:35 +00:00
* Fix DM/GM channel member import defaulting SchemeUser to false The direct-channel participant import path only assigned scheme flags when the import data carried them, so imports that omitted those fields (notably mmetl's Slack export) produced channel members with no effective role. The web client then routed those channels to the "missing channel role" loading state and the message input never loaded. A customer reported 444 affected channel member rows for a single user. Default SchemeGuest and SchemeUser from the resolved user before the existing nil-checked overrides, matching the regular user-channel import path at lines 1273-1275. Explicit values in the import data still win. Adds regression tests for both DM and GM channels. Fixes MM-68914. * Use fresh users in SchemeUser regression tests The new subtests added in the previous commit reused BasicUser, BasicUser2, and user3, which already had channels created by earlier subtests in TestImportImportDirectChannel with non-zero LastViewedAt. The freshness guard in importDirectChannel then skipped the participants and the assertions ran against pre-existing channel members rather than the import path. As a result the tests passed regardless of whether the fix was present. Switch to fresh users created via th.CreateUser so there is no pre-existing channel, no LastViewedAt mismatch, and UpdateMultipleMembers actually runs with the import-built members. Verified by reverting the fix in import_functions.go: both subtests now fail without the fix and pass with it.
6537 lines
227 KiB
Go
6537 lines
227 KiB
Go
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
package app
|
|
|
|
import (
|
|
"archive/zip"
|
|
"context"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/mattermost/mattermost/server/public/model"
|
|
"github.com/mattermost/mattermost/server/public/shared/mlog"
|
|
"github.com/mattermost/mattermost/server/v8/channels/app/imports"
|
|
"github.com/mattermost/mattermost/server/v8/channels/store"
|
|
"github.com/mattermost/mattermost/server/v8/channels/testlib"
|
|
"github.com/mattermost/mattermost/server/v8/channels/utils"
|
|
"github.com/mattermost/mattermost/server/v8/channels/utils/fileutils"
|
|
"github.com/mattermost/mattermost/server/v8/platform/shared/filestore"
|
|
)
|
|
|
|
func TestImportImportScheme(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
// Mark the phase 2 permissions migration as completed.
|
|
err := th.App.Srv().Store().System().Save(&model.System{Name: model.MigrationKeyAdvancedPermissionsPhase2, Value: "true"})
|
|
require.NoError(t, err, "Failed to save system value.")
|
|
|
|
defer func() {
|
|
_, err = th.App.Srv().Store().System().PermanentDeleteByName(model.MigrationKeyAdvancedPermissionsPhase2)
|
|
require.NoError(t, err, "Failed to delete system value.")
|
|
}()
|
|
|
|
// Try importing an invalid scheme in dryRun mode.
|
|
data := imports.SchemeImportData{
|
|
Name: new(model.NewId()),
|
|
Scope: new("team"),
|
|
DefaultTeamGuestRole: &imports.RoleImportData{
|
|
Name: new(model.NewId()),
|
|
DisplayName: new(model.NewId()),
|
|
},
|
|
DefaultTeamUserRole: &imports.RoleImportData{
|
|
Name: new(model.NewId()),
|
|
DisplayName: new(model.NewId()),
|
|
},
|
|
DefaultTeamAdminRole: &imports.RoleImportData{
|
|
Name: new(model.NewId()),
|
|
DisplayName: new(model.NewId()),
|
|
},
|
|
DefaultChannelGuestRole: &imports.RoleImportData{
|
|
Name: new(model.NewId()),
|
|
DisplayName: new(model.NewId()),
|
|
},
|
|
DefaultChannelUserRole: &imports.RoleImportData{
|
|
Name: new(model.NewId()),
|
|
DisplayName: new(model.NewId()),
|
|
},
|
|
DefaultChannelAdminRole: &imports.RoleImportData{
|
|
Name: new(model.NewId()),
|
|
DisplayName: new(model.NewId()),
|
|
},
|
|
Description: new("description"),
|
|
}
|
|
|
|
appErr := th.App.importScheme(th.Context, &data, true)
|
|
require.NotNil(t, appErr, "Should have failed to import.")
|
|
|
|
_, err = th.App.Srv().Store().Scheme().GetByName(*data.Name)
|
|
require.Error(t, err, "Scheme should not have imported.")
|
|
|
|
// Try importing a valid scheme in dryRun mode.
|
|
data.DisplayName = new("display name")
|
|
|
|
appErr = th.App.importScheme(th.Context, &data, true)
|
|
require.Nil(t, appErr, "Should have succeeded.")
|
|
|
|
_, err = th.App.Srv().Store().Scheme().GetByName(*data.Name)
|
|
require.Error(t, err, "Scheme should not have imported.")
|
|
|
|
// Try importing an invalid scheme.
|
|
data.DisplayName = nil
|
|
|
|
appErr = th.App.importScheme(th.Context, &data, false)
|
|
require.NotNil(t, appErr, "Should have failed to import.")
|
|
|
|
_, err = th.App.Srv().Store().Scheme().GetByName(*data.Name)
|
|
require.Error(t, err, "Scheme should not have imported.")
|
|
|
|
// Try importing a valid scheme with all params set.
|
|
data.DisplayName = new("display name")
|
|
|
|
appErr = th.App.importScheme(th.Context, &data, false)
|
|
require.Nil(t, appErr, "Should have succeeded.")
|
|
|
|
scheme, nErr := th.App.Srv().Store().Scheme().GetByName(*data.Name)
|
|
require.NoError(t, nErr, "Failed to import scheme: %v", err)
|
|
|
|
assert.Equal(t, *data.Name, scheme.Name)
|
|
assert.Equal(t, *data.DisplayName, scheme.DisplayName)
|
|
assert.Equal(t, *data.Description, scheme.Description)
|
|
assert.Equal(t, *data.Scope, scheme.Scope)
|
|
|
|
role, nErr := th.App.Srv().Store().Role().GetByName(context.Background(), scheme.DefaultTeamAdminRole)
|
|
require.NoError(t, nErr, "Should have found the imported role.")
|
|
|
|
assert.Equal(t, *data.DefaultTeamAdminRole.DisplayName, role.DisplayName)
|
|
assert.False(t, role.BuiltIn)
|
|
assert.True(t, role.SchemeManaged)
|
|
|
|
role, nErr = th.App.Srv().Store().Role().GetByName(context.Background(), scheme.DefaultTeamUserRole)
|
|
require.NoError(t, nErr, "Should have found the imported role.")
|
|
|
|
assert.Equal(t, *data.DefaultTeamUserRole.DisplayName, role.DisplayName)
|
|
assert.False(t, role.BuiltIn)
|
|
assert.True(t, role.SchemeManaged)
|
|
|
|
role, nErr = th.App.Srv().Store().Role().GetByName(context.Background(), scheme.DefaultTeamGuestRole)
|
|
require.NoError(t, nErr, "Should have found the imported role.")
|
|
|
|
assert.Equal(t, *data.DefaultTeamGuestRole.DisplayName, role.DisplayName)
|
|
assert.False(t, role.BuiltIn)
|
|
assert.True(t, role.SchemeManaged)
|
|
|
|
role, nErr = th.App.Srv().Store().Role().GetByName(context.Background(), scheme.DefaultChannelAdminRole)
|
|
require.NoError(t, nErr, "Should have found the imported role.")
|
|
|
|
assert.Equal(t, *data.DefaultChannelAdminRole.DisplayName, role.DisplayName)
|
|
assert.False(t, role.BuiltIn)
|
|
assert.True(t, role.SchemeManaged)
|
|
|
|
role, nErr = th.App.Srv().Store().Role().GetByName(context.Background(), scheme.DefaultChannelUserRole)
|
|
require.NoError(t, nErr, "Should have found the imported role.")
|
|
|
|
assert.Equal(t, *data.DefaultChannelUserRole.DisplayName, role.DisplayName)
|
|
assert.False(t, role.BuiltIn)
|
|
assert.True(t, role.SchemeManaged)
|
|
|
|
role, nErr = th.App.Srv().Store().Role().GetByName(context.Background(), scheme.DefaultChannelGuestRole)
|
|
require.NoError(t, nErr, "Should have found the imported role.")
|
|
|
|
assert.Equal(t, *data.DefaultChannelGuestRole.DisplayName, role.DisplayName)
|
|
assert.False(t, role.BuiltIn)
|
|
assert.True(t, role.SchemeManaged)
|
|
|
|
// Try modifying all the fields and re-importing.
|
|
data.DisplayName = new("new display name")
|
|
data.Description = new("new description")
|
|
|
|
appErr = th.App.importScheme(th.Context, &data, false)
|
|
require.Nil(t, appErr, "Should have succeeded: %v", err)
|
|
|
|
scheme, nErr = th.App.Srv().Store().Scheme().GetByName(*data.Name)
|
|
require.NoError(t, nErr, "Failed to import scheme: %v", err)
|
|
|
|
assert.Equal(t, *data.Name, scheme.Name)
|
|
assert.Equal(t, *data.DisplayName, scheme.DisplayName)
|
|
assert.Equal(t, *data.Description, scheme.Description)
|
|
assert.Equal(t, *data.Scope, scheme.Scope)
|
|
|
|
role, nErr = th.App.Srv().Store().Role().GetByName(context.Background(), scheme.DefaultTeamAdminRole)
|
|
require.NoError(t, nErr, "Should have found the imported role.")
|
|
|
|
assert.Equal(t, *data.DefaultTeamAdminRole.DisplayName, role.DisplayName)
|
|
assert.False(t, role.BuiltIn)
|
|
assert.True(t, role.SchemeManaged)
|
|
|
|
role, nErr = th.App.Srv().Store().Role().GetByName(context.Background(), scheme.DefaultTeamUserRole)
|
|
require.NoError(t, nErr, "Should have found the imported role.")
|
|
|
|
assert.Equal(t, *data.DefaultTeamUserRole.DisplayName, role.DisplayName)
|
|
assert.False(t, role.BuiltIn)
|
|
assert.True(t, role.SchemeManaged)
|
|
|
|
role, nErr = th.App.Srv().Store().Role().GetByName(context.Background(), scheme.DefaultTeamGuestRole)
|
|
require.NoError(t, nErr, "Should have found the imported role.")
|
|
|
|
assert.Equal(t, *data.DefaultTeamGuestRole.DisplayName, role.DisplayName)
|
|
assert.False(t, role.BuiltIn)
|
|
assert.True(t, role.SchemeManaged)
|
|
|
|
role, nErr = th.App.Srv().Store().Role().GetByName(context.Background(), scheme.DefaultChannelAdminRole)
|
|
require.NoError(t, nErr, "Should have found the imported role.")
|
|
|
|
assert.Equal(t, *data.DefaultChannelAdminRole.DisplayName, role.DisplayName)
|
|
assert.False(t, role.BuiltIn)
|
|
assert.True(t, role.SchemeManaged)
|
|
|
|
role, nErr = th.App.Srv().Store().Role().GetByName(context.Background(), scheme.DefaultChannelUserRole)
|
|
require.NoError(t, nErr, "Should have found the imported role.")
|
|
|
|
assert.Equal(t, *data.DefaultChannelUserRole.DisplayName, role.DisplayName)
|
|
assert.False(t, role.BuiltIn)
|
|
assert.True(t, role.SchemeManaged)
|
|
|
|
role, nErr = th.App.Srv().Store().Role().GetByName(context.Background(), scheme.DefaultChannelGuestRole)
|
|
require.NoError(t, nErr, "Should have found the imported role.")
|
|
|
|
assert.Equal(t, *data.DefaultChannelGuestRole.DisplayName, role.DisplayName)
|
|
assert.False(t, role.BuiltIn)
|
|
assert.True(t, role.SchemeManaged)
|
|
|
|
// Try changing the scope of the scheme and reimporting.
|
|
data.Scope = new("channel")
|
|
|
|
appErr = th.App.importScheme(th.Context, &data, false)
|
|
require.NotNil(t, appErr, "Should have failed to import.")
|
|
|
|
scheme, nErr = th.App.Srv().Store().Scheme().GetByName(*data.Name)
|
|
require.NoError(t, nErr, "Failed to import scheme: %v", err)
|
|
|
|
assert.Equal(t, *data.Name, scheme.Name)
|
|
assert.Equal(t, *data.DisplayName, scheme.DisplayName)
|
|
assert.Equal(t, *data.Description, scheme.Description)
|
|
assert.Equal(t, "team", scheme.Scope)
|
|
}
|
|
|
|
func TestImportImportSchemeWithoutGuestRoles(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
// Mark the phase 2 permissions migration as completed.
|
|
err := th.App.Srv().Store().System().Save(&model.System{Name: model.MigrationKeyAdvancedPermissionsPhase2, Value: "true"})
|
|
require.NoError(t, err, "Failed to save system value.")
|
|
|
|
defer func() {
|
|
_, err = th.App.Srv().Store().System().PermanentDeleteByName(model.MigrationKeyAdvancedPermissionsPhase2)
|
|
require.NoError(t, err, "Failed to delete system value.")
|
|
}()
|
|
|
|
// Try importing an invalid scheme in dryRun mode.
|
|
data := imports.SchemeImportData{
|
|
Name: new(model.NewId()),
|
|
Scope: new("team"),
|
|
DefaultTeamUserRole: &imports.RoleImportData{
|
|
Name: new(model.NewId()),
|
|
DisplayName: new(model.NewId()),
|
|
},
|
|
DefaultTeamAdminRole: &imports.RoleImportData{
|
|
Name: new(model.NewId()),
|
|
DisplayName: new(model.NewId()),
|
|
},
|
|
DefaultChannelUserRole: &imports.RoleImportData{
|
|
Name: new(model.NewId()),
|
|
DisplayName: new(model.NewId()),
|
|
},
|
|
DefaultChannelAdminRole: &imports.RoleImportData{
|
|
Name: new(model.NewId()),
|
|
DisplayName: new(model.NewId()),
|
|
},
|
|
Description: new("description"),
|
|
}
|
|
|
|
appErr := th.App.importScheme(th.Context, &data, true)
|
|
require.NotNil(t, appErr, "Should have failed to import.")
|
|
|
|
_, err = th.App.Srv().Store().Scheme().GetByName(*data.Name)
|
|
require.Error(t, err, "Scheme should not have imported.")
|
|
|
|
// Try importing a valid scheme in dryRun mode.
|
|
data.DisplayName = new("display name")
|
|
|
|
appErr = th.App.importScheme(th.Context, &data, true)
|
|
require.Nil(t, appErr, "Should have succeeded.")
|
|
|
|
_, err = th.App.Srv().Store().Scheme().GetByName(*data.Name)
|
|
require.Error(t, err, "Scheme should not have imported.")
|
|
|
|
// Try importing an invalid scheme.
|
|
data.DisplayName = nil
|
|
|
|
appErr = th.App.importScheme(th.Context, &data, false)
|
|
require.NotNil(t, appErr, "Should have failed to import.")
|
|
|
|
_, err = th.App.Srv().Store().Scheme().GetByName(*data.Name)
|
|
require.Error(t, err, "Scheme should not have imported.")
|
|
|
|
// Try importing a valid scheme with all params set.
|
|
data.DisplayName = new("display name")
|
|
|
|
appErr = th.App.importScheme(th.Context, &data, false)
|
|
require.Nil(t, appErr, "Should have succeeded.")
|
|
|
|
scheme, err := th.App.Srv().Store().Scheme().GetByName(*data.Name)
|
|
require.NoError(t, err, "Failed to import scheme: %v", err)
|
|
|
|
assert.Equal(t, *data.Name, scheme.Name)
|
|
assert.Equal(t, *data.DisplayName, scheme.DisplayName)
|
|
assert.Equal(t, *data.Description, scheme.Description)
|
|
assert.Equal(t, *data.Scope, scheme.Scope)
|
|
|
|
role, err := th.App.Srv().Store().Role().GetByName(context.Background(), scheme.DefaultTeamAdminRole)
|
|
require.NoError(t, err, "Should have found the imported role.")
|
|
|
|
assert.Equal(t, *data.DefaultTeamAdminRole.DisplayName, role.DisplayName)
|
|
assert.False(t, role.BuiltIn)
|
|
assert.True(t, role.SchemeManaged)
|
|
|
|
role, err = th.App.Srv().Store().Role().GetByName(context.Background(), scheme.DefaultTeamUserRole)
|
|
require.NoError(t, err, "Should have found the imported role.")
|
|
|
|
assert.Equal(t, *data.DefaultTeamUserRole.DisplayName, role.DisplayName)
|
|
assert.False(t, role.BuiltIn)
|
|
assert.True(t, role.SchemeManaged)
|
|
|
|
role, err = th.App.Srv().Store().Role().GetByName(context.Background(), scheme.DefaultTeamGuestRole)
|
|
require.NoError(t, err, "Should have found the imported role.")
|
|
|
|
assert.Equal(t, *data.DefaultTeamGuestRole.DisplayName, role.DisplayName)
|
|
assert.False(t, role.BuiltIn)
|
|
assert.True(t, role.SchemeManaged)
|
|
|
|
role, err = th.App.Srv().Store().Role().GetByName(context.Background(), scheme.DefaultChannelAdminRole)
|
|
require.NoError(t, err, "Should have found the imported role.")
|
|
|
|
assert.Equal(t, *data.DefaultChannelAdminRole.DisplayName, role.DisplayName)
|
|
assert.False(t, role.BuiltIn)
|
|
assert.True(t, role.SchemeManaged)
|
|
|
|
role, err = th.App.Srv().Store().Role().GetByName(context.Background(), scheme.DefaultChannelUserRole)
|
|
require.NoError(t, err, "Should have found the imported role.")
|
|
|
|
assert.Equal(t, *data.DefaultChannelUserRole.DisplayName, role.DisplayName)
|
|
assert.False(t, role.BuiltIn)
|
|
assert.True(t, role.SchemeManaged)
|
|
|
|
role, err = th.App.Srv().Store().Role().GetByName(context.Background(), scheme.DefaultChannelGuestRole)
|
|
require.NoError(t, err, "Should have found the imported role.")
|
|
|
|
assert.Equal(t, *data.DefaultChannelGuestRole.DisplayName, role.DisplayName)
|
|
assert.False(t, role.BuiltIn)
|
|
assert.True(t, role.SchemeManaged)
|
|
|
|
// Try modifying all the fields and re-importing.
|
|
data.DisplayName = new("new display name")
|
|
data.Description = new("new description")
|
|
|
|
appErr = th.App.importScheme(th.Context, &data, false)
|
|
require.Nil(t, appErr, "Should have succeeded: %v", err)
|
|
|
|
scheme, err = th.App.Srv().Store().Scheme().GetByName(*data.Name)
|
|
require.NoError(t, err, "Failed to import scheme: %v", err)
|
|
|
|
assert.Equal(t, *data.Name, scheme.Name)
|
|
assert.Equal(t, *data.DisplayName, scheme.DisplayName)
|
|
assert.Equal(t, *data.Description, scheme.Description)
|
|
assert.Equal(t, *data.Scope, scheme.Scope)
|
|
|
|
role, err = th.App.Srv().Store().Role().GetByName(context.Background(), scheme.DefaultTeamAdminRole)
|
|
require.NoError(t, err, "Should have found the imported role.")
|
|
|
|
assert.Equal(t, *data.DefaultTeamAdminRole.DisplayName, role.DisplayName)
|
|
assert.False(t, role.BuiltIn)
|
|
assert.True(t, role.SchemeManaged)
|
|
|
|
role, err = th.App.Srv().Store().Role().GetByName(context.Background(), scheme.DefaultTeamUserRole)
|
|
require.NoError(t, err, "Should have found the imported role.")
|
|
|
|
assert.Equal(t, *data.DefaultTeamUserRole.DisplayName, role.DisplayName)
|
|
assert.False(t, role.BuiltIn)
|
|
assert.True(t, role.SchemeManaged)
|
|
|
|
role, err = th.App.Srv().Store().Role().GetByName(context.Background(), scheme.DefaultTeamGuestRole)
|
|
require.NoError(t, err, "Should have found the imported role.")
|
|
|
|
assert.Equal(t, *data.DefaultTeamGuestRole.DisplayName, role.DisplayName)
|
|
assert.False(t, role.BuiltIn)
|
|
assert.True(t, role.SchemeManaged)
|
|
|
|
role, err = th.App.Srv().Store().Role().GetByName(context.Background(), scheme.DefaultChannelAdminRole)
|
|
require.NoError(t, err, "Should have found the imported role.")
|
|
|
|
assert.Equal(t, *data.DefaultChannelAdminRole.DisplayName, role.DisplayName)
|
|
assert.False(t, role.BuiltIn)
|
|
assert.True(t, role.SchemeManaged)
|
|
|
|
role, err = th.App.Srv().Store().Role().GetByName(context.Background(), scheme.DefaultChannelUserRole)
|
|
require.NoError(t, err, "Should have found the imported role.")
|
|
|
|
assert.Equal(t, *data.DefaultChannelUserRole.DisplayName, role.DisplayName)
|
|
assert.False(t, role.BuiltIn)
|
|
assert.True(t, role.SchemeManaged)
|
|
|
|
role, err = th.App.Srv().Store().Role().GetByName(context.Background(), scheme.DefaultChannelGuestRole)
|
|
require.NoError(t, err, "Should have found the imported role.")
|
|
|
|
assert.Equal(t, *data.DefaultChannelGuestRole.DisplayName, role.DisplayName)
|
|
assert.False(t, role.BuiltIn)
|
|
assert.True(t, role.SchemeManaged)
|
|
|
|
// Try changing the scope of the scheme and reimporting.
|
|
data.Scope = new("channel")
|
|
|
|
appErr = th.App.importScheme(th.Context, &data, false)
|
|
require.NotNil(t, appErr, "Should have failed to import.")
|
|
|
|
scheme, err = th.App.Srv().Store().Scheme().GetByName(*data.Name)
|
|
require.NoError(t, err, "Failed to import scheme: %v", err)
|
|
|
|
assert.Equal(t, *data.Name, scheme.Name)
|
|
assert.Equal(t, *data.DisplayName, scheme.DisplayName)
|
|
assert.Equal(t, *data.Description, scheme.Description)
|
|
assert.Equal(t, "team", scheme.Scope)
|
|
}
|
|
|
|
func TestImportImportRole(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
// Try importing an invalid role in dryRun mode.
|
|
rid1 := model.NewId()
|
|
data := imports.RoleImportData{
|
|
Name: &rid1,
|
|
}
|
|
|
|
appErr := th.App.importRole(th.Context, &data, true)
|
|
require.NotNil(t, appErr, "Should have failed to import.")
|
|
|
|
_, nErr := th.App.Srv().Store().Role().GetByName(context.Background(), rid1)
|
|
require.Error(t, nErr, "Should have failed to import.")
|
|
|
|
// Try importing the valid role in dryRun mode.
|
|
data.DisplayName = new("display name")
|
|
|
|
appErr = th.App.importRole(th.Context, &data, true)
|
|
require.Nil(t, appErr, "Should have succeeded.")
|
|
|
|
_, nErr = th.App.Srv().Store().Role().GetByName(context.Background(), rid1)
|
|
require.Error(t, nErr, "Role should not have imported as we are in dry run mode.")
|
|
|
|
// Try importing an invalid role.
|
|
data.DisplayName = nil
|
|
|
|
appErr = th.App.importRole(th.Context, &data, false)
|
|
require.NotNil(t, appErr, "Should have failed to import.")
|
|
|
|
_, nErr = th.App.Srv().Store().Role().GetByName(context.Background(), rid1)
|
|
require.Error(t, nErr, "Role should not have imported.")
|
|
|
|
// Try importing a valid role with all params set.
|
|
data.DisplayName = new("display name")
|
|
data.Description = new("description")
|
|
data.Permissions = &[]string{"invite_user", "add_user_to_team"}
|
|
|
|
appErr = th.App.importRole(th.Context, &data, false)
|
|
require.Nil(t, appErr, "Should have succeeded.")
|
|
|
|
role, nErr := th.App.Srv().Store().Role().GetByName(context.Background(), rid1)
|
|
require.NoError(t, nErr, "Should have found the imported role.")
|
|
|
|
assert.Equal(t, *data.Name, role.Name)
|
|
assert.Equal(t, *data.DisplayName, role.DisplayName)
|
|
assert.Equal(t, *data.Description, role.Description)
|
|
assert.Equal(t, *data.Permissions, role.Permissions)
|
|
assert.False(t, role.BuiltIn)
|
|
assert.False(t, role.SchemeManaged)
|
|
|
|
// Try changing all the params and reimporting.
|
|
data.DisplayName = new("new display name")
|
|
data.Description = new("description")
|
|
data.Permissions = &[]string{"manage_slash_commands"}
|
|
data.SchemeManaged = new(true)
|
|
|
|
appErr = th.App.importRole(th.Context, &data, false)
|
|
require.Nil(t, appErr, "Should have succeeded. %v", appErr)
|
|
|
|
role, nErr = th.App.Srv().Store().Role().GetByName(context.Background(), rid1)
|
|
require.NoError(t, nErr, "Should have found the imported role.")
|
|
|
|
assert.Equal(t, *data.Name, role.Name)
|
|
assert.Equal(t, *data.DisplayName, role.DisplayName)
|
|
assert.Equal(t, *data.Description, role.Description)
|
|
assert.Equal(t, *data.Permissions, role.Permissions)
|
|
assert.False(t, role.BuiltIn)
|
|
assert.True(t, role.SchemeManaged)
|
|
|
|
// Check that re-importing with only required fields doesn't update the others.
|
|
data2 := imports.RoleImportData{
|
|
Name: &rid1,
|
|
DisplayName: new("new display name again"),
|
|
}
|
|
|
|
appErr = th.App.importRole(th.Context, &data2, false)
|
|
require.Nil(t, appErr, "Should have succeeded.")
|
|
|
|
role, nErr = th.App.Srv().Store().Role().GetByName(context.Background(), rid1)
|
|
require.NoError(t, nErr, "Should have found the imported role.")
|
|
|
|
assert.Equal(t, *data2.Name, role.Name)
|
|
assert.Equal(t, *data2.DisplayName, role.DisplayName)
|
|
assert.Equal(t, *data.Description, role.Description)
|
|
assert.Equal(t, *data.Permissions, role.Permissions)
|
|
assert.False(t, role.BuiltIn)
|
|
assert.True(t, role.SchemeManaged)
|
|
}
|
|
|
|
func TestImportImportTeam(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
// Mark the phase 2 permissions migration as completed.
|
|
err := th.App.Srv().Store().System().Save(&model.System{Name: model.MigrationKeyAdvancedPermissionsPhase2, Value: "true"})
|
|
require.NoError(t, err, "Failed to save system value.")
|
|
|
|
defer func() {
|
|
_, err = th.App.Srv().Store().System().PermanentDeleteByName(model.MigrationKeyAdvancedPermissionsPhase2)
|
|
require.NoError(t, err, "Failed to delete system value.")
|
|
}()
|
|
|
|
scheme1 := th.SetupTeamScheme(t)
|
|
scheme2 := th.SetupTeamScheme(t)
|
|
|
|
// Check how many teams are in the database.
|
|
teamsCount, err := th.App.Srv().Store().Team().AnalyticsTeamCount(nil)
|
|
require.NoError(t, err, "Failed to get team count.")
|
|
|
|
// we also assert that the team name can be upper case
|
|
// Note there are no reserved team names starting with `Z`, making this flake-free.
|
|
teamName := "Z" + model.NewId()
|
|
sanitizedTeamName := strings.ToLower(teamName)
|
|
|
|
data := imports.TeamImportData{
|
|
Name: new(teamName),
|
|
DisplayName: new("Display Name"),
|
|
Type: new("XYZ"),
|
|
Description: new("The team description."),
|
|
AllowOpenInvite: new(true),
|
|
Scheme: &scheme1.Name,
|
|
}
|
|
|
|
// Try importing an invalid team in dryRun mode.
|
|
err = th.App.importTeam(th.Context, &data, true)
|
|
require.Error(t, err, "Should have received an error importing an invalid team.")
|
|
|
|
// Do a valid team in dry-run mode.
|
|
data.Type = new("O")
|
|
appErr := th.App.importTeam(th.Context, &data, true)
|
|
require.Nil(t, appErr, "Received an error validating valid team.")
|
|
|
|
// Check that no more teams are in the DB.
|
|
th.CheckTeamCount(t, teamsCount)
|
|
|
|
// Do an invalid team in apply mode, check db changes.
|
|
data.Type = new("XYZ")
|
|
err = th.App.importTeam(th.Context, &data, false)
|
|
require.Error(t, err, "Import should have failed on invalid team.")
|
|
|
|
// Check that no more teams are in the DB.
|
|
th.CheckTeamCount(t, teamsCount)
|
|
|
|
// Do a valid team in apply mode, check db changes.
|
|
data.Type = new("O")
|
|
appErr = th.App.importTeam(th.Context, &data, false)
|
|
require.Nil(t, appErr, "Received an error importing valid team: %v", err)
|
|
|
|
// Check that one more team is in the DB.
|
|
th.CheckTeamCount(t, teamsCount+1)
|
|
|
|
// Get the team and check that all the fields are correct.
|
|
team, appErr := th.App.GetTeamByName(sanitizedTeamName)
|
|
require.Nil(t, appErr, "Failed to get team from database.")
|
|
|
|
assert.Equal(t, *data.DisplayName, team.DisplayName)
|
|
assert.Equal(t, *data.Type, team.Type)
|
|
assert.Equal(t, *data.Description, team.Description)
|
|
assert.Equal(t, *data.AllowOpenInvite, team.AllowOpenInvite)
|
|
assert.Equal(t, scheme1.Id, *team.SchemeId)
|
|
|
|
// Alter all the fields of that team (apart from unique identifier) and import again.
|
|
data.DisplayName = new("Display Name 2")
|
|
data.Type = new("P")
|
|
data.Description = new("The new description")
|
|
data.AllowOpenInvite = new(false)
|
|
data.Scheme = &scheme2.Name
|
|
|
|
// Check that the original number of teams are again in the DB (because this query doesn't include deleted).
|
|
data.Type = new("O")
|
|
appErr = th.App.importTeam(th.Context, &data, false)
|
|
require.Nil(t, appErr, "Received an error importing updated valid team.")
|
|
|
|
th.CheckTeamCount(t, teamsCount+1)
|
|
|
|
// Get the team and check that all fields are correct.
|
|
team, appErr = th.App.GetTeamByName(sanitizedTeamName)
|
|
require.Nil(t, appErr, "Failed to get team from database.")
|
|
|
|
assert.Equal(t, *data.DisplayName, team.DisplayName)
|
|
assert.Equal(t, *data.Type, team.Type)
|
|
assert.Equal(t, *data.Description, team.Description)
|
|
assert.Equal(t, *data.AllowOpenInvite, team.AllowOpenInvite)
|
|
assert.Equal(t, scheme2.Id, *team.SchemeId)
|
|
}
|
|
|
|
func TestImportImportChannel(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
// Mark the phase 2 permissions migration as completed.
|
|
err := th.App.Srv().Store().System().Save(&model.System{Name: model.MigrationKeyAdvancedPermissionsPhase2, Value: "true"})
|
|
require.NoError(t, err, "Failed to save system value.")
|
|
|
|
defer func() {
|
|
_, err = th.App.Srv().Store().System().PermanentDeleteByName(model.MigrationKeyAdvancedPermissionsPhase2)
|
|
require.NoError(t, err, "Failed to delete system value.")
|
|
}()
|
|
|
|
scheme1 := th.SetupChannelScheme(t)
|
|
scheme2 := th.SetupChannelScheme(t)
|
|
|
|
// Import a Team.
|
|
teamName := model.NewRandomTeamName()
|
|
appErr := th.App.importTeam(th.Context, &imports.TeamImportData{
|
|
Name: &teamName,
|
|
DisplayName: new("Display Name"),
|
|
Type: new("O"),
|
|
}, false)
|
|
require.Nil(t, appErr, "Failed to import team.")
|
|
team, appErr := th.App.GetTeamByName(teamName)
|
|
require.Nil(t, appErr, "Failed to get team from database.")
|
|
|
|
// Check how many channels are in the database.
|
|
channelCount, nErr := th.App.Srv().Store().Channel().AnalyticsTypeCount("", model.ChannelTypeOpen)
|
|
require.NoError(t, nErr, "Failed to get team count.")
|
|
|
|
// Do an invalid channel in dry-run mode.
|
|
chanOpen := model.ChannelTypeOpen
|
|
data := imports.ChannelImportData{
|
|
Team: &teamName,
|
|
DisplayName: new("Display Name"),
|
|
Type: &chanOpen,
|
|
Header: new("Channel Header"),
|
|
Purpose: new("Channel Purpose"),
|
|
Scheme: &scheme1.Name,
|
|
}
|
|
appErr = th.App.importChannel(th.Context, &data, true)
|
|
require.NotNil(t, appErr, "Expected error due to invalid name.")
|
|
|
|
// Check that no more channels are in the DB.
|
|
th.CheckChannelsCount(t, channelCount)
|
|
|
|
// Do a valid channel with a nonexistent team in dry-run mode.
|
|
data.Name = new("channelname")
|
|
data.Team = new(model.NewId())
|
|
appErr = th.App.importChannel(th.Context, &data, true)
|
|
require.Nil(t, appErr, "Expected success as cannot validate channel name in dry run mode.")
|
|
|
|
// Check that no more channels are in the DB.
|
|
th.CheckChannelsCount(t, channelCount)
|
|
|
|
// Do a valid channel in dry-run mode.
|
|
data.Team = &teamName
|
|
appErr = th.App.importChannel(th.Context, &data, true)
|
|
require.Nil(t, appErr, "Expected success as valid team.")
|
|
|
|
// Check that no more channels are in the DB.
|
|
th.CheckChannelsCount(t, channelCount)
|
|
|
|
// Do an invalid channel in apply mode.
|
|
data.Name = nil
|
|
appErr = th.App.importChannel(th.Context, &data, false)
|
|
require.NotNil(t, appErr, "Expected error due to invalid name (apply mode).")
|
|
|
|
// Check that no more channels are in the DB.
|
|
th.CheckChannelsCount(t, channelCount)
|
|
|
|
// Do a valid channel in apply mode with a non-existent team.
|
|
data.Name = new("channelname")
|
|
data.Team = new(model.NewId())
|
|
appErr = th.App.importChannel(th.Context, &data, false)
|
|
require.NotNil(t, appErr, "Expected error due to non-existent team (apply mode).")
|
|
|
|
// Check that no more channels are in the DB.
|
|
th.CheckChannelsCount(t, channelCount)
|
|
|
|
// Do a valid channel in apply mode.
|
|
data.Team = &teamName
|
|
|
|
// we also assert that the channel name can be upper case
|
|
// for the import workflow
|
|
data.Name = new("channelName")
|
|
sanitizedChannelName := strings.ToLower(*data.Name)
|
|
|
|
appErr = th.App.importChannel(th.Context, &data, false)
|
|
require.Nil(t, appErr, "Expected success in apply mode")
|
|
|
|
// Check that 1 more channel is in the DB.
|
|
th.CheckChannelsCount(t, channelCount+1)
|
|
|
|
// Get the Channel and check all the fields are correct.
|
|
channel, appErr := th.App.GetChannelByName(th.Context, sanitizedChannelName, team.Id, false)
|
|
require.Nil(t, appErr, "Failed to get channel from database.")
|
|
|
|
assert.Equal(t, sanitizedChannelName, channel.Name)
|
|
assert.Equal(t, *data.DisplayName, channel.DisplayName)
|
|
assert.Equal(t, *data.Type, channel.Type)
|
|
assert.Equal(t, *data.Header, channel.Header)
|
|
assert.Equal(t, *data.Purpose, channel.Purpose)
|
|
assert.Equal(t, scheme1.Id, *channel.SchemeId)
|
|
|
|
// Alter all the fields of that channel.
|
|
cTypePr := model.ChannelTypePrivate
|
|
data.DisplayName = new("Changed Disp Name")
|
|
data.Type = &cTypePr
|
|
data.Header = new("New Header")
|
|
data.Purpose = new("New Purpose")
|
|
data.Scheme = &scheme2.Name
|
|
appErr = th.App.importChannel(th.Context, &data, false)
|
|
require.Nil(t, appErr, "Expected success in apply mode")
|
|
|
|
// Check channel count the same.
|
|
th.CheckChannelsCount(t, channelCount)
|
|
|
|
// Get the Channel and check all the fields are correct.
|
|
channel, appErr = th.App.GetChannelByName(th.Context, sanitizedChannelName, team.Id, false)
|
|
require.Nil(t, appErr, "Failed to get channel from database.")
|
|
|
|
assert.Equal(t, sanitizedChannelName, channel.Name)
|
|
assert.Equal(t, *data.DisplayName, channel.DisplayName)
|
|
assert.Equal(t, *data.Type, channel.Type)
|
|
assert.Equal(t, *data.Header, channel.Header)
|
|
assert.Equal(t, *data.Purpose, channel.Purpose)
|
|
assert.Equal(t, scheme2.Id, *channel.SchemeId)
|
|
|
|
// Do a valid archived channel.
|
|
now := model.GetMillis()
|
|
data.Name = new("archivedchannel")
|
|
data.DisplayName = new("Archived Channel")
|
|
data.Type = &chanOpen
|
|
data.Header = new("Archived Channel Header")
|
|
data.Purpose = new("Archived Channel Purpose")
|
|
data.Scheme = &scheme1.Name
|
|
data.DeletedAt = &now
|
|
appErr = th.App.importChannel(th.Context, &data, false)
|
|
require.Nil(t, appErr, "Expected success in apply mode")
|
|
aChan, appErr := th.App.GetChannelByName(th.Context, sanitizedChannelName, team.Id, true)
|
|
require.Nil(t, appErr, "Failed to get channel from database.")
|
|
assert.Equal(t, sanitizedChannelName, aChan.Name)
|
|
}
|
|
|
|
func TestImportImportUser(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
// Check how many users are in the database.
|
|
userCount, cErr := th.App.Srv().Store().User().Count(model.UserCountOptions{
|
|
IncludeDeleted: true,
|
|
IncludeBotAccounts: false,
|
|
})
|
|
require.NoError(t, cErr, "Failed to get user count.")
|
|
|
|
t.Run("import an invalid user in dry-run", func(t *testing.T) {
|
|
data := imports.UserImportData{
|
|
Username: new(model.NewUsername()),
|
|
}
|
|
appErr := th.App.importUser(th.Context, &data, true)
|
|
require.NotNil(t, appErr, "Should have failed to import invalid user.")
|
|
|
|
// Check that no more users are in the DB.
|
|
userCountCurrent, err := th.App.Srv().Store().User().Count(model.UserCountOptions{
|
|
IncludeDeleted: true,
|
|
IncludeBotAccounts: false,
|
|
})
|
|
require.NoError(t, err, "Failed to get user count.")
|
|
assert.Equal(t, userCount, userCountCurrent, "Unexpected number of users")
|
|
})
|
|
|
|
t.Run("import a valid user in dry-run", func(t *testing.T) {
|
|
data := imports.UserImportData{
|
|
Username: new(model.NewUsername()),
|
|
Email: new(model.NewId() + "@example.com"),
|
|
}
|
|
appErr := th.App.importUser(th.Context, &data, true)
|
|
require.Nil(t, appErr, "Should have succeeded to import valid user.")
|
|
|
|
// Check that no more users are in the DB.
|
|
userCountCurrent, err := th.App.Srv().Store().User().Count(model.UserCountOptions{
|
|
IncludeDeleted: true,
|
|
IncludeBotAccounts: false,
|
|
})
|
|
require.NoError(t, err, "Failed to get user count.")
|
|
assert.Equal(t, userCount, userCountCurrent, "Unexpected number of users")
|
|
})
|
|
|
|
t.Run("import an invalid user in apply mode", func(t *testing.T) {
|
|
data := imports.UserImportData{
|
|
Username: new(model.NewUsername()),
|
|
}
|
|
appErr := th.App.importUser(th.Context, &data, false)
|
|
require.NotNil(t, appErr, "Should have failed to import invalid user.")
|
|
|
|
// Check that no more users are in the DB.
|
|
userCountCurrent, err := th.App.Srv().Store().User().Count(model.UserCountOptions{
|
|
IncludeDeleted: true,
|
|
IncludeBotAccounts: false,
|
|
})
|
|
require.NoError(t, err, "Failed to get user count.")
|
|
assert.Equal(t, userCount, userCountCurrent, "Unexpected number of users")
|
|
})
|
|
|
|
t.Run("import a valid user in apply mode", func(t *testing.T) {
|
|
username := "A" + model.NewUsername()[1:]
|
|
testsDir, _ := fileutils.FindDir("tests")
|
|
data := imports.UserImportData{
|
|
Avatar: imports.Avatar{
|
|
ProfileImage: new(filepath.Join(testsDir, "test.png")),
|
|
},
|
|
Username: &username,
|
|
Email: new(model.NewId() + "@example.com"),
|
|
Nickname: new(model.NewId()),
|
|
FirstName: new(model.NewId()),
|
|
LastName: new(model.NewId()),
|
|
Position: new(model.NewId()),
|
|
}
|
|
appErr := th.App.importUser(th.Context, &data, false)
|
|
require.Nil(t, appErr, "Should have succeeded to import valid user.")
|
|
|
|
// Check that one more user is in the DB.
|
|
userCountCurrent, err := th.App.Srv().Store().User().Count(model.UserCountOptions{
|
|
IncludeDeleted: true,
|
|
IncludeBotAccounts: false,
|
|
})
|
|
require.NoError(t, err, "Failed to get user count.")
|
|
userCount++ // Increment the user count.
|
|
assert.Equal(t, userCount, userCountCurrent, "Unexpected number of users")
|
|
|
|
// Get the user and check all the fields are correct.
|
|
user, err2 := th.App.GetUserByUsername(username)
|
|
require.Nil(t, err2, "Failed to get user from database.")
|
|
|
|
assert.Equal(t, *data.Email, user.Email)
|
|
assert.Equal(t, *data.Nickname, user.Nickname)
|
|
assert.Equal(t, *data.FirstName, user.FirstName)
|
|
assert.Equal(t, *data.LastName, user.LastName)
|
|
assert.Equal(t, *data.Position, user.Position)
|
|
|
|
// Check calculated properties.
|
|
require.Equal(t, strings.ToLower(username), user.Username, "Expected Username to be lower case.")
|
|
require.Empty(t, user.AuthService, "Expected Auth Service to be empty.")
|
|
require.Empty(t, user.AuthData, "Expected AuthData to be empty.")
|
|
require.NotEmpty(t, user.Password, "Expected password to be set.")
|
|
require.True(t, user.EmailVerified, "Expected EmailVerified to be true.")
|
|
require.Equal(t, user.Locale, *th.App.Config().LocalizationSettings.DefaultClientLocale, "Expected Locale to be the default.")
|
|
require.Equal(t, user.Roles, "system_user", "Expected roles to be system_user")
|
|
})
|
|
|
|
t.Run("import a valid user where there is an existing user", func(t *testing.T) {
|
|
username := model.NewUsername()
|
|
testsDir, _ := fileutils.FindDir("tests")
|
|
data := imports.UserImportData{
|
|
Avatar: imports.Avatar{
|
|
ProfileImage: new(filepath.Join(testsDir, "test.png")),
|
|
},
|
|
Username: &username,
|
|
Email: new(model.NewId() + "@example.com"),
|
|
Nickname: new(model.NewId()),
|
|
FirstName: new(model.NewId()),
|
|
LastName: new(model.NewId()),
|
|
Position: new(model.NewId()),
|
|
}
|
|
appErr := th.App.importUser(th.Context, &data, false)
|
|
require.Nil(t, appErr, "Should have succeeded to import valid user.")
|
|
|
|
// Check that one more user is in the DB.
|
|
userCountCurrent, err := th.App.Srv().Store().User().Count(model.UserCountOptions{
|
|
IncludeDeleted: true,
|
|
IncludeBotAccounts: false,
|
|
})
|
|
require.NoError(t, err, "Failed to get user count.")
|
|
userCount++ // Increment the user count.
|
|
assert.Equal(t, userCount, userCountCurrent, "Unexpected number of users")
|
|
|
|
// Alter all the fields of that user.
|
|
data.Email = new(model.NewId() + "@example.com")
|
|
data.ProfileImage = new(filepath.Join(testsDir, "testgif.gif"))
|
|
data.AuthService = new("ldap")
|
|
data.AuthData = &username
|
|
data.Nickname = new(model.NewId())
|
|
data.FirstName = new(model.NewId())
|
|
data.LastName = new(model.NewId())
|
|
data.Position = new(model.NewId())
|
|
data.Roles = new("system_admin system_user")
|
|
data.Locale = new("zh_CN")
|
|
|
|
appErr = th.App.importUser(th.Context, &data, false)
|
|
require.Nil(t, appErr, "Should have succeeded to update valid user %v", err)
|
|
|
|
// Check user count the same.
|
|
userCountCurrent, err = th.App.Srv().Store().User().Count(model.UserCountOptions{
|
|
IncludeDeleted: true,
|
|
IncludeBotAccounts: false,
|
|
})
|
|
require.NoError(t, err, "Failed to get user count.")
|
|
assert.Equal(t, userCount, userCountCurrent, "Unexpected number of users")
|
|
|
|
// Get the user and check all the fields are correct.
|
|
user, err2 := th.App.GetUserByUsername(username)
|
|
require.Nil(t, err2, "Failed to get user from database.")
|
|
|
|
assert.Equal(t, *data.Email, user.Email)
|
|
assert.Equal(t, *data.Nickname, user.Nickname)
|
|
assert.Equal(t, *data.FirstName, user.FirstName)
|
|
assert.Equal(t, *data.LastName, user.LastName)
|
|
assert.Equal(t, *data.Position, user.Position)
|
|
|
|
require.Equal(t, "ldap", user.AuthService, "Expected Auth Service to be ldap \"%v\"", user.AuthService)
|
|
require.Equal(t, user.AuthData, data.AuthData, "Expected AuthData to be set.")
|
|
require.Empty(t, user.Password, "Expected password to be empty.")
|
|
require.True(t, user.EmailVerified, "Expected EmailVerified to be true.")
|
|
require.Equal(t, *data.Locale, user.Locale, "Expected Locale to be the set.")
|
|
require.Equal(t, *data.Roles, user.Roles, "Expected roles to be set: %v", user.Roles)
|
|
})
|
|
|
|
t.Run("import invalid fields", func(t *testing.T) {
|
|
username := model.NewUsername()
|
|
testsDir, _ := fileutils.FindDir("tests")
|
|
data := imports.UserImportData{
|
|
Avatar: imports.Avatar{
|
|
ProfileImage: new(filepath.Join(testsDir, "test.png")),
|
|
},
|
|
Username: &username,
|
|
Email: new(model.NewId() + "@example.com"),
|
|
Nickname: new(model.NewId()),
|
|
FirstName: new(model.NewId()),
|
|
LastName: new(model.NewId()),
|
|
Position: new(model.NewId()),
|
|
AuthData: &username,
|
|
AuthService: new("ldap"),
|
|
}
|
|
appErr := th.App.importUser(th.Context, &data, false)
|
|
require.Nil(t, appErr, "Should have succeeded to import valid user.")
|
|
|
|
// Check that one more user is in the DB.
|
|
userCountCurrent, err := th.App.Srv().Store().User().Count(model.UserCountOptions{
|
|
IncludeDeleted: true,
|
|
IncludeBotAccounts: false,
|
|
})
|
|
require.NoError(t, err, "Failed to get user count.")
|
|
userCount++ // Increment the user count.
|
|
assert.Equal(t, userCount, userCountCurrent, "Unexpected number of users")
|
|
|
|
// Check Password and AuthData together.
|
|
data.Password = new(model.NewTestPassword())
|
|
appErr = th.App.importUser(th.Context, &data, false)
|
|
require.NotNil(t, appErr, "Should have failed to import invalid user.")
|
|
|
|
data.AuthData = nil
|
|
data.AuthService = nil
|
|
appErr = th.App.importUser(th.Context, &data, false)
|
|
require.Nil(t, appErr, "Should have succeeded to update valid user %v", err)
|
|
|
|
data.Password = new("")
|
|
appErr = th.App.importUser(th.Context, &data, false)
|
|
require.NotNil(t, appErr, "Should have failed to import invalid user.")
|
|
|
|
data.Password = new(strings.Repeat("0123456789", 10))
|
|
appErr = th.App.importUser(th.Context, &data, false)
|
|
require.NotNil(t, appErr, "Should have failed to import invalid user.")
|
|
|
|
// Check that no more user is in the DB.
|
|
userCountCurrent, err = th.App.Srv().Store().User().Count(model.UserCountOptions{
|
|
IncludeDeleted: true,
|
|
IncludeBotAccounts: false,
|
|
})
|
|
require.NoError(t, err, "Failed to get user count.")
|
|
assert.Equal(t, userCount, userCountCurrent, "Unexpected number of users")
|
|
})
|
|
|
|
t.Run("import with team and channel memberships", func(t *testing.T) {
|
|
teamName := model.NewRandomTeamName()
|
|
tAppErr := th.App.importTeam(th.Context, &imports.TeamImportData{
|
|
Name: &teamName,
|
|
DisplayName: new("Display Name"),
|
|
Type: new("O"),
|
|
}, false)
|
|
require.Nil(t, tAppErr, "Failed to import team.")
|
|
team, appErr := th.App.GetTeamByName(teamName)
|
|
require.Nil(t, appErr, "Failed to get team from database.")
|
|
|
|
channelName := model.NewId()
|
|
chanTypeOpen := model.ChannelTypeOpen
|
|
appErr = th.App.importChannel(th.Context, &imports.ChannelImportData{
|
|
Team: &teamName,
|
|
Name: &channelName,
|
|
DisplayName: new("Display Name"),
|
|
Type: &chanTypeOpen,
|
|
}, false)
|
|
require.Nil(t, appErr, "Failed to import channel.")
|
|
channel, appErr := th.App.GetChannelByName(th.Context, channelName, team.Id, false)
|
|
require.Nil(t, appErr, "Failed to get channel from database.")
|
|
|
|
username := model.NewUsername()
|
|
data := imports.UserImportData{
|
|
Username: &username,
|
|
Email: new(model.NewId() + "@example.com"),
|
|
Nickname: new(model.NewId()),
|
|
FirstName: new(model.NewId()),
|
|
LastName: new(model.NewId()),
|
|
Position: new(model.NewId()),
|
|
}
|
|
|
|
teamMembers, appErr := th.App.GetTeamMembers(team.Id, 0, 1000, nil)
|
|
require.Nil(t, appErr, "Failed to get team member count")
|
|
teamMemberCount := len(teamMembers)
|
|
|
|
channelMemberCount, appErr := th.App.GetChannelMemberCount(th.Context, channel.Id)
|
|
require.Nil(t, appErr, "Failed to get channel member count")
|
|
|
|
t.Run("invalid team and channel memberships in dry-run mode", func(t *testing.T) {
|
|
data.Teams = &[]imports.UserTeamImportData{
|
|
{
|
|
Roles: new("invalid"),
|
|
Channels: &[]imports.UserChannelImportData{
|
|
{
|
|
Roles: new("invalid"),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
appErr = th.App.importUser(th.Context, &data, true)
|
|
assert.NotNil(t, appErr)
|
|
})
|
|
|
|
t.Run("unknown team name & invalid channel membership in dry-run mode", func(t *testing.T) {
|
|
data.Teams = &[]imports.UserTeamImportData{
|
|
{
|
|
Name: new(model.NewId()),
|
|
Channels: &[]imports.UserChannelImportData{
|
|
{
|
|
Roles: new("invalid"),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
appErr = th.App.importUser(th.Context, &data, true)
|
|
assert.NotNil(t, appErr)
|
|
})
|
|
|
|
t.Run("valid team & invalid channel membership in dry-run mode", func(t *testing.T) {
|
|
data.Teams = &[]imports.UserTeamImportData{
|
|
{
|
|
Name: &teamName,
|
|
Channels: &[]imports.UserChannelImportData{
|
|
{
|
|
Roles: new("invalid"),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
appErr = th.App.importUser(th.Context, &data, true)
|
|
assert.NotNil(t, appErr)
|
|
})
|
|
|
|
t.Run("valid team & unknown channel name in dry-run mode", func(t *testing.T) {
|
|
data.Teams = &[]imports.UserTeamImportData{
|
|
{
|
|
Name: &teamName,
|
|
Channels: &[]imports.UserChannelImportData{
|
|
{
|
|
Name: new(model.NewId()),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
appErr = th.App.importUser(th.Context, &data, true)
|
|
assert.Nil(t, appErr)
|
|
})
|
|
|
|
t.Run("valid team & valid channel name in dry-run mode", func(t *testing.T) {
|
|
data.Teams = &[]imports.UserTeamImportData{
|
|
{
|
|
Name: &teamName,
|
|
Channels: &[]imports.UserChannelImportData{
|
|
{
|
|
Name: &channelName,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
appErr = th.App.importUser(th.Context, &data, true)
|
|
assert.Nil(t, appErr)
|
|
|
|
// Check no new member objects were created because dry run mode.
|
|
tmc, appErr2 := th.App.GetTeamMembers(team.Id, 0, 1000, nil)
|
|
require.Nil(t, appErr2, "Failed to get Team Member Count")
|
|
require.Len(t, tmc, teamMemberCount, "Number of team members not as expected")
|
|
|
|
cmc, appErr2 := th.App.GetChannelMemberCount(th.Context, channel.Id)
|
|
require.Nil(t, appErr2, "Failed to get Channel Member Count")
|
|
require.Equal(t, channelMemberCount, cmc, "Number of channel members not as expected")
|
|
})
|
|
|
|
t.Run("invalid team & channel membership in apply mode", func(t *testing.T) {
|
|
data.Teams = &[]imports.UserTeamImportData{
|
|
{
|
|
Roles: new("invalid"),
|
|
Channels: &[]imports.UserChannelImportData{
|
|
{
|
|
Roles: new("invalid"),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
appErr = th.App.importUser(th.Context, &data, false)
|
|
assert.NotNil(t, appErr)
|
|
})
|
|
|
|
t.Run("unknown team name & invalid channel membership in apply mode", func(t *testing.T) {
|
|
data.Teams = &[]imports.UserTeamImportData{
|
|
{
|
|
Name: new(model.NewId()),
|
|
Channels: &[]imports.UserChannelImportData{
|
|
{
|
|
Roles: new("invalid"),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
appErr = th.App.importUser(th.Context, &data, false)
|
|
assert.NotNil(t, appErr)
|
|
})
|
|
|
|
t.Run("import with valid team and invalid channel memberships in apply mode", func(t *testing.T) {
|
|
data.Teams = &[]imports.UserTeamImportData{
|
|
{
|
|
Name: &teamName,
|
|
Channels: &[]imports.UserChannelImportData{
|
|
{
|
|
Roles: new("invalid"),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
appErr = th.App.importUser(th.Context, &data, false)
|
|
assert.NotNil(t, appErr)
|
|
|
|
// Check no new member objects were created because all tests should have failed so far.
|
|
tmc, appErr2 := th.App.GetTeamMembers(team.Id, 0, 1000, nil)
|
|
require.Nil(t, appErr2, "Failed to get Team Member Count")
|
|
require.Len(t, tmc, teamMemberCount)
|
|
|
|
cmc, appErr2 := th.App.GetChannelMemberCount(th.Context, channel.Id)
|
|
require.Nil(t, appErr2, "Failed to get Channel Member Count")
|
|
require.Equal(t, channelMemberCount, cmc)
|
|
})
|
|
|
|
t.Run("valid team & unknown channel name in apply mode", func(t *testing.T) {
|
|
data.Teams = &[]imports.UserTeamImportData{
|
|
{
|
|
Name: &teamName,
|
|
Channels: &[]imports.UserChannelImportData{
|
|
{
|
|
Name: new(model.NewId()),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
appErr = th.App.importUser(th.Context, &data, false)
|
|
assert.NotNil(t, appErr)
|
|
|
|
// Check only new team member object created because dry run mode.
|
|
tmc, appErr2 := th.App.GetTeamMembers(team.Id, 0, 1000, nil)
|
|
require.Nil(t, appErr2, "Failed to get Team Member Count")
|
|
teamMemberCount++
|
|
require.Len(t, tmc, teamMemberCount)
|
|
|
|
cmc, appErr2 := th.App.GetChannelMemberCount(th.Context, channel.Id)
|
|
require.Nil(t, appErr2, "Failed to get Channel Member Count")
|
|
require.Equal(t, channelMemberCount, cmc)
|
|
|
|
// Check team member properties.
|
|
user, appErr2 := th.App.GetUserByUsername(username)
|
|
require.Nil(t, appErr2, "Failed to get user from database.")
|
|
|
|
teamMember, appErr2 := th.App.GetTeamMember(th.Context, team.Id, user.Id)
|
|
require.Nil(t, appErr2, "Failed to get team member from database.")
|
|
require.Equal(t, "team_user", teamMember.Roles)
|
|
})
|
|
|
|
t.Run("valid team & valid channel name in apply mode", func(t *testing.T) {
|
|
data.Teams = &[]imports.UserTeamImportData{
|
|
{
|
|
Name: &teamName,
|
|
Channels: &[]imports.UserChannelImportData{
|
|
{
|
|
Name: &channelName,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
// convert to a new user
|
|
username = model.NewUsername()
|
|
data.Username = &username
|
|
data.Email = new(model.NewId() + "@example.com")
|
|
appErr2 := th.App.importUser(th.Context, &data, false)
|
|
assert.Nil(t, appErr2)
|
|
|
|
// Check only new channel member object created because dry run mode.
|
|
tmc, appErr2 := th.App.GetTeamMembers(team.Id, 0, 1000, nil)
|
|
require.Nil(t, appErr2, "Failed to get Team Member Count")
|
|
teamMemberCount++
|
|
require.Len(t, tmc, teamMemberCount, "Number of team members not as expected")
|
|
|
|
cmc, appErr2 := th.App.GetChannelMemberCount(th.Context, channel.Id)
|
|
require.Nil(t, appErr2, "Failed to get Channel Member Count")
|
|
channelMemberCount++
|
|
require.Equal(t, channelMemberCount, cmc, "Number of channel members not as expected")
|
|
|
|
user, err2 := th.App.GetUserByUsername(username)
|
|
require.Nil(t, err2, "Failed to get user from database.")
|
|
|
|
// Check channel member properties.
|
|
channelMember, appErr2 := th.App.GetChannelMember(th.Context, channel.Id, user.Id)
|
|
require.Nil(t, appErr2, "Failed to get channel member from database.")
|
|
assert.Equal(t, "channel_user", channelMember.Roles)
|
|
assert.Equal(t, "default", channelMember.NotifyProps[model.DesktopNotifyProp])
|
|
assert.Equal(t, "default", channelMember.NotifyProps[model.PushNotifyProp])
|
|
assert.Equal(t, "all", channelMember.NotifyProps[model.MarkUnreadNotifyProp])
|
|
})
|
|
|
|
t.Run("test with the properties of the team and channel membership changed", func(t *testing.T) {
|
|
data.Teams = &[]imports.UserTeamImportData{
|
|
{
|
|
Name: &teamName,
|
|
Theme: new(`{"awayIndicator":"#DBBD4E","buttonBg":"#23A1FF","buttonColor":"#FFFFFF","centerChannelBg":"#ffffff","centerChannelColor":"#333333","codeTheme":"github","image":"/static/files/a4a388b38b32678e83823ef1b3e17766.png","linkColor":"#2389d7","mentionBg":"#2389d7","mentionColor":"#ffffff","mentionHighlightBg":"#fff2bb","mentionHighlightLink":"#2f81b7","newMessageSeparator":"#FF8800","onlineIndicator":"#7DBE00","sidebarBg":"#fafafa","sidebarHeaderBg":"#3481B9","sidebarHeaderTextColor":"#ffffff","sidebarText":"#333333","sidebarTextActiveBorder":"#378FD2","sidebarTextActiveColor":"#111111","sidebarTextHoverBg":"#e6f2fa","sidebarUnreadText":"#333333","type":"Mattermost"}`),
|
|
Roles: new("team_user team_admin"),
|
|
Channels: &[]imports.UserChannelImportData{
|
|
{
|
|
Name: &channelName,
|
|
Roles: new("channel_user channel_admin"),
|
|
NotifyProps: &imports.UserChannelNotifyPropsImportData{
|
|
Desktop: model.NewPointer(model.UserNotifyMention),
|
|
Mobile: model.NewPointer(model.UserNotifyMention),
|
|
MarkUnread: model.NewPointer(model.UserNotifyMention),
|
|
},
|
|
Favorite: new(true),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
// convert to a new user
|
|
username = model.NewUsername()
|
|
data.Username = &username
|
|
data.Email = new(model.NewId() + "@example.com")
|
|
|
|
appErr2 := th.App.importUser(th.Context, &data, false)
|
|
assert.Nil(t, appErr2)
|
|
|
|
user, err2 := th.App.GetUserByUsername(username)
|
|
require.Nil(t, err2, "Failed to get user from database.")
|
|
|
|
// Check both member properties.
|
|
teamMember, appErr2 := th.App.GetTeamMember(th.Context, team.Id, user.Id)
|
|
require.Nil(t, appErr2, "Failed to get team member from database.")
|
|
require.Equal(t, "team_user team_admin", teamMember.Roles)
|
|
|
|
channelMember, appErr2 := th.App.GetChannelMember(th.Context, channel.Id, user.Id)
|
|
require.Nil(t, appErr2, "Failed to get channel member Desktop from database.")
|
|
assert.Equal(t, "channel_user channel_admin", channelMember.Roles)
|
|
assert.Equal(t, model.UserNotifyMention, channelMember.NotifyProps[model.DesktopNotifyProp])
|
|
assert.Equal(t, model.UserNotifyMention, channelMember.NotifyProps[model.PushNotifyProp])
|
|
assert.Equal(t, model.UserNotifyMention, channelMember.NotifyProps[model.MarkUnreadNotifyProp])
|
|
|
|
checkPreference(t, th.App, user.Id, model.PreferenceCategoryFavoriteChannel, channel.Id, "true")
|
|
checkPreference(t, th.App, user.Id, model.PreferenceCategoryTheme, team.Id, *(*data.Teams)[0].Theme)
|
|
|
|
// No more new member objects.
|
|
tmc, appErr2 := th.App.GetTeamMembers(team.Id, 0, 1000, nil)
|
|
require.Nil(t, appErr2, "Failed to get Team Member Count")
|
|
require.Len(t, tmc, teamMemberCount+1, "Number of team members not as expected")
|
|
|
|
cmc, appErr2 := th.App.GetChannelMemberCount(th.Context, channel.Id)
|
|
require.Nil(t, appErr2, "Failed to get Channel Member Count")
|
|
require.Equal(t, channelMemberCount+1, cmc, "Number of channel members not as expected")
|
|
})
|
|
})
|
|
|
|
t.Run("add a user with some preferences.", func(t *testing.T) {
|
|
teamName := model.NewRandomTeamName()
|
|
appErr2 := th.App.importTeam(th.Context, &imports.TeamImportData{
|
|
Name: &teamName,
|
|
DisplayName: new("Display Name"),
|
|
Type: new("O"),
|
|
}, false)
|
|
require.Nil(t, appErr2, "Failed to import team.")
|
|
|
|
channelName := model.NewId()
|
|
chanTypeOpen := model.ChannelTypeOpen
|
|
appErr2 = th.App.importChannel(th.Context, &imports.ChannelImportData{
|
|
Team: &teamName,
|
|
Name: &channelName,
|
|
DisplayName: new("Display Name"),
|
|
Type: &chanTypeOpen,
|
|
}, false)
|
|
require.Nil(t, appErr2, "Failed to import channel.")
|
|
|
|
username := model.NewUsername()
|
|
data := imports.UserImportData{
|
|
Username: &username,
|
|
Email: new(model.NewId() + "@example.com"),
|
|
Theme: new(`{"awayIndicator":"#DCBD4E","buttonBg":"#23A2FF","buttonColor":"#FFFFFF","centerChannelBg":"#ffffff","centerChannelColor":"#333333","codeTheme":"github","image":"/static/files/a4a388b38b32678e83823ef1b3e17766.png","linkColor":"#2389d7","mentionBg":"#2389d7","mentionColor":"#ffffff","mentionHighlightBg":"#fff2bb","mentionHighlightLink":"#2f81b7","newMessageSeparator":"#FF8800","onlineIndicator":"#7DBE00","sidebarBg":"#fafafa","sidebarHeaderBg":"#3481B9","sidebarHeaderTextColor":"#ffffff","sidebarText":"#333333","sidebarTextActiveBorder":"#378FD2","sidebarTextActiveColor":"#111111","sidebarTextHoverBg":"#e6f2fa","sidebarUnreadText":"#333333","type":"Mattermost"}`),
|
|
UseMilitaryTime: new("true"),
|
|
CollapsePreviews: new("true"),
|
|
MessageDisplay: new("compact"),
|
|
ColorizeUsernames: new("true"),
|
|
ChannelDisplayMode: new("centered"),
|
|
TutorialStep: new("3"),
|
|
UseMarkdownPreview: new("true"),
|
|
UseFormatting: new("true"),
|
|
ShowUnreadSection: new("true"),
|
|
EmailInterval: new("immediately"),
|
|
NameFormat: new("full_name"),
|
|
SendOnCtrlEnter: new("true"),
|
|
CodeBlockCtrlEnter: new("true"),
|
|
ShowJoinLeave: new("false"),
|
|
SyncDrafts: new("false"),
|
|
ShowUnreadScrollPosition: new("start_from_newest"),
|
|
LimitVisibleDmsGms: new("20"),
|
|
}
|
|
appErr2 = th.App.importUser(th.Context, &data, false)
|
|
assert.Nil(t, appErr2)
|
|
|
|
// Check their values.
|
|
user, appErr2 := th.App.GetUserByUsername(username)
|
|
require.Nil(t, appErr2, "Failed to get user from database.")
|
|
|
|
checkPreference(t, th.App, user.Id, model.PreferenceCategoryTheme, "", *data.Theme)
|
|
checkPreference(t, th.App, user.Id, model.PreferenceCategoryDisplaySettings, model.PreferenceNameUseMilitaryTime, *data.UseMilitaryTime)
|
|
checkPreference(t, th.App, user.Id, model.PreferenceCategoryDisplaySettings, model.PreferenceNameCollapseSetting, *data.CollapsePreviews)
|
|
checkPreference(t, th.App, user.Id, model.PreferenceCategoryDisplaySettings, model.PreferenceNameMessageDisplay, *data.MessageDisplay)
|
|
checkPreference(t, th.App, user.Id, model.PreferenceCategoryDisplaySettings, model.PreferenceNameColorizeUsernames, *data.ColorizeUsernames)
|
|
checkPreference(t, th.App, user.Id, model.PreferenceCategoryDisplaySettings, model.PreferenceNameChannelDisplayMode, *data.ChannelDisplayMode)
|
|
checkPreference(t, th.App, user.Id, model.PreferenceCategoryTutorialSteps, user.Id, *data.TutorialStep)
|
|
checkPreference(t, th.App, user.Id, model.PreferenceCategoryAdvancedSettings, "feature_enabled_markdown_preview", *data.UseMarkdownPreview)
|
|
checkPreference(t, th.App, user.Id, model.PreferenceCategoryAdvancedSettings, "formatting", *data.UseFormatting)
|
|
checkPreference(t, th.App, user.Id, model.PreferenceCategorySidebarSettings, "show_unread_section", *data.ShowUnreadSection)
|
|
checkPreference(t, th.App, user.Id, model.PreferenceCategoryDisplaySettings, model.PreferenceNameNameFormat, "full_name")
|
|
checkPreference(t, th.App, user.Id, model.PreferenceCategoryAdvancedSettings, "send_on_ctrl_enter", "true")
|
|
checkPreference(t, th.App, user.Id, model.PreferenceCategoryAdvancedSettings, "code_block_ctrl_enter", "true")
|
|
checkPreference(t, th.App, user.Id, model.PreferenceCategoryAdvancedSettings, "join_leave", "false")
|
|
checkPreference(t, th.App, user.Id, model.PreferenceCategoryAdvancedSettings, "sync_drafts", "false")
|
|
checkPreference(t, th.App, user.Id, model.PreferenceCategoryAdvancedSettings, "unread_scroll_position", "start_from_newest")
|
|
checkPreference(t, th.App, user.Id, model.PreferenceCategorySidebarSettings, model.PreferenceLimitVisibleDmsGms, "20")
|
|
|
|
// Change those preferences.
|
|
data = imports.UserImportData{
|
|
Username: &username,
|
|
Email: new(model.NewId() + "@example.com"),
|
|
Theme: new(`{"awayIndicator":"#123456","buttonBg":"#23A2FF","buttonColor":"#FFFFFF","centerChannelBg":"#ffffff","centerChannelColor":"#333333","codeTheme":"github","image":"/static/files/a4a388b38b32678e83823ef1b3e17766.png","linkColor":"#2389d7","mentionBg":"#2389d7","mentionColor":"#ffffff","mentionHighlightBg":"#fff2bb","mentionHighlightLink":"#2f81b7","newMessageSeparator":"#FF8800","onlineIndicator":"#7DBE00","sidebarBg":"#fafafa","sidebarHeaderBg":"#3481B9","sidebarHeaderTextColor":"#ffffff","sidebarText":"#333333","sidebarTextActiveBorder":"#378FD2","sidebarTextActiveColor":"#111111","sidebarTextHoverBg":"#e6f2fa","sidebarUnreadText":"#333333","type":"Mattermost"}`),
|
|
UseMilitaryTime: new("false"),
|
|
CollapsePreviews: new("false"),
|
|
MessageDisplay: new("clean"),
|
|
ColorizeUsernames: new("false"),
|
|
ChannelDisplayMode: new("full"),
|
|
TutorialStep: new("2"),
|
|
EmailInterval: new("hour"),
|
|
}
|
|
appErr2 = th.App.importUser(th.Context, &data, false)
|
|
assert.Nil(t, appErr2)
|
|
|
|
// Check their values again.
|
|
checkPreference(t, th.App, user.Id, model.PreferenceCategoryTheme, "", *data.Theme)
|
|
checkPreference(t, th.App, user.Id, model.PreferenceCategoryDisplaySettings, model.PreferenceNameUseMilitaryTime, *data.UseMilitaryTime)
|
|
checkPreference(t, th.App, user.Id, model.PreferenceCategoryDisplaySettings, model.PreferenceNameCollapseSetting, *data.CollapsePreviews)
|
|
checkPreference(t, th.App, user.Id, model.PreferenceCategoryDisplaySettings, model.PreferenceNameMessageDisplay, *data.MessageDisplay)
|
|
checkPreference(t, th.App, user.Id, model.PreferenceCategoryDisplaySettings, model.PreferenceNameColorizeUsernames, *data.ColorizeUsernames)
|
|
checkPreference(t, th.App, user.Id, model.PreferenceCategoryDisplaySettings, model.PreferenceNameChannelDisplayMode, *data.ChannelDisplayMode)
|
|
checkPreference(t, th.App, user.Id, model.PreferenceCategoryTutorialSteps, user.Id, *data.TutorialStep)
|
|
checkPreference(t, th.App, user.Id, model.PreferenceCategoryNotifications, model.PreferenceNameEmailInterval, "3600")
|
|
|
|
// Set Notify Without mention keys
|
|
data.NotifyProps = &imports.UserNotifyPropsImportData{
|
|
Desktop: model.NewPointer(model.UserNotifyAll),
|
|
DesktopSound: new("true"),
|
|
Email: new("true"),
|
|
Mobile: model.NewPointer(model.UserNotifyAll),
|
|
MobilePushStatus: model.NewPointer(model.StatusOnline),
|
|
ChannelTrigger: new("true"),
|
|
CommentsTrigger: model.NewPointer(model.CommentsNotifyRoot),
|
|
}
|
|
appErr2 = th.App.importUser(th.Context, &data, false)
|
|
assert.Nil(t, appErr2)
|
|
|
|
user, appErr2 = th.App.GetUserByUsername(username)
|
|
require.Nil(t, appErr2, "Failed to get user from database.")
|
|
|
|
checkNotifyProp(t, user, model.DesktopNotifyProp, model.UserNotifyAll)
|
|
checkNotifyProp(t, user, model.DesktopSoundNotifyProp, "true")
|
|
checkNotifyProp(t, user, model.EmailNotifyProp, "true")
|
|
checkNotifyProp(t, user, model.PushNotifyProp, model.UserNotifyAll)
|
|
checkNotifyProp(t, user, model.PushStatusNotifyProp, model.StatusOnline)
|
|
checkNotifyProp(t, user, model.ChannelMentionsNotifyProp, "true")
|
|
checkNotifyProp(t, user, model.CommentsNotifyProp, model.CommentsNotifyRoot)
|
|
checkNotifyProp(t, user, model.MentionKeysNotifyProp, "")
|
|
|
|
// Set Notify Props with Mention keys
|
|
data.NotifyProps = &imports.UserNotifyPropsImportData{
|
|
Desktop: model.NewPointer(model.UserNotifyAll),
|
|
DesktopSound: new("true"),
|
|
Email: new("true"),
|
|
Mobile: model.NewPointer(model.UserNotifyAll),
|
|
MobilePushStatus: model.NewPointer(model.StatusOnline),
|
|
ChannelTrigger: new("true"),
|
|
CommentsTrigger: model.NewPointer(model.CommentsNotifyRoot),
|
|
MentionKeys: new("valid,misc"),
|
|
}
|
|
appErr2 = th.App.importUser(th.Context, &data, false)
|
|
assert.Nil(t, appErr2)
|
|
|
|
user, appErr2 = th.App.GetUserByUsername(username)
|
|
require.Nil(t, appErr2, "Failed to get user from database.")
|
|
|
|
checkNotifyProp(t, user, model.DesktopNotifyProp, model.UserNotifyAll)
|
|
checkNotifyProp(t, user, model.DesktopSoundNotifyProp, "true")
|
|
checkNotifyProp(t, user, model.EmailNotifyProp, "true")
|
|
checkNotifyProp(t, user, model.PushNotifyProp, model.UserNotifyAll)
|
|
checkNotifyProp(t, user, model.PushStatusNotifyProp, model.StatusOnline)
|
|
checkNotifyProp(t, user, model.ChannelMentionsNotifyProp, "true")
|
|
checkNotifyProp(t, user, model.CommentsNotifyProp, model.CommentsNotifyRoot)
|
|
checkNotifyProp(t, user, model.MentionKeysNotifyProp, "valid,misc")
|
|
|
|
// Change Notify Props with mention keys
|
|
data.NotifyProps = &imports.UserNotifyPropsImportData{
|
|
Desktop: model.NewPointer(model.UserNotifyMention),
|
|
DesktopSound: new("false"),
|
|
Email: new("false"),
|
|
Mobile: model.NewPointer(model.UserNotifyNone),
|
|
MobilePushStatus: model.NewPointer(model.StatusAway),
|
|
ChannelTrigger: new("false"),
|
|
CommentsTrigger: model.NewPointer(model.CommentsNotifyAny),
|
|
MentionKeys: new("misc"),
|
|
}
|
|
appErr2 = th.App.importUser(th.Context, &data, false)
|
|
assert.Nil(t, appErr2)
|
|
|
|
user, appErr2 = th.App.GetUserByUsername(username)
|
|
require.Nil(t, appErr2, "Failed to get user from database.")
|
|
|
|
checkNotifyProp(t, user, model.DesktopNotifyProp, model.UserNotifyMention)
|
|
checkNotifyProp(t, user, model.DesktopSoundNotifyProp, "false")
|
|
checkNotifyProp(t, user, model.EmailNotifyProp, "false")
|
|
checkNotifyProp(t, user, model.PushNotifyProp, model.UserNotifyNone)
|
|
checkNotifyProp(t, user, model.PushStatusNotifyProp, model.StatusAway)
|
|
checkNotifyProp(t, user, model.ChannelMentionsNotifyProp, "false")
|
|
checkNotifyProp(t, user, model.CommentsNotifyProp, model.CommentsNotifyAny)
|
|
checkNotifyProp(t, user, model.MentionKeysNotifyProp, "misc")
|
|
|
|
// Change Notify Props without mention keys
|
|
data.NotifyProps = &imports.UserNotifyPropsImportData{
|
|
Desktop: model.NewPointer(model.UserNotifyMention),
|
|
DesktopSound: new("false"),
|
|
Email: new("false"),
|
|
Mobile: model.NewPointer(model.UserNotifyNone),
|
|
MobilePushStatus: model.NewPointer(model.StatusAway),
|
|
ChannelTrigger: new("false"),
|
|
CommentsTrigger: model.NewPointer(model.CommentsNotifyAny),
|
|
}
|
|
appErr2 = th.App.importUser(th.Context, &data, false)
|
|
assert.Nil(t, appErr2)
|
|
|
|
user, appErr2 = th.App.GetUserByUsername(username)
|
|
require.Nil(t, appErr2, "Failed to get user from database.")
|
|
|
|
checkNotifyProp(t, user, model.DesktopNotifyProp, model.UserNotifyMention)
|
|
checkNotifyProp(t, user, model.DesktopSoundNotifyProp, "false")
|
|
checkNotifyProp(t, user, model.EmailNotifyProp, "false")
|
|
checkNotifyProp(t, user, model.PushNotifyProp, model.UserNotifyNone)
|
|
checkNotifyProp(t, user, model.PushStatusNotifyProp, model.StatusAway)
|
|
checkNotifyProp(t, user, model.ChannelMentionsNotifyProp, "false")
|
|
checkNotifyProp(t, user, model.CommentsNotifyProp, model.CommentsNotifyAny)
|
|
checkNotifyProp(t, user, model.MentionKeysNotifyProp, "misc")
|
|
|
|
// Check Notify Props get set on *create* user.
|
|
username = model.NewUsername()
|
|
data = imports.UserImportData{
|
|
Username: &username,
|
|
Email: new(model.NewId() + "@example.com"),
|
|
}
|
|
data.NotifyProps = &imports.UserNotifyPropsImportData{
|
|
Desktop: model.NewPointer(model.UserNotifyMention),
|
|
DesktopSound: new("false"),
|
|
Email: new("false"),
|
|
Mobile: model.NewPointer(model.UserNotifyNone),
|
|
MobilePushStatus: model.NewPointer(model.StatusAway),
|
|
ChannelTrigger: new("false"),
|
|
CommentsTrigger: model.NewPointer(model.CommentsNotifyAny),
|
|
MentionKeys: new("misc"),
|
|
}
|
|
|
|
appErr2 = th.App.importUser(th.Context, &data, false)
|
|
assert.Nil(t, appErr2)
|
|
|
|
user, appErr2 = th.App.GetUserByUsername(username)
|
|
require.Nil(t, appErr2, "Failed to get user from database.")
|
|
|
|
checkNotifyProp(t, user, model.DesktopNotifyProp, model.UserNotifyMention)
|
|
checkNotifyProp(t, user, model.DesktopSoundNotifyProp, "false")
|
|
checkNotifyProp(t, user, model.EmailNotifyProp, "false")
|
|
checkNotifyProp(t, user, model.PushNotifyProp, model.UserNotifyNone)
|
|
checkNotifyProp(t, user, model.PushStatusNotifyProp, model.StatusAway)
|
|
checkNotifyProp(t, user, model.ChannelMentionsNotifyProp, "false")
|
|
checkNotifyProp(t, user, model.CommentsNotifyProp, model.CommentsNotifyAny)
|
|
checkNotifyProp(t, user, model.MentionKeysNotifyProp, "misc")
|
|
|
|
// Test importing a user with roles set to a team and a channel which are affected by an override scheme.
|
|
// The import subsystem should translate `channel_admin/channel_user/team_admin/team_user`
|
|
// to the appropriate scheme-managed-role booleans.
|
|
|
|
// Mark the phase 2 permissions migration as completed.
|
|
err := th.App.Srv().Store().System().Save(&model.System{Name: model.MigrationKeyAdvancedPermissionsPhase2, Value: "true"})
|
|
require.NoError(t, err)
|
|
|
|
defer func() {
|
|
_, err = th.App.Srv().Store().System().PermanentDeleteByName(model.MigrationKeyAdvancedPermissionsPhase2)
|
|
require.NoError(t, err)
|
|
}()
|
|
|
|
teamSchemeData := &imports.SchemeImportData{
|
|
Name: new(model.NewId()),
|
|
DisplayName: new(model.NewId()),
|
|
Scope: new("team"),
|
|
DefaultTeamGuestRole: &imports.RoleImportData{
|
|
Name: new(model.NewId()),
|
|
DisplayName: new(model.NewId()),
|
|
},
|
|
DefaultTeamUserRole: &imports.RoleImportData{
|
|
Name: new(model.NewId()),
|
|
DisplayName: new(model.NewId()),
|
|
},
|
|
DefaultTeamAdminRole: &imports.RoleImportData{
|
|
Name: new(model.NewId()),
|
|
DisplayName: new(model.NewId()),
|
|
},
|
|
DefaultChannelGuestRole: &imports.RoleImportData{
|
|
Name: new(model.NewId()),
|
|
DisplayName: new(model.NewId()),
|
|
},
|
|
DefaultChannelUserRole: &imports.RoleImportData{
|
|
Name: new(model.NewId()),
|
|
DisplayName: new(model.NewId()),
|
|
},
|
|
DefaultChannelAdminRole: &imports.RoleImportData{
|
|
Name: new(model.NewId()),
|
|
DisplayName: new(model.NewId()),
|
|
},
|
|
Description: new("description"),
|
|
}
|
|
|
|
appErr2 = th.App.importScheme(th.Context, teamSchemeData, false)
|
|
assert.Nil(t, appErr2)
|
|
|
|
teamScheme, nErr := th.App.Srv().Store().Scheme().GetByName(*teamSchemeData.Name)
|
|
require.NoError(t, nErr, "Failed to import scheme")
|
|
|
|
teamData := &imports.TeamImportData{
|
|
Name: new(NewTestId()),
|
|
DisplayName: new("Display Name"),
|
|
Type: new("O"),
|
|
Description: new("The team description."),
|
|
AllowOpenInvite: new(true),
|
|
Scheme: &teamScheme.Name,
|
|
}
|
|
appErr2 = th.App.importTeam(th.Context, teamData, false)
|
|
assert.Nil(t, appErr2)
|
|
team, appErr2 := th.App.GetTeamByName(teamName)
|
|
require.Nil(t, appErr2, "Failed to get team from database.")
|
|
|
|
channelData := &imports.ChannelImportData{
|
|
Team: &teamName,
|
|
Name: new(NewTestId()),
|
|
DisplayName: new("Display Name"),
|
|
Type: &chanTypeOpen,
|
|
Header: new("Channel Header"),
|
|
Purpose: new("Channel Purpose"),
|
|
}
|
|
appErr2 = th.App.importChannel(th.Context, channelData, false)
|
|
assert.Nil(t, appErr2)
|
|
channel, appErr2 := th.App.GetChannelByName(th.Context, *channelData.Name, team.Id, false)
|
|
require.Nil(t, appErr2, "Failed to get channel from database")
|
|
|
|
// Test with a valid team & valid channel name in apply mode.
|
|
userData := &imports.UserImportData{
|
|
Username: &username,
|
|
Email: new(model.NewId() + "@example.com"),
|
|
Teams: &[]imports.UserTeamImportData{
|
|
{
|
|
Name: &team.Name,
|
|
Roles: new("team_user team_admin"),
|
|
Channels: &[]imports.UserChannelImportData{
|
|
{
|
|
Name: &channel.Name,
|
|
Roles: new("channel_admin channel_user"),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
appErr2 = th.App.importUser(th.Context, userData, false)
|
|
assert.Nil(t, appErr2)
|
|
|
|
user, appErr2 = th.App.GetUserByUsername(*userData.Username)
|
|
require.Nil(t, appErr2, "Failed to get user from database.")
|
|
|
|
teamMember, appErr2 := th.App.GetTeamMember(th.Context, team.Id, user.Id)
|
|
require.Nil(t, appErr2, "Failed to get the team member")
|
|
|
|
assert.True(t, teamMember.SchemeAdmin)
|
|
assert.True(t, teamMember.SchemeUser)
|
|
assert.False(t, teamMember.SchemeGuest)
|
|
assert.Equal(t, "", teamMember.ExplicitRoles)
|
|
|
|
channelMember, appErr2 := th.App.GetChannelMember(th.Context, channel.Id, user.Id)
|
|
require.Nil(t, appErr2, "Failed to get the channel member")
|
|
|
|
assert.True(t, channelMember.SchemeAdmin)
|
|
assert.True(t, channelMember.SchemeUser)
|
|
assert.False(t, channelMember.SchemeGuest)
|
|
assert.Equal(t, "", channelMember.ExplicitRoles)
|
|
|
|
// Test importing deleted user with a valid team & valid channel name in apply mode.
|
|
username = model.NewUsername()
|
|
deleteAt := model.GetMillis()
|
|
deletedUserData := &imports.UserImportData{
|
|
Username: &username,
|
|
DeleteAt: &deleteAt,
|
|
Email: new(model.NewId() + "@example.com"),
|
|
Teams: &[]imports.UserTeamImportData{
|
|
{
|
|
Name: &team.Name,
|
|
Roles: new("team_user"),
|
|
Channels: &[]imports.UserChannelImportData{
|
|
{
|
|
Name: &channel.Name,
|
|
Roles: new("channel_user"),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
appErr2 = th.App.importUser(th.Context, deletedUserData, false)
|
|
assert.Nil(t, appErr2)
|
|
|
|
user, appErr2 = th.App.GetUserByUsername(*deletedUserData.Username)
|
|
require.Nil(t, appErr2, "Failed to get user from database.")
|
|
|
|
teamMember, appErr2 = th.App.GetTeamMember(th.Context, team.Id, user.Id)
|
|
require.Nil(t, appErr2, "Failed to get the team member")
|
|
|
|
assert.False(t, teamMember.SchemeAdmin)
|
|
assert.True(t, teamMember.SchemeUser)
|
|
assert.False(t, teamMember.SchemeGuest)
|
|
assert.Equal(t, "", teamMember.ExplicitRoles)
|
|
|
|
channelMember, appErr2 = th.App.GetChannelMember(th.Context, channel.Id, user.Id)
|
|
require.Nil(t, appErr2, "Failed to get the channel member")
|
|
|
|
assert.False(t, channelMember.SchemeAdmin)
|
|
assert.True(t, channelMember.SchemeUser)
|
|
assert.False(t, channelMember.SchemeGuest)
|
|
assert.Equal(t, "", channelMember.ExplicitRoles)
|
|
})
|
|
|
|
t.Run("import deleted guest with a valid team & valid channel name in apply mode", func(t *testing.T) {
|
|
teamData := &imports.TeamImportData{
|
|
Name: new(model.NewRandomTeamName()),
|
|
DisplayName: new("Display Name"),
|
|
Type: new("O"),
|
|
Description: new("The team description."),
|
|
AllowOpenInvite: new(true),
|
|
}
|
|
appErr := th.App.importTeam(th.Context, teamData, false)
|
|
assert.Nil(t, appErr)
|
|
|
|
team, appErr2 := th.App.GetTeamByName(*teamData.Name)
|
|
require.Nil(t, appErr2, "Failed to get team from database.")
|
|
|
|
channelData := &imports.ChannelImportData{
|
|
Team: teamData.Name,
|
|
Name: new(NewTestId()),
|
|
DisplayName: new("Display Name"),
|
|
Type: model.NewPointer(model.ChannelTypeOpen),
|
|
Header: new("Channel Header"),
|
|
Purpose: new("Channel Purpose"),
|
|
}
|
|
appErr2 = th.App.importChannel(th.Context, channelData, false)
|
|
assert.Nil(t, appErr2)
|
|
channel, appErr2 := th.App.GetChannelByName(th.Context, *channelData.Name, team.Id, false)
|
|
require.Nil(t, appErr2, "Failed to get channel from database")
|
|
|
|
username := model.NewUsername()
|
|
deleteAt := model.GetMillis()
|
|
deletedGuestData := &imports.UserImportData{
|
|
Username: &username,
|
|
DeleteAt: &deleteAt,
|
|
Email: new(model.NewId() + "@example.com"),
|
|
Roles: new("system_guest"),
|
|
Teams: &[]imports.UserTeamImportData{
|
|
{
|
|
Name: &team.Name,
|
|
Roles: new("team_guest"),
|
|
Channels: &[]imports.UserChannelImportData{
|
|
{
|
|
Name: &channel.Name,
|
|
Roles: new("channel_guest"),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
appErr = th.App.importUser(th.Context, deletedGuestData, false)
|
|
assert.Nil(t, appErr)
|
|
|
|
user, appErr := th.App.GetUserByUsername(*deletedGuestData.Username)
|
|
require.Nil(t, appErr, "Failed to get user from database.")
|
|
|
|
teamMember, appErr := th.App.GetTeamMember(th.Context, team.Id, user.Id)
|
|
require.Nil(t, appErr, "Failed to get the team member")
|
|
|
|
assert.False(t, teamMember.SchemeAdmin)
|
|
assert.False(t, teamMember.SchemeUser)
|
|
assert.True(t, teamMember.SchemeGuest)
|
|
assert.Equal(t, "", teamMember.ExplicitRoles)
|
|
|
|
channelMember, appErr := th.App.GetChannelMember(th.Context, channel.Id, user.Id)
|
|
require.Nil(t, appErr, "Failed to get the channel member")
|
|
|
|
assert.False(t, teamMember.SchemeAdmin)
|
|
assert.False(t, channelMember.SchemeUser)
|
|
assert.True(t, teamMember.SchemeGuest)
|
|
assert.Equal(t, "", channelMember.ExplicitRoles)
|
|
})
|
|
|
|
t.Run("import guest user without any team or channel memberships", func(t *testing.T) {
|
|
username := model.NewUsername()
|
|
guestData := &imports.UserImportData{
|
|
Username: &username,
|
|
Email: new(model.NewId() + "@example.com"),
|
|
Roles: new("system_guest"),
|
|
}
|
|
|
|
appErr := th.App.importUser(th.Context, guestData, false)
|
|
require.Nil(t, appErr, "Failed to import guest user without memberships")
|
|
|
|
user, appErr := th.App.GetUserByUsername(*guestData.Username)
|
|
require.Nil(t, appErr, "Failed to get user from database.")
|
|
|
|
assert.True(t, user.IsGuest(), "User should be a guest")
|
|
assert.Equal(t, "system_guest", user.Roles)
|
|
|
|
teams, appErr := th.App.GetTeamsForUser(user.Id)
|
|
require.Nil(t, appErr)
|
|
assert.Empty(t, teams, "Guest user should have no team memberships")
|
|
})
|
|
}
|
|
|
|
func TestImportUserTeams(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
team2 := th.CreateTeam(t)
|
|
channel2 := th.CreateChannel(t, th.BasicTeam)
|
|
channel3 := th.CreateChannel(t, team2)
|
|
customRole := th.CreateRole(t, "test_custom_role")
|
|
sampleTheme := "{\"test\":\"#abcdef\"}"
|
|
|
|
tt := []struct {
|
|
name string
|
|
data *[]imports.UserTeamImportData
|
|
expectedError bool
|
|
expectedUserTeams int
|
|
expectedUserChannels int
|
|
expectedExplicitRoles string
|
|
expectedRoles string
|
|
expectedTheme string
|
|
}{
|
|
{
|
|
name: "Not existing team should fail",
|
|
data: &[]imports.UserTeamImportData{
|
|
{
|
|
Name: new("not-existing-team-name"),
|
|
},
|
|
},
|
|
expectedError: true,
|
|
},
|
|
{
|
|
name: "nil data shouldn't do anything",
|
|
expectedError: false,
|
|
expectedUserTeams: 0,
|
|
expectedUserChannels: 0,
|
|
},
|
|
{
|
|
name: "Should fail if one of the roles doesn't exist",
|
|
data: &[]imports.UserTeamImportData{
|
|
{
|
|
Name: &th.BasicTeam.Name,
|
|
Roles: new("not-existing-role"),
|
|
},
|
|
},
|
|
expectedError: true,
|
|
expectedUserTeams: 1,
|
|
expectedUserChannels: 0,
|
|
expectedExplicitRoles: "",
|
|
expectedRoles: "team_user",
|
|
},
|
|
{
|
|
name: "Should success to import explicit role",
|
|
data: &[]imports.UserTeamImportData{
|
|
{
|
|
Name: &th.BasicTeam.Name,
|
|
Roles: &customRole.Name,
|
|
},
|
|
},
|
|
expectedError: false,
|
|
expectedUserTeams: 1,
|
|
expectedUserChannels: 1,
|
|
expectedExplicitRoles: customRole.Name,
|
|
expectedRoles: customRole.Name + " team_user",
|
|
},
|
|
{
|
|
name: "Should success to import admin role",
|
|
data: &[]imports.UserTeamImportData{
|
|
{
|
|
Name: &th.BasicTeam.Name,
|
|
Roles: model.NewPointer(model.TeamAdminRoleId),
|
|
},
|
|
},
|
|
expectedError: false,
|
|
expectedUserTeams: 1,
|
|
expectedUserChannels: 1,
|
|
expectedExplicitRoles: "",
|
|
expectedRoles: "team_user team_admin",
|
|
},
|
|
{
|
|
name: "Should success to import with theme",
|
|
data: &[]imports.UserTeamImportData{
|
|
{
|
|
Name: &th.BasicTeam.Name,
|
|
Theme: &sampleTheme,
|
|
},
|
|
},
|
|
expectedError: false,
|
|
expectedUserTeams: 1,
|
|
expectedUserChannels: 1,
|
|
expectedExplicitRoles: "",
|
|
expectedRoles: "team_user",
|
|
expectedTheme: sampleTheme,
|
|
},
|
|
{
|
|
name: "Team without channels must add the default channel",
|
|
data: &[]imports.UserTeamImportData{
|
|
{
|
|
Name: &th.BasicTeam.Name,
|
|
},
|
|
},
|
|
expectedError: false,
|
|
expectedUserTeams: 1,
|
|
expectedUserChannels: 1,
|
|
expectedExplicitRoles: "",
|
|
expectedRoles: "team_user",
|
|
},
|
|
{
|
|
name: "Team with default channel must add only the default channel",
|
|
data: &[]imports.UserTeamImportData{
|
|
{
|
|
Name: &th.BasicTeam.Name,
|
|
Channels: &[]imports.UserChannelImportData{
|
|
{
|
|
Name: model.NewPointer(model.DefaultChannelName),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expectedError: false,
|
|
expectedUserTeams: 1,
|
|
expectedUserChannels: 1,
|
|
expectedExplicitRoles: "",
|
|
expectedRoles: "team_user",
|
|
},
|
|
{
|
|
name: "Team with non default channel must add default channel and the other channel",
|
|
data: &[]imports.UserTeamImportData{
|
|
{
|
|
Name: &th.BasicTeam.Name,
|
|
Channels: &[]imports.UserChannelImportData{
|
|
{
|
|
Name: &th.BasicChannel.Name,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expectedError: false,
|
|
expectedUserTeams: 1,
|
|
expectedUserChannels: 2,
|
|
expectedExplicitRoles: "",
|
|
expectedRoles: "team_user",
|
|
},
|
|
{
|
|
name: "Multiple teams with multiple channels each",
|
|
data: &[]imports.UserTeamImportData{
|
|
{
|
|
Name: &th.BasicTeam.Name,
|
|
Channels: &[]imports.UserChannelImportData{
|
|
{
|
|
Name: &th.BasicChannel.Name,
|
|
},
|
|
{
|
|
Name: &channel2.Name,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: &team2.Name,
|
|
Channels: &[]imports.UserChannelImportData{
|
|
{
|
|
Name: &channel3.Name,
|
|
},
|
|
{
|
|
Name: new("town-square"),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expectedError: false,
|
|
expectedUserTeams: 2,
|
|
expectedUserChannels: 5,
|
|
},
|
|
}
|
|
|
|
for _, tc := range tt {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
user := th.CreateUser(t)
|
|
|
|
// Two times import must end with the same results
|
|
for range 2 {
|
|
appErr := th.App.importUserTeams(th.Context, user, tc.data)
|
|
if tc.expectedError {
|
|
require.NotNil(t, appErr)
|
|
} else {
|
|
require.Nil(t, appErr)
|
|
}
|
|
teamMembers, nErr := th.App.Srv().Store().Team().GetTeamsForUser(th.Context, user.Id, "", true)
|
|
require.NoError(t, nErr)
|
|
require.Len(t, teamMembers, tc.expectedUserTeams)
|
|
if tc.expectedUserTeams == 1 {
|
|
require.Equal(t, tc.expectedExplicitRoles, teamMembers[0].ExplicitRoles, "Not matching expected explicit roles")
|
|
require.Equal(t, tc.expectedRoles, teamMembers[0].Roles, "not matching expected roles")
|
|
if tc.expectedTheme != "" {
|
|
pref, prefErr := th.App.Srv().Store().Preference().Get(user.Id, model.PreferenceCategoryTheme, teamMembers[0].TeamId)
|
|
require.NoError(t, prefErr)
|
|
require.Equal(t, tc.expectedTheme, pref.Value)
|
|
}
|
|
}
|
|
|
|
totalMembers := 0
|
|
for _, teamMember := range teamMembers {
|
|
channelMembers, err := th.App.Srv().Store().Channel().GetMembersForUser(teamMember.TeamId, user.Id)
|
|
require.NoError(t, err)
|
|
totalMembers += len(channelMembers)
|
|
}
|
|
require.Equal(t, tc.expectedUserChannels, totalMembers)
|
|
}
|
|
})
|
|
}
|
|
|
|
t.Run("Should fail if the MaxUserPerTeam is reached", func(t *testing.T) {
|
|
user := th.CreateUser(t)
|
|
data := &[]imports.UserTeamImportData{
|
|
{
|
|
Name: &th.BasicTeam.Name,
|
|
},
|
|
}
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.MaxUsersPerTeam = 1 })
|
|
defer th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.MaxUsersPerTeam = 100 })
|
|
appErr := th.App.importUserTeams(th.Context, user, data)
|
|
require.NotNil(t, appErr)
|
|
})
|
|
}
|
|
|
|
func TestImportUserChannels(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
channel2 := th.CreateChannel(t, th.BasicTeam)
|
|
customRole := th.CreateRole(t, "test_custom_role")
|
|
sampleNotifyProps := imports.UserChannelNotifyPropsImportData{
|
|
Desktop: new("all"),
|
|
Mobile: new("none"),
|
|
MarkUnread: new("all"),
|
|
}
|
|
|
|
tt := []struct {
|
|
name string
|
|
data *[]imports.UserChannelImportData
|
|
expectedError bool
|
|
expectedUserChannels int
|
|
expectedExplicitRoles string
|
|
expectedRoles string
|
|
expectedNotifyProps *imports.UserChannelNotifyPropsImportData
|
|
}{
|
|
{
|
|
name: "Not existing channel should fail",
|
|
data: &[]imports.UserChannelImportData{
|
|
{
|
|
Name: new("not-existing-channel-name"),
|
|
},
|
|
},
|
|
expectedError: true,
|
|
},
|
|
{
|
|
name: "nil data shouldn't do anything",
|
|
expectedError: false,
|
|
expectedUserChannels: 0,
|
|
},
|
|
{
|
|
name: "Should fail if one of the roles doesn't exist",
|
|
data: &[]imports.UserChannelImportData{
|
|
{
|
|
Name: &th.BasicChannel.Name,
|
|
Roles: new("not-existing-role"),
|
|
},
|
|
},
|
|
expectedError: true,
|
|
expectedUserChannels: 1,
|
|
expectedExplicitRoles: "",
|
|
expectedRoles: "channel_user",
|
|
},
|
|
{
|
|
name: "Should success to import explicit role",
|
|
data: &[]imports.UserChannelImportData{
|
|
{
|
|
Name: &th.BasicChannel.Name,
|
|
Roles: &customRole.Name,
|
|
},
|
|
},
|
|
expectedError: false,
|
|
expectedUserChannels: 1,
|
|
expectedExplicitRoles: customRole.Name,
|
|
expectedRoles: customRole.Name + " channel_user",
|
|
},
|
|
{
|
|
name: "Should success to import admin role",
|
|
data: &[]imports.UserChannelImportData{
|
|
{
|
|
Name: &th.BasicChannel.Name,
|
|
Roles: model.NewPointer(model.ChannelAdminRoleId),
|
|
},
|
|
},
|
|
expectedError: false,
|
|
expectedUserChannels: 1,
|
|
expectedExplicitRoles: "",
|
|
expectedRoles: "channel_user channel_admin",
|
|
},
|
|
{
|
|
name: "Should success to import with notifyProps",
|
|
data: &[]imports.UserChannelImportData{
|
|
{
|
|
Name: &th.BasicChannel.Name,
|
|
NotifyProps: &sampleNotifyProps,
|
|
},
|
|
},
|
|
expectedError: false,
|
|
expectedUserChannels: 1,
|
|
expectedExplicitRoles: "",
|
|
expectedRoles: "channel_user",
|
|
expectedNotifyProps: &sampleNotifyProps,
|
|
},
|
|
{
|
|
name: "Should import properly multiple channels",
|
|
data: &[]imports.UserChannelImportData{
|
|
{
|
|
Name: &th.BasicChannel.Name,
|
|
},
|
|
{
|
|
Name: &channel2.Name,
|
|
},
|
|
},
|
|
expectedError: false,
|
|
expectedUserChannels: 2,
|
|
},
|
|
}
|
|
|
|
for _, tc := range tt {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
user := th.CreateUser(t)
|
|
_, _, err := th.App.ch.srv.teamService.JoinUserToTeam(th.Context, th.BasicTeam, user)
|
|
require.NoError(t, err)
|
|
|
|
// Two times import must end with the same results
|
|
for range 2 {
|
|
appErr := th.App.importUserChannels(th.Context, user, th.BasicTeam, tc.data)
|
|
if tc.expectedError {
|
|
require.NotNil(t, appErr)
|
|
} else {
|
|
require.Nil(t, appErr)
|
|
}
|
|
channelMembers, err := th.App.Srv().Store().Channel().GetMembersForUser(th.BasicTeam.Id, user.Id)
|
|
require.NoError(t, err)
|
|
require.Len(t, channelMembers, tc.expectedUserChannels)
|
|
if tc.expectedUserChannels == 1 {
|
|
channelMember := channelMembers[0]
|
|
require.Equal(t, tc.expectedExplicitRoles, channelMember.ExplicitRoles, "Not matching expected explicit roles")
|
|
require.Equal(t, tc.expectedRoles, channelMember.Roles, "not matching expected roles")
|
|
if tc.expectedNotifyProps != nil {
|
|
require.Equal(t, *tc.expectedNotifyProps.Desktop, channelMember.NotifyProps[model.DesktopNotifyProp])
|
|
require.Equal(t, *tc.expectedNotifyProps.Mobile, channelMember.NotifyProps[model.PushNotifyProp])
|
|
require.Equal(t, *tc.expectedNotifyProps.MarkUnread, channelMember.NotifyProps[model.MarkUnreadNotifyProp])
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestImportUserDefaultNotifyProps(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
// Create a valid new user with some, but not all, notify props populated.
|
|
username := model.NewUsername()
|
|
data := imports.UserImportData{
|
|
Username: &username,
|
|
Email: new(model.NewId() + "@example.com"),
|
|
NotifyProps: &imports.UserNotifyPropsImportData{
|
|
Email: new("false"),
|
|
MentionKeys: new(""),
|
|
},
|
|
}
|
|
require.Nil(t, th.App.importUser(th.Context, &data, false))
|
|
|
|
user, err := th.App.GetUserByUsername(username)
|
|
require.Nil(t, err)
|
|
|
|
// Check the value of the notify prop we specified explicitly in the import data.
|
|
val, ok := user.NotifyProps[model.EmailNotifyProp]
|
|
assert.True(t, ok)
|
|
assert.Equal(t, "false", val)
|
|
|
|
// Check all the other notify props are set to their default values.
|
|
comparisonUser := model.User{Username: user.Username}
|
|
comparisonUser.SetDefaultNotifications()
|
|
|
|
for key, expectedValue := range comparisonUser.NotifyProps {
|
|
if key == model.EmailNotifyProp {
|
|
continue
|
|
}
|
|
|
|
val, ok := user.NotifyProps[key]
|
|
assert.True(t, ok)
|
|
assert.Equal(t, expectedValue, val)
|
|
}
|
|
}
|
|
|
|
func TestImportimportMultiplePostLines(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
// Create a Team.
|
|
teamName := model.NewRandomTeamName()
|
|
appErr := th.App.importTeam(th.Context, &imports.TeamImportData{
|
|
Name: &teamName,
|
|
DisplayName: new("Display Name"),
|
|
Type: new("O"),
|
|
}, false)
|
|
require.Nil(t, appErr, "Failed to import team.")
|
|
team, err := th.App.GetTeamByName(teamName)
|
|
require.Nil(t, err, "Failed to get team from database.")
|
|
|
|
// Create a Channel.
|
|
channelName := NewTestId()
|
|
chanTypeOpen := model.ChannelTypeOpen
|
|
appErr = th.App.importChannel(th.Context, &imports.ChannelImportData{
|
|
Team: &teamName,
|
|
Name: &channelName,
|
|
DisplayName: new("Display Name"),
|
|
Type: &chanTypeOpen,
|
|
}, false)
|
|
require.Nil(t, appErr, "Failed to import channel.")
|
|
channel, err := th.App.GetChannelByName(th.Context, channelName, team.Id, false)
|
|
require.Nil(t, err, "Failed to get channel from database.")
|
|
|
|
// Create a user.
|
|
username := model.NewUsername()
|
|
appErr = th.App.importUser(th.Context, &imports.UserImportData{
|
|
Username: &username,
|
|
Email: new(model.NewId() + "@example.com"),
|
|
}, false)
|
|
require.Nil(t, appErr, "Failed to import user.")
|
|
user, err := th.App.GetUserByUsername(username)
|
|
require.Nil(t, err, "Failed to get user from database.")
|
|
|
|
username2 := model.NewUsername()
|
|
appErr = th.App.importUser(th.Context, &imports.UserImportData{
|
|
Username: &username2,
|
|
Email: new(model.NewId() + "@example.com"),
|
|
}, false)
|
|
require.Nil(t, appErr, "Failed to import user.")
|
|
user2, err := th.App.GetUserByUsername(username2)
|
|
require.Nil(t, err, "Failed to get user from database.")
|
|
|
|
// Count the number of posts in the testing team.
|
|
require.NoError(t, th.App.Srv().Store().Post().RefreshPostStats())
|
|
initialPostCount, nErr := th.App.Srv().Store().Post().AnalyticsPostCount(&model.PostCountOptions{TeamId: team.Id})
|
|
require.NoError(t, nErr)
|
|
|
|
createAt := model.GetMillis()
|
|
hashtagTime := createAt + 2
|
|
replyPostTime := hashtagTime + 4
|
|
replyTime := hashtagTime + 5
|
|
|
|
var assertionCount int64
|
|
|
|
t.Run("invalid post in dry run mode", func(t *testing.T) {
|
|
// Try adding an invalid post in dry run mode.
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &username,
|
|
},
|
|
},
|
|
LineNumber: 25,
|
|
}
|
|
errLine, err2 := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, true, true)
|
|
assert.NotNil(t, err2)
|
|
assert.Equal(t, data.LineNumber, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 0, team.Id)
|
|
})
|
|
|
|
t.Run("valid post in dry run mode", func(t *testing.T) {
|
|
// Try adding a valid post in dry run mode.
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &username,
|
|
Message: new("Hello"),
|
|
CreateAt: new(model.GetMillis()),
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err2 := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, true, true)
|
|
assert.Nil(t, err2)
|
|
assert.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 0, team.Id)
|
|
})
|
|
|
|
t.Run("invalid post in apply mode", func(t *testing.T) {
|
|
// Try adding an invalid post in apply mode.
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &username,
|
|
CreateAt: new(model.GetMillis()),
|
|
},
|
|
},
|
|
LineNumber: 35,
|
|
}
|
|
errLine, err2 := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
assert.NotNil(t, err2)
|
|
assert.Equal(t, data.LineNumber, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 0, team.Id)
|
|
})
|
|
|
|
t.Run("valid post with invalid team in apply mode", func(t *testing.T) {
|
|
// Try adding a valid post with invalid team in apply mode.
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: new(NewTestId()),
|
|
Channel: &channelName,
|
|
User: &username,
|
|
Message: new("Message"),
|
|
CreateAt: new(model.GetMillis()),
|
|
},
|
|
},
|
|
LineNumber: 10,
|
|
}
|
|
errLine, err2 := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
assert.NotNil(t, err2)
|
|
// Batch will fail when searching for teams, so no specific line
|
|
// is associated with the error
|
|
assert.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 0, team.Id)
|
|
})
|
|
|
|
t.Run("valid post with invalid channel in apply mode", func(t *testing.T) {
|
|
// Try adding a valid post with invalid channel in apply mode.
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: new(NewTestId()),
|
|
User: &username,
|
|
Message: new("Message"),
|
|
CreateAt: new(model.GetMillis()),
|
|
},
|
|
},
|
|
LineNumber: 7,
|
|
}
|
|
errLine, err2 := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
assert.NotNil(t, err2)
|
|
// Batch will fail when searching for channels, so no specific
|
|
// line is associated with the error
|
|
assert.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 0, team.Id)
|
|
})
|
|
|
|
t.Run("valid post with invalid user in apply mode", func(t *testing.T) {
|
|
// Try adding a valid post with invalid user in apply mode.
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: new(model.NewId()),
|
|
Message: new("Message"),
|
|
CreateAt: new(model.GetMillis()),
|
|
},
|
|
},
|
|
LineNumber: 2,
|
|
}
|
|
errLine, err2 := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
assert.NotNil(t, err2)
|
|
// Batch will fail when searching for users, so no specific line
|
|
// is associated with the error
|
|
assert.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 0, team.Id)
|
|
})
|
|
|
|
t.Run("valid post in apply mode", func(t *testing.T) {
|
|
// Try adding a valid post in apply mode.
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &username,
|
|
Message: new("Message"),
|
|
CreateAt: &createAt,
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err2 := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
assert.Nil(t, err2)
|
|
assert.Equal(t, 0, errLine)
|
|
assertionCount++
|
|
AssertAllPostsCount(t, th.App, initialPostCount, assertionCount, team.Id)
|
|
|
|
// Check the post values.
|
|
posts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, createAt)
|
|
require.NoError(t, nErr)
|
|
|
|
require.Len(t, posts, 1, "Unexpected number of posts found.")
|
|
|
|
post := posts[0]
|
|
postBool := post.Message != *data.Post.Message || post.CreateAt != *data.Post.CreateAt || post.UserId != user.Id
|
|
require.False(t, postBool, "Post properties not as expected")
|
|
|
|
// Update the post.
|
|
data = imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &username,
|
|
Message: new("Message"),
|
|
CreateAt: &createAt,
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err = th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, assertionCount, team.Id)
|
|
|
|
// Check the post values.
|
|
posts, nErr = th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, createAt)
|
|
require.NoError(t, nErr)
|
|
|
|
require.Len(t, posts, 1, "Unexpected number of posts found.")
|
|
|
|
post = posts[0]
|
|
postBool = post.Message != *data.Post.Message || post.CreateAt != *data.Post.CreateAt || post.UserId != user.Id
|
|
require.False(t, postBool, "Post properties not as expected")
|
|
})
|
|
|
|
t.Run("import the post with a different time", func(t *testing.T) {
|
|
// Save the post with a different time.
|
|
newTime := createAt + 1
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &username,
|
|
Message: new("Message"),
|
|
CreateAt: &newTime,
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err2 := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
assert.Nil(t, err2)
|
|
assert.Equal(t, 0, errLine)
|
|
assertionCount++
|
|
AssertAllPostsCount(t, th.App, initialPostCount, assertionCount, team.Id)
|
|
})
|
|
|
|
t.Run("import the post with a different message", func(t *testing.T) {
|
|
// Save the post with a different message.
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &username,
|
|
Message: new("Message 2"),
|
|
CreateAt: &createAt,
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err2 := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
assert.Nil(t, err2)
|
|
assert.Equal(t, 0, errLine)
|
|
assertionCount++
|
|
AssertAllPostsCount(t, th.App, initialPostCount, assertionCount, team.Id)
|
|
})
|
|
|
|
t.Run("import post with hashtags", func(t *testing.T) {
|
|
// Test with hashtags
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &username,
|
|
Message: new("Message 2 #hashtagmashupcity"),
|
|
CreateAt: &hashtagTime,
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err2 := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
assert.Nil(t, err2)
|
|
assert.Equal(t, 0, errLine)
|
|
assertionCount++
|
|
AssertAllPostsCount(t, th.App, initialPostCount, assertionCount, team.Id)
|
|
|
|
posts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, hashtagTime)
|
|
require.NoError(t, nErr)
|
|
|
|
require.Len(t, posts, 1, "Unexpected number of posts found.")
|
|
|
|
post := posts[0]
|
|
postBool := post.Message != *data.Post.Message || post.CreateAt != *data.Post.CreateAt || post.UserId != user.Id
|
|
require.False(t, postBool, "Post properties not as expected")
|
|
|
|
require.Equal(t, "#hashtagmashupcity", post.Hashtags, "Hashtags not as expected: %s", post.Hashtags)
|
|
})
|
|
|
|
t.Run("import post with flags", func(t *testing.T) {
|
|
// Post with flags.
|
|
flagsTime := hashtagTime + 1
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &username,
|
|
Message: new("Message with Favorites"),
|
|
CreateAt: &flagsTime,
|
|
FlaggedBy: &[]string{
|
|
username,
|
|
username2,
|
|
},
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
|
|
errLine, err2 := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
assert.Nil(t, err2, "Expected success.")
|
|
assert.Equal(t, 0, errLine)
|
|
assertionCount++
|
|
AssertAllPostsCount(t, th.App, initialPostCount, assertionCount, team.Id)
|
|
|
|
// Check the post values.
|
|
posts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, flagsTime)
|
|
require.NoError(t, nErr)
|
|
|
|
require.Len(t, posts, 1, "Unexpected number of posts found.")
|
|
|
|
post := posts[0]
|
|
postBool := post.Message != *data.Post.Message || post.CreateAt != *data.Post.CreateAt || post.UserId != user.Id
|
|
require.False(t, postBool, "Post properties not as expected")
|
|
|
|
checkPreference(t, th.App, user.Id, model.PreferenceCategoryFlaggedPost, post.Id, "true")
|
|
checkPreference(t, th.App, user2.Id, model.PreferenceCategoryFlaggedPost, post.Id, "true")
|
|
})
|
|
|
|
t.Run("import new post with reactions", func(t *testing.T) {
|
|
// Post with reaction.
|
|
reactionPostTime := hashtagTime + 2
|
|
reactionTime := hashtagTime + 3
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &username,
|
|
Message: new("Message with reactions"),
|
|
CreateAt: &reactionPostTime,
|
|
Reactions: &[]imports.ReactionImportData{{
|
|
User: &user2.Username,
|
|
EmojiName: new("+1"),
|
|
CreateAt: &reactionTime,
|
|
}, {
|
|
User: &user.Username,
|
|
EmojiName: new("+1"),
|
|
CreateAt: &reactionTime,
|
|
}},
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err2 := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
assert.Nil(t, err2, "Expected success.")
|
|
assert.Equal(t, 0, errLine)
|
|
assertionCount++
|
|
AssertAllPostsCount(t, th.App, initialPostCount, assertionCount, team.Id)
|
|
|
|
// Check the post values.
|
|
posts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, reactionPostTime)
|
|
require.NoError(t, nErr)
|
|
|
|
require.Len(t, posts, 1, "Unexpected number of posts found.")
|
|
|
|
post := posts[0]
|
|
postBool := post.Message != *data.Post.Message || post.CreateAt != *data.Post.CreateAt || post.UserId != user.Id || !post.HasReactions
|
|
require.False(t, postBool, "Post properties not as expected")
|
|
|
|
reactions, nErr := th.App.Srv().Store().Reaction().GetForPost(post.Id, false)
|
|
require.NoError(t, nErr, "Can't get reaction")
|
|
|
|
require.Len(t, reactions, 2, "Invalid number of reactions")
|
|
|
|
// Update post with replies with reactions.
|
|
newReactionTime := reactionTime + 1
|
|
newReplyTime := reactionPostTime + 1
|
|
data = imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &username,
|
|
Message: new("Message with reactions"),
|
|
CreateAt: &reactionPostTime,
|
|
Replies: &[]imports.ReplyImportData{{
|
|
User: &username,
|
|
Message: new("Message reply"),
|
|
CreateAt: &newReplyTime,
|
|
Reactions: &[]imports.ReactionImportData{{
|
|
User: &user2.Username,
|
|
EmojiName: new("+1"),
|
|
CreateAt: &newReactionTime,
|
|
}},
|
|
}},
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err = th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
assert.Nil(t, err, "Expected success.")
|
|
assert.Equal(t, 0, errLine)
|
|
// No new post created, only the reply is added.
|
|
assertionCount++
|
|
AssertAllPostsCount(t, th.App, initialPostCount, assertionCount, team.Id)
|
|
|
|
// Check the post values.
|
|
posts, nErr = th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, newReplyTime)
|
|
require.NoError(t, nErr)
|
|
|
|
require.Len(t, posts, 1, "Unexpected number of posts found.")
|
|
|
|
post = posts[0]
|
|
|
|
reactions, nErr = th.App.Srv().Store().Reaction().GetForPost(post.Id, false)
|
|
require.NoError(t, nErr, "Can't get reaction")
|
|
|
|
require.Len(t, reactions, 1, "Invalid number of reactions")
|
|
})
|
|
|
|
t.Run("import post with reactions with new replies", func(t *testing.T) {
|
|
// Post with reaction.
|
|
reactionPostTime := hashtagTime + 11
|
|
reactionTime := hashtagTime + 12
|
|
newReplyTime := reactionPostTime + 1
|
|
newReactionTime := reactionTime + 1
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &username,
|
|
Message: new("Message with reaction"),
|
|
CreateAt: &reactionPostTime,
|
|
Reactions: &[]imports.ReactionImportData{{
|
|
User: &user2.Username,
|
|
EmojiName: new("+1"),
|
|
CreateAt: &reactionTime,
|
|
}},
|
|
Replies: &[]imports.ReplyImportData{{
|
|
User: &username,
|
|
Message: new("Message reply"),
|
|
CreateAt: &newReplyTime,
|
|
Reactions: &[]imports.ReactionImportData{{
|
|
User: &user2.Username,
|
|
EmojiName: new("+1"),
|
|
CreateAt: &newReactionTime,
|
|
}},
|
|
}},
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err2 := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
assert.Nil(t, err2, "Expected success.")
|
|
assert.Equal(t, 0, errLine)
|
|
assertionCount += 2
|
|
AssertAllPostsCount(t, th.App, initialPostCount, assertionCount, team.Id)
|
|
|
|
// Check the post values.
|
|
posts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, reactionPostTime)
|
|
require.NoError(t, nErr)
|
|
|
|
require.Len(t, posts, 1, "Unexpected number of posts found.")
|
|
|
|
post := posts[0]
|
|
postBool := post.Message != *data.Post.Message || post.CreateAt != *data.Post.CreateAt || post.UserId != user.Id || !post.HasReactions
|
|
require.False(t, postBool, "Post properties not as expected")
|
|
|
|
reactions, nErr := th.App.Srv().Store().Reaction().GetForPost(post.Id, false)
|
|
require.NoError(t, nErr, "Can't get reaction")
|
|
|
|
require.Len(t, reactions, 1, "Invalid number of reactions")
|
|
|
|
// Check the post values.
|
|
posts, nErr = th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, newReplyTime)
|
|
require.NoError(t, nErr)
|
|
|
|
require.Len(t, posts, 1, "Unexpected number of posts found.")
|
|
|
|
post = posts[0]
|
|
|
|
reactions, nErr = th.App.Srv().Store().Reaction().GetForPost(post.Id, false)
|
|
require.NoError(t, nErr, "Can't get reaction")
|
|
|
|
require.Len(t, reactions, 1, "Invalid number of reactions")
|
|
})
|
|
|
|
t.Run("import post with replies", func(t *testing.T) {
|
|
// Post with reply.
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &username,
|
|
Message: new("Message with reply"),
|
|
CreateAt: &replyPostTime,
|
|
Replies: &[]imports.ReplyImportData{{
|
|
User: &user2.Username,
|
|
Message: new("Message reply"),
|
|
CreateAt: &replyTime,
|
|
Props: &model.StringInterface{"key": "value"},
|
|
}},
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err2 := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
assert.Nil(t, err2, "Expected success.")
|
|
assert.Equal(t, 0, errLine)
|
|
assertionCount += 2
|
|
AssertAllPostsCount(t, th.App, initialPostCount, assertionCount, team.Id)
|
|
|
|
// Check the post values.
|
|
posts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, replyPostTime)
|
|
require.NoError(t, nErr)
|
|
|
|
require.Len(t, posts, 1, "Unexpected number of posts found.")
|
|
|
|
post := posts[0]
|
|
postBool := post.Message != *data.Post.Message || post.CreateAt != *data.Post.CreateAt || post.UserId != user.Id
|
|
require.False(t, postBool, "Post properties not as expected")
|
|
|
|
// Check the reply values.
|
|
replies, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, replyTime)
|
|
require.NoError(t, nErr)
|
|
|
|
require.Len(t, replies, 1, "Unexpected number of posts found.")
|
|
|
|
reply := replies[0]
|
|
replyBool := reply.Message != *(*data.Post.Replies)[0].Message || reply.CreateAt != *(*data.Post.Replies)[0].CreateAt || reply.UserId != user2.Id
|
|
require.False(t, replyBool, "Post properties not as expected")
|
|
|
|
v := reply.GetProp("key")
|
|
require.NotNil(t, v, "Post prop should exist")
|
|
require.Equal(t, "value", v, "Post props not as expected")
|
|
|
|
require.Equal(t, post.Id, reply.RootId, "Unexpected reply RootId")
|
|
})
|
|
|
|
t.Run("update post with replies", func(t *testing.T) {
|
|
replyPostTime2 := replyPostTime + 1
|
|
// Create post without replies.
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &user2.Username,
|
|
Message: new("Message with reply"),
|
|
CreateAt: &replyPostTime2,
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err2 := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
assert.Nil(t, err2, "Expected success.")
|
|
assert.Equal(t, 0, errLine)
|
|
assertionCount++
|
|
AssertAllPostsCount(t, th.App, initialPostCount, assertionCount, team.Id)
|
|
|
|
// Update post with replies.
|
|
data = imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &user2.Username,
|
|
Message: new("Message with reply"),
|
|
CreateAt: &replyPostTime2,
|
|
Replies: &[]imports.ReplyImportData{{
|
|
User: &username,
|
|
Message: new("Message reply"),
|
|
CreateAt: &replyTime,
|
|
}},
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err = th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
assert.Nil(t, err, "Expected success.")
|
|
assert.Equal(t, 0, errLine)
|
|
// No new post created, only the reply is added.
|
|
assertionCount++
|
|
AssertAllPostsCount(t, th.App, initialPostCount, assertionCount, team.Id)
|
|
|
|
// Create new post with replies based on the previous one.
|
|
data = imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &user2.Username,
|
|
Message: new("Message with reply 2"),
|
|
CreateAt: &replyPostTime2,
|
|
Replies: &[]imports.ReplyImportData{{
|
|
User: &username,
|
|
Message: new("Message reply"),
|
|
CreateAt: &replyTime,
|
|
}},
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err = th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
assert.Nil(t, err, "Expected success.")
|
|
assert.Equal(t, 0, errLine)
|
|
assertionCount += 2
|
|
AssertAllPostsCount(t, th.App, initialPostCount, assertionCount, team.Id)
|
|
|
|
// Create new reply for existing post with replies.
|
|
data = imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &user2.Username,
|
|
Message: new("Message with reply"),
|
|
CreateAt: &replyPostTime2,
|
|
Replies: &[]imports.ReplyImportData{{
|
|
User: &username,
|
|
Message: new("Message reply 2"),
|
|
CreateAt: &replyTime,
|
|
}},
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err = th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
assert.Nil(t, err, "Expected success.")
|
|
assert.Equal(t, 0, errLine)
|
|
assertionCount++
|
|
AssertAllPostsCount(t, th.App, initialPostCount, assertionCount, team.Id)
|
|
|
|
// Create new reply with type and edit_at for existing post with replies.
|
|
editedReplyPostTime := hashtagTime + 6
|
|
editedReplyTime := hashtagTime + 7
|
|
editedReplyEditTime := hashtagTime + 8
|
|
|
|
data = imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &user2.Username,
|
|
Message: new("Message with reply"),
|
|
CreateAt: &editedReplyPostTime,
|
|
Replies: &[]imports.ReplyImportData{{
|
|
User: &username,
|
|
Type: model.NewPointer(model.PostTypeSystemGeneric),
|
|
Message: new("Message reply 3"),
|
|
CreateAt: &editedReplyTime,
|
|
EditAt: &editedReplyEditTime,
|
|
}},
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err = th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
assert.Nil(t, err, "Expected success.")
|
|
assert.Equal(t, 0, errLine)
|
|
assertionCount += 2
|
|
AssertAllPostsCount(t, th.App, initialPostCount, assertionCount, team.Id)
|
|
|
|
// Check the reply values.
|
|
replies, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, editedReplyTime)
|
|
assert.NoError(t, nErr, "Expected success.")
|
|
reply := replies[0]
|
|
importReply := (*data.Post.Replies)[0]
|
|
replyBool := reply.Type != *importReply.Type || reply.Message != *importReply.Message || reply.CreateAt != *importReply.CreateAt || reply.EditAt != *importReply.EditAt || reply.UserId != user.Id
|
|
require.False(t, replyBool, "Post properties not as expected")
|
|
})
|
|
|
|
t.Run("import post with pinned message", func(t *testing.T) {
|
|
// Create another Team.
|
|
teamName2 := model.NewRandomTeamName()
|
|
appErr := th.App.importTeam(th.Context, &imports.TeamImportData{
|
|
Name: &teamName2,
|
|
DisplayName: new("Display Name 2"),
|
|
Type: new("O"),
|
|
}, false)
|
|
require.Nil(t, appErr, "Failed to import team.")
|
|
team2, err2 := th.App.GetTeamByName(teamName2)
|
|
require.Nil(t, err2, "Failed to get team from database.")
|
|
|
|
// Create another Channel for the another team.
|
|
appErr = th.App.importChannel(th.Context, &imports.ChannelImportData{
|
|
Team: &teamName2,
|
|
Name: &channelName,
|
|
DisplayName: new("Display Name"),
|
|
Type: &chanTypeOpen,
|
|
}, false)
|
|
require.Nil(t, appErr, "Failed to import channel.")
|
|
_, err = th.App.GetChannelByName(th.Context, channelName, team2.Id, false)
|
|
require.Nil(t, err, "Failed to get channel from database.")
|
|
|
|
// Count the number of posts in the team2.
|
|
require.NoError(t, th.App.Srv().Store().Post().RefreshPostStats())
|
|
initialPostCountForTeam2, nErr := th.App.Srv().Store().Post().AnalyticsPostCount(&model.PostCountOptions{TeamId: team2.Id})
|
|
require.NoError(t, nErr)
|
|
|
|
// Try adding two valid posts in apply mode.
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &username,
|
|
Message: new("another message"),
|
|
CreateAt: &createAt,
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
data2 := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName2,
|
|
Channel: &channelName,
|
|
User: &username,
|
|
Message: new("another message"),
|
|
CreateAt: &createAt,
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err2 := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data, data2}, false, true)
|
|
assert.Nil(t, err2)
|
|
assert.Equal(t, 0, errLine)
|
|
|
|
// Create a pinned message.
|
|
data = imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &user2.Username,
|
|
Message: new("Pinned Message"),
|
|
CreateAt: new(model.GetMillis()),
|
|
IsPinned: new(true),
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err = th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
|
|
resultPosts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, *data.Post.CreateAt)
|
|
require.NoError(t, nErr, "Expected success.")
|
|
// Should be one post only created at this time.
|
|
require.Equal(t, 1, len(resultPosts))
|
|
resultPost := resultPosts[0]
|
|
require.True(t, resultPost.IsPinned, "This post should be pinned.")
|
|
|
|
// Posts should be added to the right team
|
|
AssertAllPostsCount(t, th.App, initialPostCountForTeam2, 1, team2.Id)
|
|
assertionCount += 2
|
|
AssertAllPostsCount(t, th.App, initialPostCount, assertionCount, team.Id)
|
|
})
|
|
|
|
t.Run("Importing a post with a reply both pinned", func(t *testing.T) {
|
|
// Create a thread.
|
|
importCreate := time.Now().Add(-1 * time.Minute).UnixMilli()
|
|
replyCreate := time.Now().Add(-30 * time.Second).UnixMilli()
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &user.Username,
|
|
Message: new("Thread Message"),
|
|
CreateAt: new(importCreate),
|
|
IsPinned: new(true),
|
|
Replies: &[]imports.ReplyImportData{{
|
|
User: &user.Username,
|
|
Message: new("Reply"),
|
|
CreateAt: new(replyCreate),
|
|
IsPinned: new(true),
|
|
}},
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
|
|
_, err = th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err)
|
|
|
|
resultPosts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, importCreate)
|
|
require.NoError(t, nErr)
|
|
require.Equal(t, 1, len(resultPosts))
|
|
require.True(t, resultPosts[0].IsPinned)
|
|
|
|
resultPosts, nErr = th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, replyCreate)
|
|
require.NoError(t, nErr)
|
|
require.Equal(t, 1, len(resultPosts))
|
|
require.True(t, resultPosts[0].IsPinned)
|
|
})
|
|
|
|
t.Run("Importing a post with a thread", func(t *testing.T) {
|
|
// Create a thread.
|
|
importCreate := time.Now().Add(-1 * time.Minute).UnixMilli()
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &user.Username,
|
|
Message: new("Thread Message"),
|
|
CreateAt: new(importCreate),
|
|
Replies: &[]imports.ReplyImportData{{
|
|
User: &user.Username,
|
|
Message: new("Reply"),
|
|
CreateAt: new(model.GetMillis()),
|
|
}},
|
|
ThreadFollowers: &[]imports.ThreadFollowerImportData{{
|
|
User: &user.Username,
|
|
LastViewed: new(model.GetMillis()),
|
|
}, {
|
|
User: &user2.Username,
|
|
LastViewed: new(model.GetMillis()),
|
|
}},
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
|
|
errLine, err2 := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err2)
|
|
require.Equal(t, 0, errLine)
|
|
|
|
resultPosts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, importCreate)
|
|
require.NoError(t, nErr)
|
|
require.Equal(t, 1, len(resultPosts))
|
|
|
|
followers, nErr := th.App.Srv().Store().Thread().GetThreadFollowers(resultPosts[0].Id, true)
|
|
require.NoError(t, nErr)
|
|
|
|
assert.ElementsMatch(t, []string{user.Id, user2.Id}, followers)
|
|
})
|
|
|
|
t.Run("Importing a post with a non existent follower", func(t *testing.T) {
|
|
// Create a thread.
|
|
importCreate := time.Now().Add(-1 * time.Minute).UnixMilli()
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &user.Username,
|
|
Message: new("Thread Message"),
|
|
CreateAt: new(importCreate),
|
|
Replies: &[]imports.ReplyImportData{{
|
|
User: &user.Username,
|
|
Message: new("Reply"),
|
|
CreateAt: new(model.GetMillis()),
|
|
}},
|
|
ThreadFollowers: &[]imports.ThreadFollowerImportData{{
|
|
User: &user.Username,
|
|
LastViewed: new(model.GetMillis()),
|
|
}, {
|
|
User: new("invalid.user"),
|
|
}},
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
|
|
errLine, err := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.NotNil(t, err)
|
|
require.Equal(t, 1, errLine)
|
|
})
|
|
|
|
t.Run("Importing a post with a non existent follower", func(t *testing.T) {
|
|
importCreate := time.Now().Add(-1 * time.Minute).UnixMilli()
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &user.Username,
|
|
Message: new("Thread Message"),
|
|
CreateAt: new(importCreate),
|
|
Replies: &[]imports.ReplyImportData{{
|
|
User: &user.Username,
|
|
Message: new("Reply"),
|
|
CreateAt: new(model.GetMillis()),
|
|
}},
|
|
ThreadFollowers: &[]imports.ThreadFollowerImportData{{
|
|
User: &user.Username,
|
|
LastViewed: new(model.GetMillis()),
|
|
}, {
|
|
User: new("invalid.user"),
|
|
}},
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
|
|
errLine, err := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.NotNil(t, err)
|
|
require.Equal(t, 1, errLine)
|
|
})
|
|
|
|
t.Run("Importing a post with new followers", func(t *testing.T) {
|
|
importCreate := time.Now().Add(-5 * time.Minute).UnixMilli()
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &username,
|
|
Message: new("Hello"),
|
|
CreateAt: new(importCreate),
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
|
|
errLine, err := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
|
|
resultPosts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, importCreate)
|
|
require.NoError(t, nErr)
|
|
require.Equal(t, 1, len(resultPosts))
|
|
|
|
data = imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &user.Username,
|
|
Message: new("Hello"),
|
|
CreateAt: new(importCreate),
|
|
Replies: &[]imports.ReplyImportData{{
|
|
User: &user.Username,
|
|
Message: new("Reply"),
|
|
CreateAt: new(model.GetMillis()),
|
|
}},
|
|
ThreadFollowers: &[]imports.ThreadFollowerImportData{{
|
|
User: &user.Username,
|
|
LastViewed: new(model.GetMillis()),
|
|
}},
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
|
|
errLine, err = th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
|
|
followers, nErr := th.App.Srv().Store().Thread().GetThreadFollowers(resultPosts[0].Id, true)
|
|
require.NoError(t, nErr)
|
|
|
|
assert.ElementsMatch(t, []string{user.Id}, followers)
|
|
})
|
|
|
|
t.Run("Importing a post that someone flagged", func(t *testing.T) {
|
|
// Create a thread.
|
|
importCreate := time.Now().Add(-1 * time.Minute).UnixMilli()
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &user.Username,
|
|
Message: new("Flagged Message"),
|
|
CreateAt: new(importCreate),
|
|
FlaggedBy: &[]string{user.Username},
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
|
|
errLine, err := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
|
|
resultPosts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, importCreate)
|
|
require.NoError(t, nErr)
|
|
require.Equal(t, 1, len(resultPosts))
|
|
|
|
pref, nErr := th.App.ch.srv.Store().Preference().GetCategoryAndName(model.PreferenceCategoryFlaggedPost, resultPosts[0].Id)
|
|
require.NoError(t, nErr)
|
|
|
|
require.Len(t, pref, 1)
|
|
assert.Equal(t, user.Id, pref[0].UserId)
|
|
})
|
|
|
|
t.Run("Importing a post that someone flagged its replies", func(t *testing.T) {
|
|
// Create a thread.
|
|
importCreate := time.Now().Add(-1 * time.Minute).UnixMilli()
|
|
replyCreate := time.Now().Add(-30 * time.Second).UnixMilli()
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &user.Username,
|
|
Message: new("Flagged Message"),
|
|
CreateAt: new(importCreate),
|
|
Replies: &[]imports.ReplyImportData{{
|
|
User: &user.Username,
|
|
Message: new("Reply"),
|
|
CreateAt: new(replyCreate),
|
|
FlaggedBy: &[]string{user2.Username},
|
|
}},
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
|
|
errLine, err := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
|
|
resultPosts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, replyCreate)
|
|
require.NoError(t, nErr)
|
|
require.Equal(t, 1, len(resultPosts))
|
|
|
|
pref, nErr := th.App.ch.srv.Store().Preference().GetCategoryAndName(model.PreferenceCategoryFlaggedPost, resultPosts[0].Id)
|
|
require.NoError(t, nErr)
|
|
|
|
require.Len(t, pref, 1)
|
|
assert.Equal(t, user2.Id, pref[0].UserId)
|
|
})
|
|
}
|
|
|
|
func TestImportImportPost(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
// Create a Team.
|
|
teamName := model.NewRandomTeamName()
|
|
appErr := th.App.importTeam(th.Context, &imports.TeamImportData{
|
|
Name: &teamName,
|
|
DisplayName: new("Display Name"),
|
|
Type: new("O"),
|
|
}, false)
|
|
require.Nil(t, appErr, "Failed to import team.")
|
|
team, appErr := th.App.GetTeamByName(teamName)
|
|
require.Nil(t, appErr, "Failed to get team from database.")
|
|
|
|
// Create a Channel.
|
|
channelName := NewTestId()
|
|
chanTypeOpen := model.ChannelTypeOpen
|
|
appErr = th.App.importChannel(th.Context, &imports.ChannelImportData{
|
|
Team: &teamName,
|
|
Name: &channelName,
|
|
DisplayName: new("Display Name"),
|
|
Type: &chanTypeOpen,
|
|
}, false)
|
|
require.Nil(t, appErr, "Failed to import channel.")
|
|
channel, appErr := th.App.GetChannelByName(th.Context, channelName, team.Id, false)
|
|
require.Nil(t, appErr, "Failed to get channel from database.")
|
|
|
|
// Create a user.
|
|
username := model.NewUsername()
|
|
appErr = th.App.importUser(th.Context, &imports.UserImportData{
|
|
Username: &username,
|
|
Email: new(model.NewId() + "@example.com"),
|
|
}, false)
|
|
require.Nil(t, appErr, "Failed to import user.")
|
|
user, appErr := th.App.GetUserByUsername(username)
|
|
require.Nil(t, appErr, "Failed to get user from database.")
|
|
|
|
username2 := model.NewUsername()
|
|
appErr = th.App.importUser(th.Context, &imports.UserImportData{
|
|
Username: &username2,
|
|
Email: new(model.NewId() + "@example.com"),
|
|
}, false)
|
|
require.Nil(t, appErr, "Failed to import user.")
|
|
user2, appErr := th.App.GetUserByUsername(username2)
|
|
require.Nil(t, appErr, "Failed to get user from database.")
|
|
|
|
// Count the number of posts in the testing team.
|
|
require.NoError(t, th.App.Srv().Store().Post().RefreshPostStats())
|
|
initialPostCount, nErr := th.App.Srv().Store().Post().AnalyticsPostCount(&model.PostCountOptions{TeamId: team.Id})
|
|
require.NoError(t, nErr)
|
|
|
|
time := model.GetMillis()
|
|
hashtagTime := time + 2
|
|
replyPostTime := hashtagTime + 4
|
|
replyTime := hashtagTime + 5
|
|
posttypeTime := hashtagTime + 6
|
|
editatCreateTime := hashtagTime + 7
|
|
editatEditTime := hashtagTime + 8
|
|
|
|
t.Run("Try adding an invalid post in dry run mode", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &username,
|
|
},
|
|
},
|
|
LineNumber: 12,
|
|
}
|
|
errLine, err := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, true, true)
|
|
assert.NotNil(t, err)
|
|
assert.Equal(t, data.LineNumber, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 0, team.Id)
|
|
})
|
|
|
|
t.Run("Try adding a valid post in dry run mode", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &username,
|
|
Message: new("Hello"),
|
|
CreateAt: new(model.GetMillis()),
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, true, true)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 0, team.Id)
|
|
})
|
|
|
|
t.Run("Try adding an invalid post in apply mode", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &username,
|
|
CreateAt: new(model.GetMillis()),
|
|
},
|
|
},
|
|
LineNumber: 2,
|
|
}
|
|
errLine, err := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
assert.NotNil(t, err)
|
|
assert.Equal(t, data.LineNumber, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 0, team.Id)
|
|
})
|
|
|
|
t.Run("Try adding a valid post with invalid team in apply mode", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: new(NewTestId()),
|
|
Channel: &channelName,
|
|
User: &username,
|
|
Message: new("Message"),
|
|
CreateAt: new(model.GetMillis()),
|
|
},
|
|
},
|
|
LineNumber: 7,
|
|
}
|
|
errLine, err := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
assert.NotNil(t, err)
|
|
assert.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 0, team.Id)
|
|
})
|
|
|
|
t.Run("Try adding a valid post with invalid channel in apply mode", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: new(NewTestId()),
|
|
User: &username,
|
|
Message: new("Message"),
|
|
CreateAt: new(model.GetMillis()),
|
|
},
|
|
},
|
|
LineNumber: 8,
|
|
}
|
|
errLine, err := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
assert.NotNil(t, err)
|
|
assert.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 0, team.Id)
|
|
})
|
|
|
|
t.Run("Try adding a valid post with invalid user in apply mode", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: new(model.NewId()),
|
|
Message: new("Message"),
|
|
CreateAt: new(model.GetMillis()),
|
|
},
|
|
},
|
|
LineNumber: 9,
|
|
}
|
|
errLine, err := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
assert.NotNil(t, err)
|
|
assert.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 0, team.Id)
|
|
})
|
|
|
|
t.Run("Try adding a valid post in apply mode", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &username,
|
|
Message: new("Message"),
|
|
CreateAt: &time,
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 1, team.Id)
|
|
|
|
// Check the post values.
|
|
posts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, time)
|
|
require.NoError(t, nErr)
|
|
|
|
require.Len(t, posts, 1, "Unexpected number of posts found.")
|
|
|
|
post := posts[0]
|
|
postBool := post.Message != *data.Post.Message || post.CreateAt != *data.Post.CreateAt || post.UserId != user.Id
|
|
require.False(t, postBool, "Post properties not as expected")
|
|
})
|
|
|
|
t.Run("Update the post", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &username2,
|
|
Message: new("Message"),
|
|
CreateAt: &time,
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 1, team.Id)
|
|
|
|
// Check the post values.
|
|
posts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, time)
|
|
require.NoError(t, nErr)
|
|
|
|
require.Len(t, posts, 1, "Unexpected number of posts found.")
|
|
|
|
post := posts[0]
|
|
postBool := post.Message != *data.Post.Message || post.CreateAt != *data.Post.CreateAt || post.UserId != user2.Id
|
|
require.False(t, postBool, "Post properties not as expected")
|
|
})
|
|
|
|
t.Run("Save the post with a different time", func(t *testing.T) {
|
|
newTime := time + 1
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &username,
|
|
Message: new("Message"),
|
|
CreateAt: &newTime,
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 2, team.Id)
|
|
})
|
|
|
|
t.Run("Save the post with a different message", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &username,
|
|
Message: new("Message 2"),
|
|
CreateAt: &time,
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 3, team.Id)
|
|
})
|
|
|
|
t.Run("Test with hashtag", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &username,
|
|
Message: new("Message 2 #hashtagmashupcity"),
|
|
CreateAt: &hashtagTime,
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 4, team.Id)
|
|
|
|
posts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, hashtagTime)
|
|
require.NoError(t, nErr)
|
|
|
|
require.Len(t, posts, 1, "Unexpected number of posts found.")
|
|
|
|
post := posts[0]
|
|
postBool := post.Message != *data.Post.Message || post.CreateAt != *data.Post.CreateAt || post.UserId != user.Id
|
|
require.False(t, postBool, "Post properties not as expected")
|
|
|
|
require.Equal(t, "#hashtagmashupcity", post.Hashtags, "Hashtags not as expected: %s", post.Hashtags)
|
|
})
|
|
|
|
t.Run("Post with flags", func(t *testing.T) {
|
|
flagsTime := hashtagTime + 1
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &username,
|
|
Message: new("Message with Favorites"),
|
|
CreateAt: &flagsTime,
|
|
FlaggedBy: &[]string{
|
|
username,
|
|
username2,
|
|
},
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
|
|
errLine, err := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err, "Expected success.")
|
|
require.Equal(t, 0, errLine)
|
|
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 5, team.Id)
|
|
|
|
// Check the post values.
|
|
posts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, flagsTime)
|
|
require.NoError(t, nErr)
|
|
|
|
require.Len(t, posts, 1, "Unexpected number of posts found.")
|
|
|
|
post := posts[0]
|
|
postBool := post.Message != *data.Post.Message || post.CreateAt != *data.Post.CreateAt || post.UserId != user.Id
|
|
require.False(t, postBool, "Post properties not as expected")
|
|
|
|
checkPreference(t, th.App, user.Id, model.PreferenceCategoryFlaggedPost, post.Id, "true")
|
|
checkPreference(t, th.App, user2.Id, model.PreferenceCategoryFlaggedPost, post.Id, "true")
|
|
})
|
|
|
|
t.Run("Post with reaction", func(t *testing.T) {
|
|
reactionPostTime := hashtagTime + 2
|
|
reactionTime := hashtagTime + 3
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &username,
|
|
Message: new("Message with reaction"),
|
|
CreateAt: &reactionPostTime,
|
|
Reactions: &[]imports.ReactionImportData{{
|
|
User: &user2.Username,
|
|
EmojiName: new("+1"),
|
|
CreateAt: &reactionTime,
|
|
}},
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err, "Expected success.")
|
|
require.Equal(t, 0, errLine)
|
|
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 6, team.Id)
|
|
|
|
// Check the post values.
|
|
posts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, reactionPostTime)
|
|
require.NoError(t, nErr)
|
|
|
|
require.Len(t, posts, 1, "Unexpected number of posts found.")
|
|
|
|
post := posts[0]
|
|
postBool := post.Message != *data.Post.Message || post.CreateAt != *data.Post.CreateAt || post.UserId != user.Id || !post.HasReactions
|
|
require.False(t, postBool, "Post properties not as expected")
|
|
|
|
reactions, nErr := th.App.Srv().Store().Reaction().GetForPost(post.Id, false)
|
|
require.NoError(t, nErr, "Can't get reaction")
|
|
|
|
require.Len(t, reactions, 1, "Invalid number of reactions")
|
|
})
|
|
|
|
t.Run("Post with reply", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &username,
|
|
Message: new("Message with reply"),
|
|
CreateAt: &replyPostTime,
|
|
Replies: &[]imports.ReplyImportData{{
|
|
User: &user2.Username,
|
|
Message: new("Message reply"),
|
|
CreateAt: &replyTime,
|
|
}},
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err, "Expected success.")
|
|
require.Equal(t, 0, errLine)
|
|
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 8, team.Id)
|
|
|
|
// Check the post values.
|
|
posts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, replyPostTime)
|
|
require.NoError(t, nErr)
|
|
|
|
require.Len(t, posts, 1, "Unexpected number of posts found.")
|
|
|
|
post := posts[0]
|
|
postBool := post.Message != *data.Post.Message || post.CreateAt != *data.Post.CreateAt || post.UserId != user.Id
|
|
require.False(t, postBool, "Post properties not as expected")
|
|
|
|
// Check the reply values.
|
|
replies, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, replyTime)
|
|
require.NoError(t, nErr)
|
|
|
|
require.Len(t, replies, 1, "Unexpected number of posts found.")
|
|
|
|
reply := replies[0]
|
|
replyBool := reply.Message != *(*data.Post.Replies)[0].Message || reply.CreateAt != *(*data.Post.Replies)[0].CreateAt || reply.UserId != user2.Id
|
|
require.False(t, replyBool, "Post properties not as expected")
|
|
|
|
require.Equal(t, post.Id, reply.RootId, "Unexpected reply RootId")
|
|
})
|
|
|
|
t.Run("Update post with replies", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &user2.Username,
|
|
Message: new("Message with reply"),
|
|
CreateAt: &replyPostTime,
|
|
Replies: &[]imports.ReplyImportData{{
|
|
User: &username,
|
|
Message: new("Message reply"),
|
|
CreateAt: &replyTime,
|
|
}},
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err, "Expected success.")
|
|
require.Equal(t, 0, errLine)
|
|
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 8, team.Id)
|
|
})
|
|
|
|
t.Run("Create new post with replies based on the previous one", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &user2.Username,
|
|
Message: new("Message with reply 2"),
|
|
CreateAt: &replyPostTime,
|
|
Replies: &[]imports.ReplyImportData{{
|
|
User: &username,
|
|
Message: new("Message reply"),
|
|
CreateAt: &replyTime,
|
|
}},
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err, "Expected success.")
|
|
require.Equal(t, 0, errLine)
|
|
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 10, team.Id)
|
|
})
|
|
|
|
t.Run("Create new reply for existing post with replies", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &user2.Username,
|
|
Message: new("Message with reply"),
|
|
CreateAt: &replyPostTime,
|
|
Replies: &[]imports.ReplyImportData{{
|
|
User: &username,
|
|
Message: new("Message reply 2"),
|
|
CreateAt: &replyTime,
|
|
}},
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err, "Expected success.")
|
|
require.Equal(t, 0, errLine)
|
|
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 11, team.Id)
|
|
})
|
|
|
|
t.Run("Post with Type", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &username,
|
|
Type: model.NewPointer(model.PostTypeSystemGeneric),
|
|
Message: new("Message with Type"),
|
|
CreateAt: &posttypeTime,
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
|
|
errLine, err := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err, "Expected success.")
|
|
require.Equal(t, 0, errLine)
|
|
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 12, team.Id)
|
|
|
|
// Check the post values.
|
|
posts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, posttypeTime)
|
|
require.NoError(t, nErr)
|
|
|
|
require.Len(t, posts, 1, "Unexpected number of posts found.")
|
|
|
|
post := posts[0]
|
|
postBool := post.Message != *data.Post.Message || post.CreateAt != *data.Post.CreateAt || post.UserId != user.Id || post.Type != *data.Post.Type
|
|
require.False(t, postBool, "Post properties not as expected")
|
|
})
|
|
|
|
t.Run("Post with EditAt", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &username,
|
|
Message: new("Message with Type"),
|
|
CreateAt: &editatCreateTime,
|
|
EditAt: &editatEditTime,
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
|
|
errLine, err := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err, "Expected success.")
|
|
require.Equal(t, 0, errLine)
|
|
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 13, team.Id)
|
|
|
|
// Check the post values.
|
|
posts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, editatCreateTime)
|
|
require.NoError(t, nErr)
|
|
|
|
require.Len(t, posts, 1, "Unexpected number of posts found.")
|
|
|
|
post := posts[0]
|
|
postBool := post.Message != *data.Post.Message || post.CreateAt != *data.Post.CreateAt || post.UserId != user.Id || post.EditAt != *data.Post.EditAt
|
|
require.False(t, postBool, "Post properties not as expected")
|
|
})
|
|
|
|
t.Run("Reply CreateAt before parent post CreateAt", func(t *testing.T) {
|
|
now := model.GetMillis()
|
|
before := now - 10
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &user2.Username,
|
|
Message: new("Message with reply"),
|
|
CreateAt: &now,
|
|
Replies: &[]imports.ReplyImportData{{
|
|
User: &username,
|
|
Message: new("Message reply 2"),
|
|
CreateAt: &before,
|
|
}},
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
|
|
errLine, err := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err, "Expected success.")
|
|
require.Equal(t, 0, errLine)
|
|
|
|
posts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, now)
|
|
require.NoError(t, nErr)
|
|
require.Len(t, posts, 2, "Unexpected number of posts found.")
|
|
require.NoError(t, th.TestLogger.Flush())
|
|
testlib.AssertLog(t, th.LogBuffer, mlog.LvlWarn.Name, "Reply CreateAt is before parent post CreateAt, setting it to parent post CreateAt")
|
|
|
|
rootPost := posts[0]
|
|
replyPost := posts[1]
|
|
if rootPost.RootId != "" {
|
|
replyPost = posts[0]
|
|
rootPost = posts[1]
|
|
}
|
|
require.Equal(t, rootPost.Id, replyPost.RootId)
|
|
require.Equal(t, now, replyPost.CreateAt)
|
|
})
|
|
}
|
|
|
|
func TestImportImportDirectChannel(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
user3 := th.CreateUser(t)
|
|
|
|
// Check how many channels are in the database.
|
|
directChannelCount, err := th.App.Srv().Store().Channel().AnalyticsTypeCount("", model.ChannelTypeDirect)
|
|
require.NoError(t, err, "Failed to get direct channel count.")
|
|
|
|
groupChannelCount, err := th.App.Srv().Store().Channel().AnalyticsTypeCount("", model.ChannelTypeGroup)
|
|
require.NoError(t, err, "Failed to get group channel count.")
|
|
|
|
// We need to generate the dataset twice to test the same data with different formats.
|
|
generateDataset := func(data imports.DirectChannelImportData) map[string]imports.DirectChannelImportData {
|
|
members := make([]string, len(data.Participants))
|
|
for i, member := range data.Participants {
|
|
members[i] = *member.Username
|
|
}
|
|
|
|
return map[string]imports.DirectChannelImportData{
|
|
"Participants": data,
|
|
"Members": {
|
|
Members: &members,
|
|
},
|
|
}
|
|
}
|
|
|
|
t.Run("Invalid channel in dry-run mode", func(t *testing.T) {
|
|
dataset := generateDataset(imports.DirectChannelImportData{
|
|
Participants: []*imports.DirectChannelMemberImportData{
|
|
{
|
|
Username: new(model.NewId()),
|
|
},
|
|
},
|
|
Header: new("Channel Header"),
|
|
})
|
|
for name, data := range dataset {
|
|
t.Run(name, func(t *testing.T) {
|
|
err = th.App.importDirectChannel(th.Context, &data, true)
|
|
require.Error(t, err)
|
|
|
|
// Check that no more channels are in the DB.
|
|
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount)
|
|
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("Valid DIRECT channel with a nonexistent member in dry-run mode", func(t *testing.T) {
|
|
dataset := generateDataset(imports.DirectChannelImportData{
|
|
Participants: []*imports.DirectChannelMemberImportData{
|
|
{
|
|
Username: new(model.NewId()),
|
|
},
|
|
{
|
|
Username: new(model.NewId()),
|
|
},
|
|
},
|
|
})
|
|
for name, data := range dataset {
|
|
t.Run(name, func(t *testing.T) {
|
|
appErr := th.App.importDirectChannel(th.Context, &data, true)
|
|
require.Nil(t, appErr)
|
|
|
|
// Check that no more channels are in the DB.
|
|
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount)
|
|
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("Valid GROUP channel with a nonexistent member in dry-run mode", func(t *testing.T) {
|
|
dataset := generateDataset(imports.DirectChannelImportData{
|
|
Participants: []*imports.DirectChannelMemberImportData{
|
|
{
|
|
Username: new(model.NewId()),
|
|
},
|
|
{
|
|
Username: new(model.NewId()),
|
|
},
|
|
{
|
|
Username: new(model.NewId()),
|
|
},
|
|
},
|
|
})
|
|
for name, data := range dataset {
|
|
t.Run(name, func(t *testing.T) {
|
|
appErr := th.App.importDirectChannel(th.Context, &data, true)
|
|
require.Nil(t, appErr)
|
|
|
|
// Check that no more channels are in the DB.
|
|
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount)
|
|
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("Invalid channel in apply mode", func(t *testing.T) {
|
|
dataset := generateDataset(imports.DirectChannelImportData{
|
|
Participants: []*imports.DirectChannelMemberImportData{
|
|
{
|
|
Username: new(model.NewId()),
|
|
},
|
|
},
|
|
})
|
|
for name, data := range dataset {
|
|
t.Run(name, func(t *testing.T) {
|
|
err = th.App.importDirectChannel(th.Context, &data, false)
|
|
require.Error(t, err)
|
|
|
|
// Check that no more channels are in the DB.
|
|
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount)
|
|
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("Valid DIRECT channel ", func(t *testing.T) {
|
|
dataset := generateDataset(imports.DirectChannelImportData{
|
|
Participants: []*imports.DirectChannelMemberImportData{
|
|
{
|
|
Username: new(th.BasicUser.Username),
|
|
},
|
|
{
|
|
Username: new(th.BasicUser2.Username),
|
|
},
|
|
},
|
|
})
|
|
for name, data := range dataset {
|
|
t.Run(name, func(t *testing.T) {
|
|
appErr := th.App.importDirectChannel(th.Context, &data, false)
|
|
require.Nil(t, appErr)
|
|
|
|
// Check that one more DIRECT channel is in the DB.
|
|
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount+1)
|
|
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount)
|
|
|
|
// Do the same DIRECT channel again.
|
|
appErr = th.App.importDirectChannel(th.Context, &data, false)
|
|
require.Nil(t, appErr)
|
|
|
|
// Check that no more channels are in the DB.
|
|
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount+1)
|
|
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount)
|
|
|
|
// Update the channel's HEADER
|
|
data.Header = new("New Channel Header 2")
|
|
appErr = th.App.importDirectChannel(th.Context, &data, false)
|
|
require.Nil(t, appErr)
|
|
|
|
// Check that no more channels are in the DB.
|
|
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount+1)
|
|
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount)
|
|
|
|
// Get the channel to check that the header was updated.
|
|
channel, appErr := th.App.GetOrCreateDirectChannel(th.Context, th.BasicUser.Id, th.BasicUser2.Id)
|
|
require.Nil(t, appErr)
|
|
require.Equal(t, channel.Header, *data.Header)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("GROUP channel with an extra invalid member", func(t *testing.T) {
|
|
dataset := generateDataset(imports.DirectChannelImportData{
|
|
Participants: []*imports.DirectChannelMemberImportData{
|
|
{
|
|
Username: new(th.BasicUser.Username),
|
|
},
|
|
{
|
|
Username: new(th.BasicUser2.Username),
|
|
},
|
|
{
|
|
Username: new(user3.Username),
|
|
},
|
|
{
|
|
Username: new(model.NewId()),
|
|
},
|
|
},
|
|
})
|
|
for name, data := range dataset {
|
|
t.Run(name, func(t *testing.T) {
|
|
appErr := th.App.importDirectChannel(th.Context, &data, false)
|
|
require.NotNil(t, appErr)
|
|
|
|
// Check that no more channels are in the DB.
|
|
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount+1)
|
|
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("Valid GROUP channel", func(t *testing.T) {
|
|
dataset := generateDataset(imports.DirectChannelImportData{
|
|
Participants: []*imports.DirectChannelMemberImportData{
|
|
{
|
|
Username: new(th.BasicUser.Username),
|
|
},
|
|
{
|
|
Username: new(th.BasicUser2.Username),
|
|
},
|
|
{
|
|
Username: new(user3.Username),
|
|
},
|
|
},
|
|
})
|
|
for name, data := range dataset {
|
|
t.Run(name, func(t *testing.T) {
|
|
appErr := th.App.importDirectChannel(th.Context, &data, false)
|
|
require.Nil(t, appErr)
|
|
|
|
// Check that one more GROUP channel is in the DB.
|
|
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount+1)
|
|
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount+1)
|
|
|
|
// Do the same DIRECT channel again.
|
|
appErr = th.App.importDirectChannel(th.Context, &data, false)
|
|
require.Nil(t, appErr)
|
|
|
|
// Check that no more channels are in the DB.
|
|
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount+1)
|
|
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount+1)
|
|
|
|
// Update the channel's HEADER
|
|
data.Header = new("New Channel Header 3")
|
|
appErr = th.App.importDirectChannel(th.Context, &data, false)
|
|
require.Nil(t, appErr)
|
|
|
|
// Check that no more channels are in the DB.
|
|
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount+1)
|
|
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount+1)
|
|
|
|
// Get the channel to check that the header was updated.
|
|
userIDs := []string{
|
|
th.BasicUser.Id,
|
|
th.BasicUser2.Id,
|
|
user3.Id,
|
|
}
|
|
channel, appErr := th.App.createGroupChannel(th.Context, userIDs, th.BasicUser.Id)
|
|
require.Equal(t, appErr.Id, store.ChannelExistsError)
|
|
require.Equal(t, channel.Header, *data.Header)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("Import a channel with some favorites", func(t *testing.T) {
|
|
dataset := generateDataset(imports.DirectChannelImportData{
|
|
Participants: []*imports.DirectChannelMemberImportData{
|
|
{
|
|
Username: new(th.BasicUser.Username),
|
|
},
|
|
{
|
|
Username: new(th.BasicUser2.Username),
|
|
},
|
|
},
|
|
})
|
|
for name, data := range dataset {
|
|
t.Run(name, func(t *testing.T) {
|
|
data.FavoritedBy = &[]string{
|
|
th.BasicUser.Username,
|
|
th.BasicUser2.Username,
|
|
}
|
|
appErr := th.App.importDirectChannel(th.Context, &data, false)
|
|
require.Nil(t, appErr)
|
|
|
|
channel, appErr := th.App.GetOrCreateDirectChannel(th.Context, th.BasicUser.Id, th.BasicUser2.Id)
|
|
require.Nil(t, appErr)
|
|
checkPreference(t, th.App, th.BasicUser.Id, model.PreferenceCategoryFavoriteChannel, channel.Id, "true")
|
|
checkPreference(t, th.App, th.BasicUser2.Id, model.PreferenceCategoryFavoriteChannel, channel.Id, "true")
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("Import a DM channel and user last view should be imported", func(t *testing.T) {
|
|
lastView := model.GetMillis()
|
|
data := imports.DirectChannelImportData{
|
|
Participants: []*imports.DirectChannelMemberImportData{
|
|
{
|
|
Username: new(th.BasicUser.Username),
|
|
LastViewedAt: new(lastView),
|
|
},
|
|
{
|
|
Username: new(th.BasicUser2.Username),
|
|
},
|
|
},
|
|
}
|
|
|
|
appErr := th.App.importDirectChannel(th.Context, &data, false)
|
|
require.Nil(t, appErr)
|
|
|
|
channel, appErr := th.App.GetOrCreateDirectChannel(th.Context, th.BasicUser.Id, th.BasicUser2.Id)
|
|
require.Nil(t, appErr)
|
|
|
|
members, appErr := th.App.GetChannelMembersPage(th.Context, channel.Id, 0, 100)
|
|
require.Nil(t, appErr)
|
|
require.Len(t, members, 2)
|
|
|
|
for _, member := range members {
|
|
if member.UserId == th.BasicUser.Id {
|
|
require.Equal(t, member.LastViewedAt, lastView)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("Import a DM channel and preserve if the channel was shown to users", func(t *testing.T) {
|
|
data := imports.DirectChannelImportData{
|
|
Participants: []*imports.DirectChannelMemberImportData{
|
|
{
|
|
Username: new(th.BasicUser.Username),
|
|
},
|
|
{
|
|
Username: new(th.BasicUser2.Username),
|
|
},
|
|
},
|
|
ShownBy: &[]string{
|
|
th.BasicUser.Username,
|
|
},
|
|
}
|
|
|
|
appErr := th.App.importDirectChannel(th.Context, &data, false)
|
|
require.Nil(t, appErr)
|
|
|
|
channel, appErr := th.App.GetOrCreateDirectChannel(th.Context, th.BasicUser.Id, th.BasicUser2.Id)
|
|
require.Nil(t, appErr)
|
|
|
|
members, appErr := th.App.GetChannelMembersPage(th.Context, channel.Id, 0, 100)
|
|
require.Nil(t, appErr)
|
|
require.Len(t, members, 2)
|
|
|
|
for _, member := range members {
|
|
if member.UserId == th.BasicUser.Id {
|
|
checkPreference(t, th.App, th.BasicUser.Id, model.PreferenceCategoryDirectChannelShow, th.BasicUser2.Id, "true")
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("Import a GM channel and preserve if the channel was shown to users", func(t *testing.T) {
|
|
data := imports.DirectChannelImportData{
|
|
Participants: []*imports.DirectChannelMemberImportData{
|
|
{
|
|
Username: new(th.BasicUser.Username),
|
|
},
|
|
{
|
|
Username: new(th.BasicUser2.Username),
|
|
},
|
|
{
|
|
Username: new(user3.Username),
|
|
},
|
|
},
|
|
ShownBy: &[]string{
|
|
th.BasicUser.Username,
|
|
},
|
|
}
|
|
|
|
appErr := th.App.importDirectChannel(th.Context, &data, false)
|
|
require.Nil(t, appErr)
|
|
|
|
channel, appErr := th.App.GetGroupChannel(th.Context, []string{th.BasicUser.Id, th.BasicUser2.Id, user3.Id})
|
|
require.Nil(t, appErr)
|
|
|
|
members, appErr := th.App.GetChannelMembersPage(th.Context, channel.Id, 0, 100)
|
|
require.Nil(t, appErr)
|
|
require.Len(t, members, 3)
|
|
|
|
for _, member := range members {
|
|
if member.UserId == th.BasicUser.Id {
|
|
checkPreference(t, th.App, th.BasicUser.Id, model.PreferenceCategoryGroupChannelShow, channel.Id, "true")
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("Import a DM channel without scheme flags defaults SchemeUser to true", func(t *testing.T) {
|
|
// Regression test for MM-68914: when the import data does not carry
|
|
// scheme flags on participants, the resulting channel members must
|
|
// still default to SchemeUser=true so the client receives a usable
|
|
// role for the DM channel.
|
|
//
|
|
// Uses fresh users so there is no pre-existing channel and the
|
|
// participants are not skipped by the LastViewedAt freshness guard
|
|
// in importDirectChannel. That guarantees UpdateMultipleMembers is
|
|
// actually invoked with the import-built members, which is where
|
|
// the bug manifests.
|
|
dmUserA := th.CreateUser(t)
|
|
dmUserB := th.CreateUser(t)
|
|
|
|
data := imports.DirectChannelImportData{
|
|
Participants: []*imports.DirectChannelMemberImportData{
|
|
{Username: new(dmUserA.Username)},
|
|
{Username: new(dmUserB.Username)},
|
|
},
|
|
}
|
|
|
|
appErr := th.App.importDirectChannel(th.Context, &data, false)
|
|
require.Nil(t, appErr)
|
|
|
|
channel, appErr := th.App.GetOrCreateDirectChannel(th.Context, dmUserA.Id, dmUserB.Id)
|
|
require.Nil(t, appErr)
|
|
|
|
members, appErr := th.App.GetChannelMembersPage(th.Context, channel.Id, 0, 100)
|
|
require.Nil(t, appErr)
|
|
require.Len(t, members, 2)
|
|
|
|
for _, member := range members {
|
|
require.True(t, member.SchemeUser, "SchemeUser should default to true for non-guest DM participants")
|
|
require.False(t, member.SchemeGuest)
|
|
require.NotEmpty(t, member.Roles, "Roles should not be empty for imported DM members")
|
|
}
|
|
})
|
|
|
|
t.Run("Import a GM channel without scheme flags defaults SchemeUser to true", func(t *testing.T) {
|
|
// Regression test for MM-68914 covering the group channel path.
|
|
// Uses fresh users for the same reasons as the DM case above.
|
|
gmUserA := th.CreateUser(t)
|
|
gmUserB := th.CreateUser(t)
|
|
gmUserC := th.CreateUser(t)
|
|
|
|
data := imports.DirectChannelImportData{
|
|
Participants: []*imports.DirectChannelMemberImportData{
|
|
{Username: new(gmUserA.Username)},
|
|
{Username: new(gmUserB.Username)},
|
|
{Username: new(gmUserC.Username)},
|
|
},
|
|
}
|
|
|
|
appErr := th.App.importDirectChannel(th.Context, &data, false)
|
|
require.Nil(t, appErr)
|
|
|
|
channel, appErr := th.App.GetGroupChannel(th.Context, []string{gmUserA.Id, gmUserB.Id, gmUserC.Id})
|
|
require.Nil(t, appErr)
|
|
|
|
members, appErr := th.App.GetChannelMembersPage(th.Context, channel.Id, 0, 100)
|
|
require.Nil(t, appErr)
|
|
require.Len(t, members, 3)
|
|
|
|
for _, member := range members {
|
|
require.True(t, member.SchemeUser, "SchemeUser should default to true for non-guest GM participants")
|
|
require.False(t, member.SchemeGuest)
|
|
require.NotEmpty(t, member.Roles, "Roles should not be empty for imported GM members")
|
|
}
|
|
})
|
|
|
|
// Regression test for MM-68736: when the GM hash already exists in Channels but one
|
|
// of the import's participants is missing from ChannelMembers, the importer used to
|
|
// call UpdateMultipleMembers for the missing user, which UPDATEs zero rows, then
|
|
// SELECTs the row back, gets sql.ErrNoRows, and fails the import with
|
|
// "ChannelMember not found". The fix inserts the missing membership row first.
|
|
t.Run("GROUP channel with pre-existing partial membership recovers all participants", func(t *testing.T) {
|
|
userA := th.CreateUser(t)
|
|
userB := th.CreateUser(t)
|
|
userC := th.CreateUser(t)
|
|
userIDs := []string{userA.Id, userB.Id, userC.Id}
|
|
|
|
// Pre-create the GM through the regular path so the Channels row and full
|
|
// membership exist, then drop userC at the store level to simulate the
|
|
// drifted/partial state described in the ticket.
|
|
gm, appErr := th.App.createGroupChannel(th.Context, userIDs, userA.Id)
|
|
require.Nil(t, appErr)
|
|
require.NoError(t, th.App.Srv().Store().Channel().RemoveMember(th.Context, gm.Id, userC.Id))
|
|
|
|
preMembers, appErr := th.App.GetChannelMembersPage(th.Context, gm.Id, 0, 100)
|
|
require.Nil(t, appErr)
|
|
require.Len(t, preMembers, 2, "precondition: userC should not be a member before import")
|
|
|
|
lastView := model.GetMillis()
|
|
data := imports.DirectChannelImportData{
|
|
Participants: []*imports.DirectChannelMemberImportData{
|
|
{Username: model.NewPointer(userA.Username)},
|
|
{Username: model.NewPointer(userB.Username)},
|
|
{
|
|
Username: model.NewPointer(userC.Username),
|
|
LastViewedAt: model.NewPointer(lastView),
|
|
},
|
|
},
|
|
}
|
|
|
|
appErr = th.App.importDirectChannel(th.Context, &data, false)
|
|
require.Nil(t, appErr, "import must not fail on pre-existing GM with partial membership")
|
|
|
|
postMembers, appErr := th.App.GetChannelMembersPage(th.Context, gm.Id, 0, 100)
|
|
require.Nil(t, appErr)
|
|
require.Len(t, postMembers, 3, "userC should have been re-added by the import")
|
|
|
|
var restored *model.ChannelMember
|
|
for i := range postMembers {
|
|
if postMembers[i].UserId == userC.Id {
|
|
restored = &postMembers[i]
|
|
break
|
|
}
|
|
}
|
|
require.NotNil(t, restored, "userC must be present in the channel members after the import")
|
|
// LastViewedAt from the import data should have been applied via the
|
|
// subsequent UpdateMultipleMembers UPDATE on the newly-inserted row.
|
|
require.Equal(t, lastView, restored.LastViewedAt)
|
|
})
|
|
|
|
// Companion to the regression above: re-running the import after the channel is
|
|
// fully populated should remain idempotent and not fall through any insert path.
|
|
t.Run("GROUP channel re-import with full membership stays idempotent", func(t *testing.T) {
|
|
userA := th.CreateUser(t)
|
|
userB := th.CreateUser(t)
|
|
userC := th.CreateUser(t)
|
|
|
|
data := imports.DirectChannelImportData{
|
|
Participants: []*imports.DirectChannelMemberImportData{
|
|
{Username: model.NewPointer(userA.Username)},
|
|
{Username: model.NewPointer(userB.Username)},
|
|
{Username: model.NewPointer(userC.Username)},
|
|
},
|
|
}
|
|
|
|
appErr := th.App.importDirectChannel(th.Context, &data, false)
|
|
require.Nil(t, appErr)
|
|
|
|
gm, appErr := th.App.GetGroupChannel(th.Context, []string{userA.Id, userB.Id, userC.Id})
|
|
require.Nil(t, appErr)
|
|
|
|
// Capture the cutoff so we can confirm no membership-change rows are
|
|
// logged by the second import. The fix only calls LogJoinEvent after a
|
|
// successful SaveMember insert, so an empty result here proves the
|
|
// missing-member branch was not entered for any participant.
|
|
beforeSecondRun := model.GetMillis()
|
|
|
|
appErr = th.App.importDirectChannel(th.Context, &data, false)
|
|
require.Nil(t, appErr)
|
|
|
|
members, appErr := th.App.GetChannelMembersPage(th.Context, gm.Id, 0, 100)
|
|
require.Nil(t, appErr)
|
|
require.Len(t, members, 3)
|
|
|
|
changes, nErr := th.App.Srv().Store().ChannelMemberHistory().GetMembershipChanges(gm.Id, beforeSecondRun, 100)
|
|
require.NoError(t, nErr)
|
|
require.Empty(t, changes, "second import must not log any membership changes when all participants are already members")
|
|
})
|
|
}
|
|
|
|
func TestImportImportDirectPost(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
// Create the DIRECT channel.
|
|
channelData := imports.DirectChannelImportData{
|
|
Participants: []*imports.DirectChannelMemberImportData{
|
|
{
|
|
Username: new(th.BasicUser.Username),
|
|
},
|
|
{
|
|
Username: new(th.BasicUser2.Username),
|
|
},
|
|
},
|
|
}
|
|
appErr := th.App.importDirectChannel(th.Context, &channelData, false)
|
|
require.Nil(t, appErr)
|
|
|
|
// Get the channel.
|
|
var directChannel *model.Channel
|
|
channel, appErr := th.App.GetOrCreateDirectChannel(th.Context, th.BasicUser.Id, th.BasicUser2.Id)
|
|
require.Nil(t, appErr)
|
|
require.NotEmpty(t, channel)
|
|
directChannel = channel
|
|
|
|
// Get the number of posts in the system.
|
|
require.NoError(t, th.App.Srv().Store().Post().RefreshPostStats())
|
|
result, err := th.App.Srv().Store().Post().AnalyticsPostCount(&model.PostCountOptions{})
|
|
require.NoError(t, err)
|
|
initialPostCount := result
|
|
initialDate := model.GetMillis()
|
|
posttypeDate := initialDate + 3
|
|
editatCreateDate := initialDate + 4
|
|
editatEditDate := initialDate + 5
|
|
|
|
t.Run("Try adding an invalid post in dry run mode", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
th.BasicUser.Username,
|
|
th.BasicUser2.Username,
|
|
},
|
|
User: new(th.BasicUser.Username),
|
|
CreateAt: new(model.GetMillis()),
|
|
},
|
|
},
|
|
LineNumber: 7,
|
|
}
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{data}, true, true)
|
|
require.NotNil(t, err)
|
|
require.Equal(t, data.LineNumber, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 0, "")
|
|
})
|
|
|
|
t.Run("Try adding a valid post in dry run mode", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
th.BasicUser.Username,
|
|
th.BasicUser2.Username,
|
|
},
|
|
User: new(th.BasicUser.Username),
|
|
Message: new("Message"),
|
|
CreateAt: new(model.GetMillis()),
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{data}, true, true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 0, "")
|
|
})
|
|
|
|
t.Run("Try adding an invalid post in apply mode", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
th.BasicUser.Username,
|
|
model.NewId(),
|
|
},
|
|
User: new(th.BasicUser.Username),
|
|
Message: new("Message"),
|
|
CreateAt: new(model.GetMillis()),
|
|
},
|
|
},
|
|
LineNumber: 9,
|
|
}
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.NotNil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 0, "")
|
|
})
|
|
|
|
t.Run("Try adding a valid post in apply mode", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
th.BasicUser.Username,
|
|
th.BasicUser2.Username,
|
|
},
|
|
User: new(th.BasicUser.Username),
|
|
Message: new("Message"),
|
|
CreateAt: new(initialDate),
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 1, "")
|
|
|
|
// Check the post values.
|
|
posts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(directChannel.Id, *data.DirectPost.CreateAt)
|
|
require.NoError(t, nErr)
|
|
require.Len(t, posts, 1)
|
|
|
|
post := posts[0]
|
|
require.Equal(t, post.Message, *data.DirectPost.Message)
|
|
require.Equal(t, post.CreateAt, *data.DirectPost.CreateAt)
|
|
require.Equal(t, post.UserId, th.BasicUser.Id)
|
|
})
|
|
|
|
t.Run("Import the post again", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
th.BasicUser.Username,
|
|
th.BasicUser2.Username,
|
|
},
|
|
User: new(th.BasicUser.Username),
|
|
Message: new("Message"),
|
|
CreateAt: new(initialDate),
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 1, "")
|
|
|
|
// Check the post values.
|
|
posts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(directChannel.Id, *data.DirectPost.CreateAt)
|
|
require.NoError(t, nErr)
|
|
require.Len(t, posts, 1)
|
|
|
|
post := posts[0]
|
|
require.Equal(t, post.Message, *data.DirectPost.Message)
|
|
require.Equal(t, post.CreateAt, *data.DirectPost.CreateAt)
|
|
require.Equal(t, post.UserId, th.BasicUser.Id)
|
|
})
|
|
|
|
t.Run("Save the post with a different time", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
th.BasicUser.Username,
|
|
th.BasicUser2.Username,
|
|
},
|
|
User: new(th.BasicUser.Username),
|
|
Message: new("Message"),
|
|
CreateAt: new(initialDate + 1),
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 2, "")
|
|
})
|
|
|
|
t.Run("Save the post with a different message", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
th.BasicUser.Username,
|
|
th.BasicUser2.Username,
|
|
},
|
|
User: new(th.BasicUser.Username),
|
|
Message: new("Message 2"),
|
|
CreateAt: new(initialDate + 1),
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 3, "")
|
|
})
|
|
|
|
t.Run("Test with hashtag", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
th.BasicUser.Username,
|
|
th.BasicUser2.Username,
|
|
},
|
|
User: new(th.BasicUser.Username),
|
|
Message: new("Message 2 #hashtagmashupcity"),
|
|
CreateAt: new(initialDate + 2),
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 4, "")
|
|
|
|
posts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(directChannel.Id, *data.DirectPost.CreateAt)
|
|
require.NoError(t, nErr)
|
|
require.Len(t, posts, 1)
|
|
|
|
post := posts[0]
|
|
require.Equal(t, post.Message, *data.DirectPost.Message)
|
|
require.Equal(t, post.CreateAt, *data.DirectPost.CreateAt)
|
|
require.Equal(t, post.UserId, th.BasicUser.Id)
|
|
require.Equal(t, post.Hashtags, "#hashtagmashupcity")
|
|
})
|
|
|
|
t.Run("Test with some flags", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
th.BasicUser.Username,
|
|
th.BasicUser2.Username,
|
|
},
|
|
FlaggedBy: &[]string{
|
|
th.BasicUser.Username,
|
|
th.BasicUser2.Username,
|
|
},
|
|
User: new(th.BasicUser.Username),
|
|
Message: new("Message"),
|
|
CreateAt: new(model.GetMillis()),
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 5, "")
|
|
|
|
// Check the post values.
|
|
posts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(directChannel.Id, *data.DirectPost.CreateAt)
|
|
require.NoError(t, nErr)
|
|
require.Len(t, posts, 1)
|
|
|
|
post := posts[0]
|
|
checkPreference(t, th.App, th.BasicUser.Id, model.PreferenceCategoryFlaggedPost, post.Id, "true")
|
|
checkPreference(t, th.App, th.BasicUser2.Id, model.PreferenceCategoryFlaggedPost, post.Id, "true")
|
|
})
|
|
|
|
t.Run("Test with Type", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
th.BasicUser.Username,
|
|
th.BasicUser2.Username,
|
|
},
|
|
User: new(th.BasicUser.Username),
|
|
Type: model.NewPointer(model.PostTypeSystemGeneric),
|
|
Message: new("Message with Type"),
|
|
CreateAt: new(posttypeDate),
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 6, "")
|
|
|
|
posts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(directChannel.Id, *data.DirectPost.CreateAt)
|
|
require.NoError(t, nErr)
|
|
require.Len(t, posts, 1)
|
|
|
|
post := posts[0]
|
|
assert.Equal(t, post.Type, *data.DirectPost.Type)
|
|
assert.Equal(t, post.Message, *data.DirectPost.Message)
|
|
assert.Equal(t, post.CreateAt, *data.DirectPost.CreateAt)
|
|
assert.Equal(t, post.UserId, th.BasicUser.Id)
|
|
})
|
|
|
|
t.Run("Test with EditAt", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
th.BasicUser.Username,
|
|
th.BasicUser2.Username,
|
|
},
|
|
User: new(th.BasicUser.Username),
|
|
Message: new("Message with EditAt"),
|
|
CreateAt: new(editatCreateDate),
|
|
EditAt: new(editatEditDate),
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 7, "")
|
|
|
|
posts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(directChannel.Id, *data.DirectPost.CreateAt)
|
|
require.NoError(t, nErr)
|
|
require.Len(t, posts, 1)
|
|
|
|
post := posts[0]
|
|
assert.Equal(t, post.Message, *data.DirectPost.Message)
|
|
assert.Equal(t, post.CreateAt, *data.DirectPost.CreateAt)
|
|
assert.Equal(t, post.EditAt, *data.DirectPost.EditAt)
|
|
assert.Equal(t, post.UserId, th.BasicUser.Id)
|
|
})
|
|
|
|
t.Run("Test with IsPinned", func(t *testing.T) {
|
|
pinnedValue := true
|
|
creationTime := model.GetMillis()
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
th.BasicUser.Username,
|
|
th.BasicUser2.Username,
|
|
},
|
|
User: new(th.BasicUser.Username),
|
|
Message: new("Message with EditAt"),
|
|
CreateAt: &creationTime,
|
|
IsPinned: &pinnedValue,
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 8, "")
|
|
|
|
posts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(directChannel.Id, *data.DirectPost.CreateAt)
|
|
require.NoError(t, nErr)
|
|
require.Len(t, posts, 1)
|
|
|
|
post := posts[0]
|
|
require.True(t, post.IsPinned)
|
|
})
|
|
|
|
t.Run("Importing a direct post with a thread", func(t *testing.T) {
|
|
// Create a thread.
|
|
importCreate := time.Now().Add(-1 * time.Minute).UnixMilli()
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
th.BasicUser.Username,
|
|
th.BasicUser2.Username,
|
|
},
|
|
User: new(th.BasicUser.Username),
|
|
Message: new("Thread Message"),
|
|
CreateAt: new(importCreate),
|
|
Replies: &[]imports.ReplyImportData{{
|
|
User: new(th.BasicUser.Username),
|
|
Message: new("Reply"),
|
|
CreateAt: new(model.GetMillis()),
|
|
}},
|
|
ThreadFollowers: &[]imports.ThreadFollowerImportData{{
|
|
User: new(th.BasicUser.Username),
|
|
LastViewed: new(model.GetMillis()),
|
|
}, {
|
|
User: new(th.BasicUser2.Username),
|
|
LastViewed: new(model.GetMillis()),
|
|
}},
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
|
|
resultPosts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, importCreate)
|
|
require.NoError(t, nErr)
|
|
require.Equal(t, 1, len(resultPosts))
|
|
|
|
followers, nErr := th.App.Srv().Store().Thread().GetThreadFollowers(resultPosts[0].Id, true)
|
|
require.NoError(t, nErr)
|
|
|
|
assert.ElementsMatch(t, []string{th.BasicUser.Id, th.BasicUser2.Id}, followers)
|
|
})
|
|
|
|
t.Run("Importing a direct post with new followers", func(t *testing.T) {
|
|
importCreate := time.Now().Add(-5 * time.Minute).UnixMilli()
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
th.BasicUser.Username,
|
|
th.BasicUser2.Username,
|
|
},
|
|
User: new(th.BasicUser.Username),
|
|
Message: new("Hello"),
|
|
CreateAt: new(importCreate),
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
|
|
resultPosts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, importCreate)
|
|
require.NoError(t, nErr)
|
|
require.Equal(t, 1, len(resultPosts))
|
|
|
|
data = imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
th.BasicUser.Username,
|
|
th.BasicUser2.Username,
|
|
},
|
|
User: new(th.BasicUser.Username),
|
|
Message: new("Hello"),
|
|
CreateAt: new(importCreate),
|
|
Replies: &[]imports.ReplyImportData{{
|
|
User: new(th.BasicUser.Username),
|
|
Message: new("Reply"),
|
|
CreateAt: new(model.GetMillis()),
|
|
}},
|
|
ThreadFollowers: &[]imports.ThreadFollowerImportData{{
|
|
User: new(th.BasicUser.Username),
|
|
LastViewed: new(model.GetMillis()),
|
|
}},
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
|
|
errLine, err = th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
|
|
followers, nErr := th.App.Srv().Store().Thread().GetThreadFollowers(resultPosts[0].Id, true)
|
|
require.NoError(t, nErr)
|
|
|
|
assert.ElementsMatch(t, []string{th.BasicUser.Id}, followers)
|
|
})
|
|
|
|
// ------------------ Group Channel -------------------------
|
|
|
|
// Create the GROUP channel.
|
|
user3 := th.CreateUser(t)
|
|
channelData = imports.DirectChannelImportData{
|
|
Participants: []*imports.DirectChannelMemberImportData{
|
|
{
|
|
Username: new(th.BasicUser.Username),
|
|
},
|
|
{
|
|
Username: new(th.BasicUser2.Username),
|
|
},
|
|
{
|
|
Username: new(user3.Username),
|
|
},
|
|
},
|
|
}
|
|
appErr = th.App.importDirectChannel(th.Context, &channelData, false)
|
|
require.Nil(t, appErr)
|
|
|
|
// Get the channel.
|
|
var groupChannel *model.Channel
|
|
userIDs := []string{
|
|
th.BasicUser.Id,
|
|
th.BasicUser2.Id,
|
|
user3.Id,
|
|
}
|
|
channel, appErr = th.App.createGroupChannel(th.Context, userIDs, th.BasicUser.Id)
|
|
require.Equal(t, appErr.Id, store.ChannelExistsError)
|
|
groupChannel = channel
|
|
|
|
// Get the number of posts in the system.
|
|
require.NoError(t, th.App.Srv().Store().Post().RefreshPostStats())
|
|
result, nErr := th.App.Srv().Store().Post().AnalyticsPostCount(&model.PostCountOptions{})
|
|
require.NoError(t, nErr)
|
|
initialPostCount = result
|
|
|
|
t.Run("Try adding an invalid post in dry run mode", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
th.BasicUser.Username,
|
|
th.BasicUser2.Username,
|
|
user3.Username,
|
|
},
|
|
User: new(th.BasicUser.Username),
|
|
CreateAt: new(model.GetMillis()),
|
|
},
|
|
},
|
|
LineNumber: 4,
|
|
}
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{data}, true, true)
|
|
require.NotNil(t, err)
|
|
require.Equal(t, data.LineNumber, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 0, "")
|
|
})
|
|
|
|
t.Run("Try adding a valid post in dry run mode", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
th.BasicUser.Username,
|
|
th.BasicUser2.Username,
|
|
user3.Username,
|
|
},
|
|
User: new(th.BasicUser.Username),
|
|
Message: new("Message"),
|
|
CreateAt: new(model.GetMillis()),
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{data}, true, true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 0, "")
|
|
})
|
|
|
|
t.Run("Try adding an invalid post in apply mode", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
th.BasicUser.Username,
|
|
th.BasicUser2.Username,
|
|
user3.Username,
|
|
model.NewId(),
|
|
},
|
|
User: new(th.BasicUser.Username),
|
|
Message: new("Message"),
|
|
CreateAt: new(model.GetMillis()),
|
|
},
|
|
},
|
|
LineNumber: 8,
|
|
}
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.NotNil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 0, "")
|
|
})
|
|
|
|
t.Run("Try adding a valid post in apply mode", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
th.BasicUser.Username,
|
|
th.BasicUser2.Username,
|
|
user3.Username,
|
|
},
|
|
User: new(th.BasicUser.Username),
|
|
Message: new("Message"),
|
|
CreateAt: new(initialDate + 10),
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 1, "")
|
|
|
|
// Check the post values.
|
|
posts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(groupChannel.Id, *data.DirectPost.CreateAt)
|
|
require.NoError(t, nErr)
|
|
require.Len(t, posts, 1)
|
|
|
|
post := posts[0]
|
|
require.Equal(t, post.Message, *data.DirectPost.Message)
|
|
require.Equal(t, post.CreateAt, *data.DirectPost.CreateAt)
|
|
require.Equal(t, post.UserId, th.BasicUser.Id)
|
|
})
|
|
|
|
t.Run("Import the post again", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
th.BasicUser.Username,
|
|
th.BasicUser2.Username,
|
|
user3.Username,
|
|
},
|
|
User: new(th.BasicUser.Username),
|
|
Message: new("Message"),
|
|
CreateAt: new(initialDate + 10),
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 1, "")
|
|
|
|
// Check the post values.
|
|
posts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(groupChannel.Id, *data.DirectPost.CreateAt)
|
|
require.NoError(t, nErr)
|
|
require.Len(t, posts, 1)
|
|
|
|
post := posts[0]
|
|
require.Equal(t, post.Message, *data.DirectPost.Message)
|
|
require.Equal(t, post.CreateAt, *data.DirectPost.CreateAt)
|
|
require.Equal(t, post.UserId, th.BasicUser.Id)
|
|
})
|
|
|
|
t.Run("Save the post with a different time", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
th.BasicUser.Username,
|
|
th.BasicUser2.Username,
|
|
user3.Username,
|
|
},
|
|
User: new(th.BasicUser.Username),
|
|
Message: new("Message"),
|
|
CreateAt: new(initialDate + 11),
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 2, "")
|
|
})
|
|
|
|
t.Run("Save the post with a different message", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
th.BasicUser.Username,
|
|
th.BasicUser2.Username,
|
|
user3.Username,
|
|
},
|
|
User: new(th.BasicUser.Username),
|
|
Message: new("Message 2"),
|
|
CreateAt: new(initialDate + 11),
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 3, "")
|
|
})
|
|
|
|
t.Run("Test with hashtag", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
th.BasicUser.Username,
|
|
th.BasicUser2.Username,
|
|
user3.Username,
|
|
},
|
|
User: new(th.BasicUser.Username),
|
|
Message: new("Message 2 #hashtagmashupcity"),
|
|
CreateAt: new(initialDate + 12),
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 4, "")
|
|
|
|
posts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(groupChannel.Id, *data.DirectPost.CreateAt)
|
|
require.NoError(t, nErr)
|
|
require.Len(t, posts, 1)
|
|
|
|
post := posts[0]
|
|
require.Equal(t, post.Message, *data.DirectPost.Message)
|
|
require.Equal(t, post.CreateAt, *data.DirectPost.CreateAt)
|
|
require.Equal(t, post.UserId, th.BasicUser.Id)
|
|
require.Equal(t, post.Hashtags, "#hashtagmashupcity")
|
|
})
|
|
|
|
t.Run("Test with some flags", func(t *testing.T) {
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
th.BasicUser.Username,
|
|
th.BasicUser2.Username,
|
|
user3.Username,
|
|
},
|
|
FlaggedBy: &[]string{
|
|
th.BasicUser.Username,
|
|
th.BasicUser2.Username,
|
|
},
|
|
User: new(th.BasicUser.Username),
|
|
Message: new("Message"),
|
|
CreateAt: new(model.GetMillis()),
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 5, "")
|
|
|
|
// Check the post values.
|
|
posts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(groupChannel.Id, *data.DirectPost.CreateAt)
|
|
require.NoError(t, nErr)
|
|
require.Len(t, posts, 1)
|
|
|
|
post := posts[0]
|
|
checkPreference(t, th.App, th.BasicUser.Id, model.PreferenceCategoryFlaggedPost, post.Id, "true")
|
|
checkPreference(t, th.App, th.BasicUser2.Id, model.PreferenceCategoryFlaggedPost, post.Id, "true")
|
|
})
|
|
|
|
t.Run("Post with reaction", func(t *testing.T) {
|
|
reactionPostTime := new(initialDate + 22)
|
|
reactionTime := new(initialDate + 23)
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
th.BasicUser.Username,
|
|
th.BasicUser2.Username,
|
|
user3.Username,
|
|
},
|
|
User: new(th.BasicUser.Username),
|
|
Message: new("Message with reaction"),
|
|
CreateAt: reactionPostTime,
|
|
Reactions: &[]imports.ReactionImportData{{
|
|
User: new(th.BasicUser2.Username),
|
|
EmojiName: new("+1"),
|
|
CreateAt: reactionTime,
|
|
}},
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err, "Expected success.")
|
|
require.Equal(t, 0, errLine)
|
|
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 6, "")
|
|
|
|
// Check the post values.
|
|
posts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(groupChannel.Id, *data.DirectPost.CreateAt)
|
|
require.NoError(t, nErr)
|
|
|
|
require.Len(t, posts, 1, "Unexpected number of posts found.")
|
|
|
|
post := posts[0]
|
|
postBool := post.Message != *data.DirectPost.Message || post.CreateAt != *data.DirectPost.CreateAt || post.UserId != th.BasicUser.Id || !post.HasReactions
|
|
require.False(t, postBool, "Post properties not as expected")
|
|
|
|
reactions, nErr := th.App.Srv().Store().Reaction().GetForPost(post.Id, false)
|
|
require.NoError(t, nErr, "Can't get reaction")
|
|
|
|
require.Len(t, reactions, 1, "Invalid number of reactions")
|
|
})
|
|
|
|
t.Run("Post with reply", func(t *testing.T) {
|
|
replyPostTime := new(initialDate + 25)
|
|
replyTime := new(initialDate + 26)
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
th.BasicUser.Username,
|
|
th.BasicUser2.Username,
|
|
user3.Username,
|
|
},
|
|
User: new(th.BasicUser.Username),
|
|
Message: new("Message with reply"),
|
|
CreateAt: replyPostTime,
|
|
Replies: &[]imports.ReplyImportData{{
|
|
User: new(th.BasicUser2.Username),
|
|
Message: new("Message reply"),
|
|
CreateAt: replyTime,
|
|
}},
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err, "Expected success.")
|
|
require.Equal(t, 0, errLine)
|
|
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 8, "")
|
|
|
|
// Check the post values.
|
|
posts, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(groupChannel.Id, *data.DirectPost.CreateAt)
|
|
require.NoError(t, nErr)
|
|
|
|
require.Len(t, posts, 1, "Unexpected number of posts found.")
|
|
|
|
post := posts[0]
|
|
postBool := post.Message != *data.DirectPost.Message || post.CreateAt != *data.DirectPost.CreateAt || post.UserId != th.BasicUser.Id
|
|
require.False(t, postBool, "Post properties not as expected")
|
|
|
|
// Check the reply values.
|
|
replies, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, *replyTime)
|
|
require.NoError(t, nErr)
|
|
|
|
require.Len(t, replies, 1, "Unexpected number of posts found.")
|
|
|
|
reply := replies[0]
|
|
replyBool := reply.Message != *(*data.DirectPost.Replies)[0].Message || reply.CreateAt != *(*data.DirectPost.Replies)[0].CreateAt || reply.UserId != th.BasicUser2.Id
|
|
require.False(t, replyBool, "Post properties not as expected")
|
|
|
|
require.Equal(t, post.Id, reply.RootId, "Unexpected reply RootId")
|
|
})
|
|
|
|
t.Run("Update post with replies", func(t *testing.T) {
|
|
replyPostTime := new(initialDate + 25)
|
|
replyTime := new(initialDate + 26)
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
th.BasicUser.Username,
|
|
th.BasicUser2.Username,
|
|
user3.Username,
|
|
},
|
|
User: new(th.BasicUser2.Username),
|
|
Message: new("Message with reply"),
|
|
CreateAt: replyPostTime,
|
|
Replies: &[]imports.ReplyImportData{{
|
|
User: new(th.BasicUser.Username),
|
|
Message: new("Message reply"),
|
|
CreateAt: replyTime,
|
|
}},
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err, "Expected success.")
|
|
require.Equal(t, 0, errLine)
|
|
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 8, "")
|
|
})
|
|
|
|
t.Run("Create new post with replies based on the previous one", func(t *testing.T) {
|
|
replyPostTime := new(initialDate + 27)
|
|
replyTime := new(initialDate + 28)
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
th.BasicUser.Username,
|
|
th.BasicUser2.Username,
|
|
user3.Username,
|
|
},
|
|
User: new(th.BasicUser2.Username),
|
|
Message: new("Message with reply 2"),
|
|
CreateAt: replyPostTime,
|
|
Replies: &[]imports.ReplyImportData{{
|
|
User: new(th.BasicUser.Username),
|
|
Message: new("Message reply"),
|
|
CreateAt: replyTime,
|
|
}},
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err, "Expected success.")
|
|
require.Equal(t, 0, errLine)
|
|
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 10, "")
|
|
})
|
|
|
|
t.Run("Post with reply having non-empty type and edit_at", func(t *testing.T) {
|
|
replyPostTime := new(initialDate + 29)
|
|
replyTime := new(initialDate + 30)
|
|
replyEditTime := new(initialDate + 31)
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
th.BasicUser.Username,
|
|
th.BasicUser2.Username,
|
|
user3.Username,
|
|
},
|
|
User: new(th.BasicUser2.Username),
|
|
Message: new("Message with reply"),
|
|
CreateAt: replyPostTime,
|
|
Replies: &[]imports.ReplyImportData{{
|
|
User: new(th.BasicUser.Username),
|
|
Type: model.NewPointer(model.PostTypeSystemGeneric),
|
|
Message: new("Message reply 2"),
|
|
CreateAt: replyTime,
|
|
EditAt: replyEditTime,
|
|
}},
|
|
},
|
|
},
|
|
LineNumber: 1,
|
|
}
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err, "Expected success.")
|
|
require.Equal(t, 0, errLine)
|
|
|
|
AssertAllPostsCount(t, th.App, initialPostCount, 12, "")
|
|
|
|
// Check the reply values.
|
|
replies, nErr := th.App.Srv().Store().Post().GetPostsCreatedAt(channel.Id, *replyTime)
|
|
require.NoError(t, nErr)
|
|
|
|
require.Len(t, replies, 1, "Unexpected number of posts found.")
|
|
|
|
reply := replies[0]
|
|
importReply := (*data.DirectPost.Replies)[0]
|
|
replyBool := reply.Type != *importReply.Type || reply.Message != *importReply.Message || reply.CreateAt != *importReply.CreateAt || reply.EditAt != *importReply.EditAt || reply.UserId != th.BasicUser.Id
|
|
require.False(t, replyBool, "Post properties not as expected")
|
|
})
|
|
}
|
|
|
|
func TestImportImportBot(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
t.Run("import invalid bot in dry-run", func(t *testing.T) {
|
|
data := imports.BotImportData{
|
|
// Missing required Username
|
|
}
|
|
appErr := th.App.importBot(th.Context, &data, true)
|
|
require.NotNil(t, appErr, "Should have failed to import invalid bot.")
|
|
})
|
|
|
|
t.Run("import valid bot in dry-run", func(t *testing.T) {
|
|
data := imports.BotImportData{
|
|
Username: new(model.NewUsername()),
|
|
DisplayName: new("Test Bot"),
|
|
Description: new("A test bot"),
|
|
Owner: &th.BasicUser.Username,
|
|
}
|
|
appErr := th.App.importBot(th.Context, &data, true)
|
|
require.Nil(t, appErr, "Should have succeeded to import valid bot in dry-run.")
|
|
|
|
// Verify bot was not created in DB.
|
|
_, err := th.App.Srv().Store().Bot().GetByUsername(*data.Username)
|
|
var nfErr *store.ErrNotFound
|
|
require.ErrorAs(t, err, &nfErr, "Bot should not be found after dry run.")
|
|
})
|
|
|
|
t.Run("import valid bot in apply mode", func(t *testing.T) {
|
|
username := model.NewUsername()
|
|
data := imports.BotImportData{
|
|
Username: &username,
|
|
DisplayName: new("Test Bot"),
|
|
Description: new("A test bot"),
|
|
Owner: &th.BasicUser.Username,
|
|
}
|
|
appErr := th.App.importBot(th.Context, &data, false)
|
|
require.Nil(t, appErr, "Should have succeeded to import valid bot.")
|
|
|
|
// Verify bot was created.
|
|
bot, err := th.App.Srv().Store().Bot().GetByUsername(username)
|
|
require.NoError(t, err, "Bot should exist after import.")
|
|
assert.Equal(t, username, bot.Username)
|
|
assert.Equal(t, "Test Bot", bot.DisplayName)
|
|
assert.Equal(t, "A test bot", bot.Description)
|
|
assert.Equal(t, th.BasicUser.Id, bot.OwnerId)
|
|
})
|
|
|
|
t.Run("re-import existing bot updates it", func(t *testing.T) {
|
|
username := model.NewUsername()
|
|
data := imports.BotImportData{
|
|
Username: &username,
|
|
DisplayName: new("Original Name"),
|
|
Description: new("Original description"),
|
|
Owner: &th.BasicUser.Username,
|
|
}
|
|
appErr := th.App.importBot(th.Context, &data, false)
|
|
require.Nil(t, appErr, "First import should succeed.")
|
|
|
|
bot, err := th.App.Srv().Store().Bot().GetByUsername(username)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "Original description", bot.Description)
|
|
|
|
// Import again with updated description.
|
|
data.Description = new("Updated description")
|
|
appErr = th.App.importBot(th.Context, &data, false)
|
|
require.Nil(t, appErr, "Re-import should succeed.")
|
|
|
|
bot, err = th.App.Srv().Store().Bot().GetByUsername(username)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "Updated description", bot.Description)
|
|
})
|
|
|
|
t.Run("import bot when user already exists but bot record does not", func(t *testing.T) {
|
|
// Create a regular user first.
|
|
username := model.NewUsername()
|
|
user, err := th.App.Srv().Store().User().Save(th.Context, &model.User{
|
|
Username: username,
|
|
Email: username + "@example.com",
|
|
Roles: model.SystemUserRoleId,
|
|
})
|
|
require.NoError(t, err, "Failed to create user.")
|
|
|
|
// Now import a bot with the same username. The user exists but has no
|
|
// bot record, so Bot().GetByUsername returns not-found and CreateBot
|
|
// will fail with username-exists. The fix should recover gracefully.
|
|
data := imports.BotImportData{
|
|
Username: &username,
|
|
DisplayName: new("Bot from existing user"),
|
|
Description: new("Recovered bot"),
|
|
Owner: &th.BasicUser.Username,
|
|
}
|
|
appErr := th.App.importBot(th.Context, &data, false)
|
|
require.Nil(t, appErr, "Import should recover when user exists without bot record.")
|
|
|
|
// Verify the bot record now exists and is linked to the pre-existing user.
|
|
bot, botErr := th.App.Srv().Store().Bot().GetByUsername(username)
|
|
require.NoError(t, botErr, "Bot record should have been created.")
|
|
assert.Equal(t, user.Id, bot.UserId)
|
|
assert.Equal(t, "Recovered bot", bot.Description)
|
|
})
|
|
|
|
t.Run("re-import bot when both user and bot record already exist", func(t *testing.T) {
|
|
// Both the user and the bot record already exist (e.g. from a previous
|
|
// complete import). GetByUsername finds the bot, so bot.UserId is set
|
|
// and the code takes the "else if hasBotChanged" update branch — NOT
|
|
// the new recovery path.
|
|
username := model.NewUsername()
|
|
user, err := th.App.Srv().Store().User().Save(th.Context, &model.User{
|
|
Username: username,
|
|
Email: username + "@example.com",
|
|
Roles: model.SystemUserRoleId,
|
|
})
|
|
require.NoError(t, err, "Failed to create user.")
|
|
|
|
_, err = th.App.Srv().Store().Bot().Save(&model.Bot{
|
|
UserId: user.Id,
|
|
Username: username,
|
|
Description: "Old description",
|
|
OwnerId: th.BasicUser.Id,
|
|
})
|
|
require.NoError(t, err, "Failed to create bot record.")
|
|
|
|
data := imports.BotImportData{
|
|
Username: &username,
|
|
Description: new("New description"),
|
|
Owner: &th.BasicUser.Username,
|
|
}
|
|
appErr := th.App.importBot(th.Context, &data, false)
|
|
require.Nil(t, appErr, "Re-import of fully existing bot should succeed.")
|
|
|
|
bot, botErr := th.App.Srv().Store().Bot().GetByUsername(username)
|
|
require.NoError(t, botErr)
|
|
assert.Equal(t, user.Id, bot.UserId)
|
|
assert.Equal(t, "New description", bot.Description)
|
|
})
|
|
|
|
t.Run("import bot does not panic when CreateBot fails due to existing user", func(t *testing.T) {
|
|
// Regression test for a nil pointer dereference caused by variable
|
|
// shadowing. The original code re-declared `var appErr *model.AppError`
|
|
// inside the CreateBot error handler, shadowing the outer appErr (which
|
|
// held the real error) with a typed nil pointer. When errors.As received
|
|
// this typed nil (*model.AppError)(nil), it was a non-nil interface, so
|
|
// it did NOT early-return false — instead it called AppError.Unwrap() on
|
|
// the nil receiver, panicking with:
|
|
// panic: runtime error: invalid memory address or nil pointer dereference
|
|
username := model.NewUsername()
|
|
user, err := th.App.Srv().Store().User().Save(th.Context, &model.User{
|
|
Username: username,
|
|
Email: username + "@example.com",
|
|
Roles: model.SystemUserRoleId,
|
|
})
|
|
require.NoError(t, err, "Failed to create user.")
|
|
require.NotEmpty(t, user.Id)
|
|
|
|
data := imports.BotImportData{
|
|
Username: &username,
|
|
DisplayName: new("Regression Bot"),
|
|
Description: new("Should not crash"),
|
|
Owner: &th.BasicUser.Username,
|
|
}
|
|
|
|
// Must not panic — this is the primary regression guard.
|
|
var appErr *model.AppError
|
|
require.NotPanics(t, func() {
|
|
appErr = th.App.importBot(th.Context, &data, false)
|
|
}, "importBot must not panic when CreateBot fails due to existing user")
|
|
|
|
// Beyond not panicking, the fix should also recover successfully.
|
|
require.Nil(t, appErr, "importBot should recover when user exists without bot record.")
|
|
|
|
bot, botErr := th.App.Srv().Store().Bot().GetByUsername(username)
|
|
require.NoError(t, botErr, "Bot record should have been created during recovery.")
|
|
assert.Equal(t, user.Id, bot.UserId, "Bot should be linked to the pre-existing user.")
|
|
assert.Equal(t, "Regression Bot", bot.DisplayName)
|
|
assert.Equal(t, "Should not crash", bot.Description)
|
|
})
|
|
|
|
t.Run("re-import with identical data is idempotent", func(t *testing.T) {
|
|
username := model.NewUsername()
|
|
data := imports.BotImportData{
|
|
Username: &username,
|
|
DisplayName: new("Idempotent Bot"),
|
|
Description: new("Same description"),
|
|
Owner: &th.BasicUser.Username,
|
|
}
|
|
appErr := th.App.importBot(th.Context, &data, false)
|
|
require.Nil(t, appErr, "First import should succeed.")
|
|
|
|
bot, err := th.App.Srv().Store().Bot().GetByUsername(username)
|
|
require.NoError(t, err)
|
|
originalUpdateAt := bot.UpdateAt
|
|
|
|
// Re-import with exactly the same data. hasBotChanged should remain
|
|
// false, so no database write occurs and the bot is unchanged.
|
|
// Sleep briefly so that any real update would produce a different
|
|
// UpdateAt timestamp (millisecond resolution).
|
|
time.Sleep(2 * time.Millisecond)
|
|
appErr = th.App.importBot(th.Context, &data, false)
|
|
require.Nil(t, appErr, "Idempotent re-import should succeed.")
|
|
|
|
bot, err = th.App.Srv().Store().Bot().GetByUsername(username)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "Idempotent Bot", bot.DisplayName)
|
|
assert.Equal(t, "Same description", bot.Description)
|
|
assert.Equal(t, originalUpdateAt, bot.UpdateAt, "UpdateAt should not change when import data is identical.")
|
|
})
|
|
|
|
t.Run("re-import with only DisplayName changed updates bot", func(t *testing.T) {
|
|
username := model.NewUsername()
|
|
data := imports.BotImportData{
|
|
Username: &username,
|
|
DisplayName: new("Original DisplayName"),
|
|
Description: new("Unchanged description"),
|
|
Owner: &th.BasicUser.Username,
|
|
}
|
|
appErr := th.App.importBot(th.Context, &data, false)
|
|
require.Nil(t, appErr, "First import should succeed.")
|
|
|
|
bot, err := th.App.Srv().Store().Bot().GetByUsername(username)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "Original DisplayName", bot.DisplayName)
|
|
|
|
// Re-import changing only the DisplayName.
|
|
data.DisplayName = new("Updated DisplayName")
|
|
appErr = th.App.importBot(th.Context, &data, false)
|
|
require.Nil(t, appErr, "Re-import with changed DisplayName should succeed.")
|
|
|
|
bot, err = th.App.Srv().Store().Bot().GetByUsername(username)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "Updated DisplayName", bot.DisplayName)
|
|
assert.Equal(t, "Unchanged description", bot.Description, "Description should remain unchanged.")
|
|
})
|
|
|
|
t.Run("import bot returns error when CreateBot fails for non-username reason", func(t *testing.T) {
|
|
// Trigger a non-username CreateBot failure by pre-creating a user whose
|
|
// email collides with the email CreateBot would generate (username@localhost).
|
|
// This causes User().Save() inside CreateBot to fail with
|
|
// ErrInvalidInput{Field: "email"}, which importBot must return directly
|
|
// instead of entering the username-conflict recovery path.
|
|
botUsername := model.NewUsername()
|
|
collidingEmail := model.NormalizeEmail(botUsername + "@localhost")
|
|
_, err := th.App.Srv().Store().User().Save(th.Context, &model.User{
|
|
Username: model.NewUsername(), // different username — no username conflict
|
|
Email: collidingEmail, // same email CreateBot would use
|
|
Roles: model.SystemUserRoleId,
|
|
})
|
|
require.NoError(t, err, "Failed to create user with colliding email.")
|
|
|
|
data := imports.BotImportData{
|
|
Username: &botUsername,
|
|
DisplayName: new("Email Conflict Bot"),
|
|
Description: new("Should fail"),
|
|
Owner: &th.BasicUser.Username,
|
|
}
|
|
appErr := th.App.importBot(th.Context, &data, false)
|
|
require.NotNil(t, appErr, "Import should fail when CreateBot hits a non-username error.")
|
|
assert.Contains(t, appErr.Id, "email_exists", "Error should indicate email conflict, not username conflict.")
|
|
})
|
|
|
|
t.Run("import bot with owner that does not exist uses owner as plugin id", func(t *testing.T) {
|
|
username := model.NewUsername()
|
|
pluginOwner := "com.example.plugin"
|
|
data := imports.BotImportData{
|
|
Username: &username,
|
|
DisplayName: new("Plugin Bot"),
|
|
Description: new("Bot owned by plugin"),
|
|
Owner: &pluginOwner,
|
|
}
|
|
appErr := th.App.importBot(th.Context, &data, false)
|
|
require.Nil(t, appErr, "Import should succeed with non-existent owner (treated as plugin).")
|
|
|
|
bot, err := th.App.Srv().Store().Bot().GetByUsername(username)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, pluginOwner, bot.OwnerId, "Owner should be the raw plugin identifier.")
|
|
})
|
|
}
|
|
|
|
func TestImportImportEmoji(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCustomEmoji = true })
|
|
|
|
testsDir, _ := fileutils.FindDir("tests")
|
|
testImage := filepath.Join(testsDir, "test.png")
|
|
|
|
data := imports.EmojiImportData{Name: new(model.NewId())}
|
|
appErr := th.App.importEmoji(th.Context, &data, true)
|
|
assert.NotNil(t, appErr, "Invalid emoji should have failed dry run")
|
|
|
|
emoji, nErr := th.App.Srv().Store().Emoji().GetByName(th.Context, *data.Name, true)
|
|
assert.Nil(t, emoji, "Emoji should not have been imported")
|
|
assert.Error(t, nErr)
|
|
|
|
data.Image = new(testImage)
|
|
appErr = th.App.importEmoji(th.Context, &data, true)
|
|
assert.Nil(t, appErr, "Valid emoji should have passed dry run")
|
|
|
|
data = imports.EmojiImportData{Name: new(model.NewId())}
|
|
appErr = th.App.importEmoji(th.Context, &data, false)
|
|
assert.NotNil(t, appErr, "Invalid emoji should have failed apply mode")
|
|
|
|
data.Image = new("non-existent-file")
|
|
appErr = th.App.importEmoji(th.Context, &data, false)
|
|
assert.NotNil(t, appErr, "Emoji with bad image file should have failed apply mode")
|
|
|
|
data.Image = new(testImage)
|
|
appErr = th.App.importEmoji(th.Context, &data, false)
|
|
assert.Nil(t, appErr, "Valid emoji should have succeeded apply mode")
|
|
|
|
emoji, nErr = th.App.Srv().Store().Emoji().GetByName(th.Context, *data.Name, true)
|
|
assert.NotNil(t, emoji, "Emoji should have been imported")
|
|
assert.NoError(t, nErr, "Emoji should have been imported without any error")
|
|
|
|
appErr = th.App.importEmoji(th.Context, &data, false)
|
|
assert.Nil(t, appErr, "Second run should have succeeded apply mode")
|
|
|
|
data = imports.EmojiImportData{Name: new("smiley"), Image: new(testImage)}
|
|
appErr = th.App.importEmoji(th.Context, &data, false)
|
|
assert.Nil(t, appErr, "System emoji should not fail")
|
|
|
|
largeImage := filepath.Join(testsDir, "large_image_file.jpg")
|
|
data = imports.EmojiImportData{Name: new(model.NewId()), Image: new(largeImage)}
|
|
appErr = th.App.importEmoji(th.Context, &data, false)
|
|
require.NotNil(t, appErr)
|
|
require.ErrorIs(t, appErr.Unwrap(), utils.ErrSizeLimitExceeded)
|
|
}
|
|
|
|
func TestImportAttachment(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
testsDir, _ := fileutils.FindDir("tests")
|
|
testImage := filepath.Join(testsDir, "test.png")
|
|
invalidPath := "some-invalid-path"
|
|
|
|
userID := model.NewId()
|
|
data := imports.AttachmentImportData{Path: &testImage}
|
|
_, err := th.App.importAttachment(th.Context, &data, &model.Post{UserId: userID, ChannelId: "some-channel"}, "some-team", true)
|
|
assert.Nil(t, err, "sample run without errors")
|
|
|
|
attachments := GetAttachments(userID, th, t)
|
|
assert.Len(t, attachments, 1)
|
|
|
|
data = imports.AttachmentImportData{Path: &invalidPath}
|
|
_, err = th.App.importAttachment(th.Context, &data, &model.Post{UserId: model.NewId(), ChannelId: "some-channel"}, "some-team", true)
|
|
assert.NotNil(t, err, "should have failed when opening the file")
|
|
assert.Equal(t, err.Id, "app.import.attachment.bad_file.error")
|
|
}
|
|
|
|
func TestImportPostAndRepliesWithAttachments(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
// Create a Team.
|
|
teamName := model.NewRandomTeamName()
|
|
appErr := th.App.importTeam(th.Context, &imports.TeamImportData{
|
|
Name: &teamName,
|
|
DisplayName: new("Display Name"),
|
|
Type: new("O"),
|
|
}, false)
|
|
require.Nil(t, appErr, "Failed to import team.")
|
|
team, appErr := th.App.GetTeamByName(teamName)
|
|
require.Nil(t, appErr, "Failed to get team from database.")
|
|
|
|
// Create a Channel.
|
|
channelName := NewTestId()
|
|
chanTypeOpen := model.ChannelTypeOpen
|
|
appErr = th.App.importChannel(th.Context, &imports.ChannelImportData{
|
|
Team: &teamName,
|
|
Name: &channelName,
|
|
DisplayName: new("Display Name"),
|
|
Type: &chanTypeOpen,
|
|
}, false)
|
|
require.Nil(t, appErr, "Failed to import channel.")
|
|
_, appErr = th.App.GetChannelByName(th.Context, channelName, team.Id, false)
|
|
require.Nil(t, appErr, "Failed to get channel from database.")
|
|
|
|
// Create a user3.
|
|
username := model.NewUsername()
|
|
appErr = th.App.importUser(th.Context, &imports.UserImportData{
|
|
Username: &username,
|
|
Email: new(model.NewId() + "@example.com"),
|
|
}, false)
|
|
require.Nil(t, appErr, "Failed to import user.")
|
|
user3, appErr := th.App.GetUserByUsername(username)
|
|
require.Nil(t, appErr, "Failed to get user3 from database.")
|
|
require.NotNil(t, user3)
|
|
|
|
username2 := model.NewUsername()
|
|
appErr = th.App.importUser(th.Context, &imports.UserImportData{
|
|
Username: &username2,
|
|
Email: new(model.NewId() + "@example.com"),
|
|
}, false)
|
|
require.Nil(t, appErr, "Failed to import user2.")
|
|
user2, appErr := th.App.GetUserByUsername(username2)
|
|
require.Nil(t, appErr, "Failed to get user2 from database.")
|
|
|
|
// Create direct post users.
|
|
username3 := model.NewUsername()
|
|
appErr = th.App.importUser(th.Context, &imports.UserImportData{
|
|
Username: &username3,
|
|
Email: new(model.NewId() + "@example.com"),
|
|
}, false)
|
|
require.Nil(t, appErr, "Failed to import user3.")
|
|
user3, appErr = th.App.GetUserByUsername(username3)
|
|
require.Nil(t, appErr, "Failed to get user3 from database.")
|
|
|
|
username4 := model.NewUsername()
|
|
appErr = th.App.importUser(th.Context, &imports.UserImportData{
|
|
Username: &username4,
|
|
Email: new(model.NewId() + "@example.com"),
|
|
}, false)
|
|
require.Nil(t, appErr, "Failed to import user4.")
|
|
|
|
user4, appErr := th.App.GetUserByUsername(username4)
|
|
require.Nil(t, appErr, "Failed to get user4 from database.")
|
|
|
|
// Post with attachments
|
|
time := model.GetMillis()
|
|
attachmentsPostTime := time
|
|
attachmentsReplyTime := time + 1
|
|
testsDir, _ := fileutils.FindDir("tests")
|
|
testImage := filepath.Join(testsDir, "test.png")
|
|
testMarkDown := filepath.Join(testsDir, "test-attachments.md")
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &username3,
|
|
Message: new("Message with reply"),
|
|
CreateAt: &attachmentsPostTime,
|
|
Attachments: &[]imports.AttachmentImportData{{Path: &testImage}, {Path: &testMarkDown}},
|
|
Replies: &[]imports.ReplyImportData{{
|
|
User: &user4.Username,
|
|
Message: new("Message reply"),
|
|
CreateAt: &attachmentsReplyTime,
|
|
Attachments: &[]imports.AttachmentImportData{{Path: &testImage}},
|
|
}},
|
|
},
|
|
},
|
|
LineNumber: 19,
|
|
}
|
|
|
|
t.Run("import with attachment", func(t *testing.T) {
|
|
errLine, err := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
|
|
attachments := GetAttachments(user3.Id, th, t)
|
|
require.Len(t, attachments, 2)
|
|
assert.Contains(t, attachments[0].Path, team.Id)
|
|
assert.Contains(t, attachments[1].Path, team.Id)
|
|
AssertFileIdsInPost(attachments, th, t)
|
|
|
|
attachments = GetAttachments(user4.Id, th, t)
|
|
require.Len(t, attachments, 1)
|
|
assert.Contains(t, attachments[0].Path, team.Id)
|
|
AssertFileIdsInPost(attachments, th, t)
|
|
})
|
|
|
|
t.Run("import existing post with new attachment", func(t *testing.T) {
|
|
data.Post.Attachments = &[]imports.AttachmentImportData{{Path: &testImage}}
|
|
errLine, err := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
|
|
attachments := GetAttachments(user3.Id, th, t)
|
|
require.Len(t, attachments, 1)
|
|
assert.Contains(t, attachments[0].Path, team.Id)
|
|
AssertFileIdsInPost(attachments, th, t)
|
|
|
|
attachments = GetAttachments(user4.Id, th, t)
|
|
require.Len(t, attachments, 1)
|
|
assert.Contains(t, attachments[0].Path, team.Id)
|
|
AssertFileIdsInPost(attachments, th, t)
|
|
})
|
|
|
|
t.Run("Reply with Attachments in Direct Post", func(t *testing.T) {
|
|
directImportData := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
user3.Username,
|
|
user2.Username,
|
|
},
|
|
User: &user3.Username,
|
|
Message: new("Message with Replies"),
|
|
CreateAt: new(model.GetMillis()),
|
|
Replies: &[]imports.ReplyImportData{{
|
|
User: &user2.Username,
|
|
Message: new("Message reply with attachment"),
|
|
CreateAt: new(model.GetMillis()),
|
|
Attachments: &[]imports.AttachmentImportData{{Path: &testImage}},
|
|
}},
|
|
},
|
|
},
|
|
LineNumber: 7,
|
|
}
|
|
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{directImportData}, false, true)
|
|
require.Nil(t, err, "Expected success.")
|
|
require.Equal(t, 0, errLine)
|
|
|
|
attachments := GetAttachments(user2.Id, th, t)
|
|
require.Len(t, attachments, 1)
|
|
assert.Contains(t, attachments[0].Path, "noteam")
|
|
AssertFileIdsInPost(attachments, th, t)
|
|
})
|
|
|
|
t.Run("import existing post with different attachment's content", func(t *testing.T) {
|
|
tmpDir := os.TempDir()
|
|
filePath := filepath.Join(tmpDir, "test_diff.png")
|
|
|
|
t.Run("different size", func(t *testing.T) {
|
|
testImage := filepath.Join(testsDir, "test.png")
|
|
imageData, err := os.ReadFile(testImage)
|
|
require.NoError(t, err)
|
|
err = os.WriteFile(filePath, imageData, 0644)
|
|
require.NoError(t, err)
|
|
|
|
data.Post.Attachments = &[]imports.AttachmentImportData{{Path: &filePath}}
|
|
data.Post.Replies = nil
|
|
data.Post.Message = new("new post")
|
|
errLine, appErr := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, appErr)
|
|
require.Equal(t, 0, errLine)
|
|
|
|
attachments := GetAttachments(user3.Id, th, t)
|
|
require.Len(t, attachments, 2)
|
|
assert.Contains(t, attachments[1].Path, team.Id)
|
|
AssertFileIdsInPost(attachments[1:], th, t)
|
|
|
|
testImage = filepath.Join(testsDir, "test-data-graph.png")
|
|
imageData, err = os.ReadFile(testImage)
|
|
require.NoError(t, err)
|
|
err = os.WriteFile(filePath, imageData, 0644)
|
|
require.NoError(t, err)
|
|
|
|
data.Post.Attachments = &[]imports.AttachmentImportData{{Path: &filePath}}
|
|
data.Post.Replies = nil
|
|
errLine, appErr = th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, appErr)
|
|
require.Equal(t, 0, errLine)
|
|
|
|
attachments2 := GetAttachments(user3.Id, th, t)
|
|
require.NotEqual(t, attachments, attachments2)
|
|
require.Len(t, attachments2, 2)
|
|
assert.Contains(t, attachments2[1].Path, team.Id)
|
|
AssertFileIdsInPost(attachments2[1:], th, t)
|
|
})
|
|
|
|
t.Run("same size", func(t *testing.T) {
|
|
imageData, err := os.ReadFile(filepath.Join(testsDir, "test_img_diff_A.png"))
|
|
require.NoError(t, err)
|
|
err = os.WriteFile(filePath, imageData, 0644)
|
|
require.NoError(t, err)
|
|
|
|
data.Post.Attachments = &[]imports.AttachmentImportData{{Path: &filePath}}
|
|
data.Post.Replies = nil
|
|
data.Post.Message = new("new post2")
|
|
errLine, appErr := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, appErr)
|
|
require.Equal(t, 0, errLine)
|
|
|
|
attachments := GetAttachments(user3.Id, th, t)
|
|
require.Len(t, attachments, 3)
|
|
assert.Contains(t, attachments[2].Path, team.Id)
|
|
AssertFileIdsInPost(attachments[2:], th, t)
|
|
|
|
imageData, err = os.ReadFile(filepath.Join(testsDir, "test_img_diff_B.png"))
|
|
require.NoError(t, err)
|
|
err = os.WriteFile(filePath, imageData, 0644)
|
|
require.NoError(t, err)
|
|
|
|
data.Post.Attachments = &[]imports.AttachmentImportData{{Path: &filePath}}
|
|
data.Post.Replies = nil
|
|
errLine, appErr = th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, appErr)
|
|
require.Equal(t, 0, errLine)
|
|
|
|
attachments2 := GetAttachments(user3.Id, th, t)
|
|
require.NotEqual(t, attachments, attachments2)
|
|
require.Len(t, attachments2, 3)
|
|
assert.Contains(t, attachments2[2].Path, team.Id)
|
|
AssertFileIdsInPost(attachments2[2:], th, t)
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestImportDirectPostWithAttachments(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
testsDir, _ := fileutils.FindDir("tests")
|
|
testImage := filepath.Join(testsDir, "test.png")
|
|
testImage2 := filepath.Join(testsDir, "test.svg")
|
|
// create a temp file with same name as original but with a different first byte
|
|
tmpFolder, err := os.MkdirTemp("", "imgFake")
|
|
require.NoError(t, err)
|
|
testImageFake := filepath.Join(tmpFolder, "test.png")
|
|
fakeFileData, err := os.ReadFile(testImage)
|
|
require.NoError(t, err)
|
|
fakeFileData[0] = 0
|
|
err = os.WriteFile(testImageFake, fakeFileData, 0644)
|
|
require.NoError(t, err)
|
|
defer func() {
|
|
err := os.RemoveAll(tmpFolder)
|
|
require.NoError(t, err)
|
|
}()
|
|
|
|
// Create a user.
|
|
username := model.NewUsername()
|
|
appErr := th.App.importUser(th.Context, &imports.UserImportData{
|
|
Username: &username,
|
|
Email: new(model.NewId() + "@example.com"),
|
|
}, false)
|
|
require.Nil(t, appErr, "Failed to import user.")
|
|
user1, appErr := th.App.GetUserByUsername(username)
|
|
require.Nil(t, appErr, "Failed to get user1 from database.")
|
|
|
|
username2 := model.NewUsername()
|
|
appErr = th.App.importUser(th.Context, &imports.UserImportData{
|
|
Username: &username2,
|
|
Email: new(model.NewId() + "@example.com"),
|
|
}, false)
|
|
require.Nil(t, appErr, "Failed to import user2.")
|
|
user2, appErr := th.App.GetUserByUsername(username2)
|
|
require.Nil(t, appErr, "Failed to get user2 from database.")
|
|
|
|
directImportData := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
user1.Username,
|
|
user2.Username,
|
|
},
|
|
User: &user1.Username,
|
|
Message: new("Direct message"),
|
|
CreateAt: new(model.GetMillis()),
|
|
Attachments: &[]imports.AttachmentImportData{{Path: &testImage}},
|
|
},
|
|
},
|
|
LineNumber: 3,
|
|
}
|
|
|
|
t.Run("Regular import of attachment", func(t *testing.T) {
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{directImportData}, false, true)
|
|
require.Nil(t, err, "Expected success.")
|
|
require.Equal(t, 0, errLine)
|
|
|
|
attachments := GetAttachments(user1.Id, th, t)
|
|
require.Len(t, attachments, 1)
|
|
assert.Contains(t, attachments[0].Path, "noteam")
|
|
AssertFileIdsInPost(attachments, th, t)
|
|
})
|
|
|
|
t.Run("Attempt to import again with same file entirely, should NOT add an attachment", func(t *testing.T) {
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{directImportData}, false, true)
|
|
require.Nil(t, err, "Expected success.")
|
|
require.Equal(t, 0, errLine)
|
|
|
|
attachments := GetAttachments(user1.Id, th, t)
|
|
require.Len(t, attachments, 1)
|
|
})
|
|
|
|
t.Run("Attempt to import again with same name and size but different content, SHOULD add an attachment", func(t *testing.T) {
|
|
directImportDataFake := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
user1.Username,
|
|
user2.Username,
|
|
},
|
|
User: &user1.Username,
|
|
Message: new("Direct message"),
|
|
CreateAt: new(model.GetMillis()),
|
|
Attachments: &[]imports.AttachmentImportData{{Path: &testImageFake}},
|
|
},
|
|
},
|
|
LineNumber: 2,
|
|
}
|
|
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{directImportDataFake}, false, true)
|
|
require.Nil(t, err, "Expected success.")
|
|
require.Equal(t, 0, errLine)
|
|
|
|
attachments := GetAttachments(user1.Id, th, t)
|
|
require.Len(t, attachments, 2)
|
|
})
|
|
|
|
t.Run("Attempt to import again with same data, SHOULD add an attachment, since it's different name", func(t *testing.T) {
|
|
directImportData2 := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
user1.Username,
|
|
user2.Username,
|
|
},
|
|
User: &user1.Username,
|
|
Message: new("Direct message"),
|
|
CreateAt: new(model.GetMillis()),
|
|
Attachments: &[]imports.AttachmentImportData{{Path: &testImage2}},
|
|
},
|
|
},
|
|
LineNumber: 2,
|
|
}
|
|
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{directImportData2}, false, true)
|
|
require.Nil(t, err, "Expected success.")
|
|
require.Equal(t, 0, errLine)
|
|
|
|
attachments := GetAttachments(user1.Id, th, t)
|
|
require.Len(t, attachments, 3)
|
|
})
|
|
}
|
|
|
|
func TestZippedImportPostAndRepliesWithAttachments(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
// Create a Team.
|
|
teamName := model.NewRandomTeamName()
|
|
appErr := th.App.importTeam(th.Context, &imports.TeamImportData{
|
|
Name: &teamName,
|
|
DisplayName: new("Display Name"),
|
|
Type: new("O"),
|
|
}, false)
|
|
require.Nil(t, appErr, "Failed to import team.")
|
|
team, appErr := th.App.GetTeamByName(teamName)
|
|
require.Nil(t, appErr, "Failed to get team from database.")
|
|
|
|
// Create a Channel.
|
|
channelName := NewTestId()
|
|
chanTypeOpen := model.ChannelTypeOpen
|
|
appErr = th.App.importChannel(th.Context, &imports.ChannelImportData{
|
|
Team: &teamName,
|
|
Name: &channelName,
|
|
DisplayName: new("Display Name"),
|
|
Type: &chanTypeOpen,
|
|
}, false)
|
|
require.Nil(t, appErr, "Failed to import channel.")
|
|
_, appErr = th.App.GetChannelByName(th.Context, channelName, team.Id, false)
|
|
require.Nil(t, appErr, "Failed to get channel from database.")
|
|
|
|
// Create users
|
|
username2 := model.NewUsername()
|
|
appErr = th.App.importUser(th.Context, &imports.UserImportData{
|
|
Username: &username2,
|
|
Email: new(model.NewId() + "@example.com"),
|
|
}, false)
|
|
require.Nil(t, appErr, "Failed to import user2.")
|
|
user2, appErr := th.App.GetUserByUsername(username2)
|
|
require.Nil(t, appErr, "Failed to get user2 from database.")
|
|
|
|
// Create direct post users.
|
|
username3 := model.NewUsername()
|
|
appErr = th.App.importUser(th.Context, &imports.UserImportData{
|
|
Username: &username3,
|
|
Email: new(model.NewId() + "@example.com"),
|
|
}, false)
|
|
require.Nil(t, appErr, "Failed to import user3.")
|
|
user3, appErr := th.App.GetUserByUsername(username3)
|
|
require.Nil(t, appErr, "Failed to get user3 from database.")
|
|
|
|
username4 := model.NewUsername()
|
|
appErr = th.App.importUser(th.Context, &imports.UserImportData{
|
|
Username: &username4,
|
|
Email: new(model.NewId() + "@example.com"),
|
|
}, false)
|
|
require.Nil(t, appErr, "Failed to import user4.")
|
|
|
|
user4, appErr := th.App.GetUserByUsername(username4)
|
|
require.Nil(t, appErr, "Failed to get user4 from database.")
|
|
|
|
// Post with attachments
|
|
time := model.GetMillis()
|
|
attachmentsPostTime := time
|
|
attachmentsReplyTime := time + 1
|
|
testsDir, _ := fileutils.FindDir("tests")
|
|
testImage := filepath.Join(testsDir, "test.png")
|
|
testZipFileName := filepath.Join(testsDir, "import_test.zip")
|
|
testZip, err := os.Open(testZipFileName)
|
|
require.NoError(t, err, "failed to open test zip")
|
|
|
|
fi, err := testZip.Stat()
|
|
require.NoError(t, err, "failed to get file info")
|
|
testZipReader, err := zip.NewReader(testZip, fi.Size())
|
|
require.NoError(t, err, "failed to read test zip")
|
|
|
|
require.NotEmpty(t, testZipReader.File)
|
|
imageData := testZipReader.File[0]
|
|
|
|
testMarkDown := filepath.Join(testsDir, "test-attachments.md")
|
|
data := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
Post: &imports.PostImportData{
|
|
Team: &teamName,
|
|
Channel: &channelName,
|
|
User: &username3,
|
|
Message: new("Message with reply"),
|
|
CreateAt: &attachmentsPostTime,
|
|
Attachments: &[]imports.AttachmentImportData{{Path: &testImage}, {Path: &testMarkDown}},
|
|
Replies: &[]imports.ReplyImportData{{
|
|
User: &user4.Username,
|
|
Message: new("Message reply"),
|
|
CreateAt: &attachmentsReplyTime,
|
|
Attachments: &[]imports.AttachmentImportData{{Path: &testImage, Data: imageData}},
|
|
}},
|
|
},
|
|
},
|
|
LineNumber: 19,
|
|
}
|
|
|
|
t.Run("import with attachment", func(t *testing.T) {
|
|
errLine, err := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
|
|
attachments := GetAttachments(user3.Id, th, t)
|
|
require.Len(t, attachments, 2)
|
|
assert.Contains(t, attachments[0].Path, team.Id)
|
|
assert.Contains(t, attachments[1].Path, team.Id)
|
|
AssertFileIdsInPost(attachments, th, t)
|
|
|
|
attachments = GetAttachments(user4.Id, th, t)
|
|
require.Len(t, attachments, 1)
|
|
assert.Contains(t, attachments[0].Path, team.Id)
|
|
AssertFileIdsInPost(attachments, th, t)
|
|
})
|
|
|
|
t.Run("import existing post with new attachment", func(t *testing.T) {
|
|
data.Post.Attachments = &[]imports.AttachmentImportData{{Path: &testImage}}
|
|
errLine, err := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
|
|
attachments := GetAttachments(user3.Id, th, t)
|
|
require.Len(t, attachments, 1)
|
|
assert.Contains(t, attachments[0].Path, team.Id)
|
|
AssertFileIdsInPost(attachments, th, t)
|
|
|
|
attachments = GetAttachments(user4.Id, th, t)
|
|
require.Len(t, attachments, 1)
|
|
assert.Contains(t, attachments[0].Path, team.Id)
|
|
AssertFileIdsInPost(attachments, th, t)
|
|
})
|
|
|
|
t.Run("Reply with Attachments in Direct Post", func(t *testing.T) {
|
|
directImportData := imports.LineImportWorkerData{
|
|
LineImportData: imports.LineImportData{
|
|
DirectPost: &imports.DirectPostImportData{
|
|
ChannelMembers: &[]string{
|
|
user3.Username,
|
|
user2.Username,
|
|
},
|
|
User: &user3.Username,
|
|
Message: new("Message with Replies"),
|
|
CreateAt: new(model.GetMillis()),
|
|
Replies: &[]imports.ReplyImportData{{
|
|
User: &user2.Username,
|
|
Message: new("Message reply with attachment"),
|
|
CreateAt: new(model.GetMillis()),
|
|
Attachments: &[]imports.AttachmentImportData{{Path: &testImage}},
|
|
}},
|
|
},
|
|
},
|
|
LineNumber: 7,
|
|
}
|
|
|
|
errLine, err := th.App.importMultipleDirectPostLines(th.Context, []imports.LineImportWorkerData{directImportData}, false, true)
|
|
require.Nil(t, err, "Expected success.")
|
|
require.Equal(t, 0, errLine)
|
|
|
|
attachments := GetAttachments(user2.Id, th, t)
|
|
require.Len(t, attachments, 1)
|
|
assert.Contains(t, attachments[0].Path, "noteam")
|
|
AssertFileIdsInPost(attachments, th, t)
|
|
})
|
|
|
|
t.Run("import existing post with different attachment's content", func(t *testing.T) {
|
|
var fileA, fileB *zip.File
|
|
for _, f := range testZipReader.File {
|
|
if f.Name == "data/test_img_diff_A.png" {
|
|
fileA = f
|
|
} else if f.Name == "data/test_img_diff_B.png" {
|
|
fileB = f
|
|
}
|
|
}
|
|
|
|
require.NotNil(t, fileA)
|
|
require.NotNil(t, fileB)
|
|
|
|
data.Post.Attachments = &[]imports.AttachmentImportData{{Path: &fileA.Name, Data: fileA}}
|
|
data.Post.Message = new("new post")
|
|
data.Post.Replies = nil
|
|
errLine, err := th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
|
|
attachments := GetAttachments(user3.Id, th, t)
|
|
require.Len(t, attachments, 2)
|
|
assert.Contains(t, attachments[1].Path, team.Id)
|
|
AssertFileIdsInPost(attachments[1:], th, t)
|
|
|
|
fileB.Name = fileA.Name
|
|
data.Post.Attachments = &[]imports.AttachmentImportData{{Path: &fileA.Name, Data: fileB}}
|
|
errLine, err = th.App.importMultiplePostLines(th.Context, []imports.LineImportWorkerData{data}, false, true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 0, errLine)
|
|
|
|
attachments = GetAttachments(user3.Id, th, t)
|
|
require.Len(t, attachments, 2)
|
|
assert.Contains(t, attachments[1].Path, team.Id)
|
|
AssertFileIdsInPost(attachments[1:], th, t)
|
|
})
|
|
}
|
|
|
|
func TestCompareFilesContent(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
t.Run("empty", func(t *testing.T) {
|
|
ok, err := compareFilesContent(strings.NewReader(""), strings.NewReader(""), 0)
|
|
require.NoError(t, err)
|
|
require.True(t, ok)
|
|
})
|
|
|
|
t.Run("no match", func(t *testing.T) {
|
|
ok, err := compareFilesContent(strings.NewReader("fileA"), strings.NewReader("fileB"), 0)
|
|
require.NoError(t, err)
|
|
require.False(t, ok)
|
|
})
|
|
|
|
t.Run("match", func(t *testing.T) {
|
|
ok, err := compareFilesContent(strings.NewReader("fileA"), strings.NewReader("fileA"), 0)
|
|
require.NoError(t, err)
|
|
require.True(t, ok)
|
|
})
|
|
}
|
|
|
|
func BenchmarkCompareFilesContent(b *testing.B) {
|
|
tmpDir := os.TempDir()
|
|
fileAPath := filepath.Join(tmpDir, "fileA")
|
|
fileBPath := filepath.Join(tmpDir, "fileB")
|
|
|
|
fileA, err := os.Create(fileAPath)
|
|
require.NoError(b, err)
|
|
defer func() {
|
|
err = fileA.Close()
|
|
require.NoError(b, err)
|
|
|
|
err = os.Remove(fileAPath)
|
|
require.NoError(b, err)
|
|
}()
|
|
|
|
fileB, err := os.Create(fileBPath)
|
|
require.NoError(b, err)
|
|
defer func() {
|
|
err = fileB.Close()
|
|
require.NoError(b, err)
|
|
|
|
err = os.Remove(fileBPath)
|
|
require.NoError(b, err)
|
|
}()
|
|
|
|
fileSize := int64(1024 * 1024 * 1024) // 1GB
|
|
|
|
err = fileA.Truncate(fileSize)
|
|
require.NoError(b, err)
|
|
err = fileB.Truncate(fileSize)
|
|
require.NoError(b, err)
|
|
|
|
bufSizesMap := map[string]int64{
|
|
"32KB": 1024 * 32, // current default of io.Copy
|
|
"128KB": 1024 * 128,
|
|
"1MB": 1024 * 1024,
|
|
"2MB": 1024 * 1024 * 2,
|
|
"4MB": 1024 * 1024 * 4,
|
|
"8MB": 1024 * 1024 * 8,
|
|
}
|
|
|
|
fileSizesMap := map[string]int64{
|
|
"512KB": 1024 * 512,
|
|
"1MB": 1024 * 1024,
|
|
"10MB": 1024 * 1024 * 10,
|
|
"100MB": 1024 * 1024 * 100,
|
|
"1GB": 1024 * 1024 * 1000,
|
|
}
|
|
|
|
// To force order
|
|
bufSizeLabels := []string{"32KB", "128KB", "1MB", "2MB", "4MB", "8MB"}
|
|
fileSizeLabels := []string{"512KB", "1MB", "10MB", "100MB", "1GB"}
|
|
|
|
b.Run("plain", func(b *testing.B) {
|
|
b.Run("local", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
|
|
for b.Loop() {
|
|
b.StopTimer()
|
|
_, err := fileA.Seek(0, io.SeekStart)
|
|
require.NoError(b, err)
|
|
_, err = fileB.Seek(0, io.SeekStart)
|
|
require.NoError(b, err)
|
|
|
|
b.StartTimer()
|
|
ok, err := compareFilesContent(fileA, fileB, 0)
|
|
require.NoError(b, err)
|
|
require.True(b, ok)
|
|
}
|
|
})
|
|
|
|
b.Run("s3", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
|
|
th := SetupConfig(b, func(cfg *model.Config) {
|
|
cfg.FileSettings = model.FileSettings{
|
|
DriverName: model.NewPointer(model.ImageDriverS3),
|
|
AmazonS3AccessKeyId: model.NewPointer(model.MinioAccessKey),
|
|
AmazonS3SecretAccessKey: model.NewPointer(model.MinioSecretKey),
|
|
AmazonS3Bucket: new("comparefilescontentbucket"),
|
|
AmazonS3Endpoint: new("localhost:9000"),
|
|
AmazonS3Region: new(""),
|
|
AmazonS3PathPrefix: new(""),
|
|
AmazonS3SSL: new(false),
|
|
AmazonS3RequestTimeoutMilliseconds: new(int64(300 * 1000)),
|
|
}
|
|
})
|
|
|
|
err := th.App.Srv().FileBackend().(*filestore.S3FileBackend).TestConnection()
|
|
require.NoError(b, err)
|
|
|
|
_, err = fileA.Seek(0, io.SeekStart)
|
|
require.NoError(b, err)
|
|
_, err = fileB.Seek(0, io.SeekStart)
|
|
require.NoError(b, err)
|
|
|
|
_, appErr := th.App.WriteFile(fileA, "compareFileA")
|
|
require.Nil(b, appErr)
|
|
defer func() {
|
|
err = th.App.RemoveFile("compareFileA")
|
|
require.NoError(b, err)
|
|
}()
|
|
|
|
_, appErr = th.App.WriteFile(fileB, "compareFileB")
|
|
require.Nil(b, appErr)
|
|
defer func() {
|
|
appErr = th.App.RemoveFile("compareFileB")
|
|
require.Nil(b, appErr)
|
|
}()
|
|
|
|
rdA, appErr := th.App.FileReader("compareFileA")
|
|
require.Nil(b, appErr)
|
|
defer func() {
|
|
err = rdA.Close()
|
|
require.NoError(b, err)
|
|
}()
|
|
|
|
rdB, appErr := th.App.FileReader("compareFileB")
|
|
require.Nil(b, appErr)
|
|
defer func() {
|
|
err = rdB.Close()
|
|
require.NoError(b, err)
|
|
}()
|
|
|
|
for _, fileSizeLabel := range fileSizeLabels {
|
|
fileSize := fileSizesMap[fileSizeLabel]
|
|
for _, bufSizeLabel := range bufSizeLabels {
|
|
bufSize := bufSizesMap[bufSizeLabel]
|
|
b.Run("bufSize-fileSize"+fileSizeLabel+"-bufSize"+bufSizeLabel, func(b *testing.B) {
|
|
for b.Loop() {
|
|
b.StopTimer()
|
|
_, err := rdA.Seek(0, io.SeekStart)
|
|
require.NoError(b, err)
|
|
_, err = rdB.Seek(0, io.SeekStart)
|
|
require.NoError(b, err)
|
|
|
|
b.StartTimer()
|
|
ok, err := compareFilesContent(&io.LimitedReader{
|
|
R: rdA,
|
|
N: fileSize,
|
|
}, &io.LimitedReader{
|
|
R: rdB,
|
|
N: fileSize,
|
|
}, bufSize)
|
|
require.NoError(b, err)
|
|
require.True(b, ok)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
})
|
|
})
|
|
|
|
b.Run("zip", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
|
|
zipFilePath := filepath.Join(tmpDir, "compareFiles.zip")
|
|
zipFile, err := os.Create(zipFilePath)
|
|
require.NoError(b, err)
|
|
defer func() {
|
|
err = zipFile.Close()
|
|
require.NoError(b, err)
|
|
|
|
err = os.Remove(zipFilePath)
|
|
require.NoError(b, err)
|
|
}()
|
|
|
|
zipWr := zip.NewWriter(zipFile)
|
|
|
|
fileAZipWr, err := zipWr.CreateHeader(&zip.FileHeader{
|
|
Name: "compareFileA",
|
|
Method: zip.Store,
|
|
})
|
|
require.NoError(b, err)
|
|
_, err = io.Copy(fileAZipWr, fileA)
|
|
require.NoError(b, err)
|
|
|
|
fileBZipWr, err := zipWr.CreateHeader(&zip.FileHeader{
|
|
Name: "compareFileB",
|
|
Method: zip.Store,
|
|
})
|
|
require.NoError(b, err)
|
|
_, err = io.Copy(fileBZipWr, fileB)
|
|
require.NoError(b, err)
|
|
|
|
err = zipWr.Close()
|
|
require.NoError(b, err)
|
|
|
|
info, err := zipFile.Stat()
|
|
require.NoError(b, err)
|
|
|
|
zipFileSize := info.Size()
|
|
|
|
b.Run("local", func(b *testing.B) {
|
|
for _, label := range bufSizeLabels {
|
|
bufSize := bufSizesMap[label]
|
|
b.Run("bufSize-"+label, func(b *testing.B) {
|
|
for b.Loop() {
|
|
b.StopTimer()
|
|
_, err := zipFile.Seek(0, io.SeekStart)
|
|
require.NoError(b, err)
|
|
zipRd, err := zip.NewReader(zipFile, zipFileSize)
|
|
require.NoError(b, err)
|
|
|
|
zipFileA, err := zipRd.Open("compareFileA")
|
|
require.NoError(b, err)
|
|
|
|
zipFileB, err := zipRd.Open("compareFileB")
|
|
require.NoError(b, err)
|
|
|
|
b.StartTimer()
|
|
ok, err := compareFilesContent(zipFileA, zipFileB, bufSize)
|
|
require.NoError(b, err)
|
|
require.True(b, ok)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
b.Run("s3", func(b *testing.B) {
|
|
th := SetupConfig(b, func(cfg *model.Config) {
|
|
cfg.FileSettings = model.FileSettings{
|
|
DriverName: model.NewPointer(model.ImageDriverS3),
|
|
AmazonS3AccessKeyId: model.NewPointer(model.MinioAccessKey),
|
|
AmazonS3SecretAccessKey: model.NewPointer(model.MinioSecretKey),
|
|
AmazonS3Bucket: new("comparefilescontentbucket"),
|
|
AmazonS3Endpoint: new("localhost:9000"),
|
|
AmazonS3Region: new(""),
|
|
AmazonS3PathPrefix: new(""),
|
|
AmazonS3SSL: new(false),
|
|
AmazonS3RequestTimeoutMilliseconds: new(int64(300 * 1000)),
|
|
}
|
|
})
|
|
|
|
err := th.App.Srv().FileBackend().(*filestore.S3FileBackend).TestConnection()
|
|
require.NoError(b, err)
|
|
|
|
_, appErr := th.App.WriteFile(zipFile, "compareFiles.zip")
|
|
require.Nil(b, appErr)
|
|
defer func() {
|
|
appErr = th.App.RemoveFile("compareFiles.zip")
|
|
require.Nil(b, appErr)
|
|
}()
|
|
|
|
zipFileRd, appErr := th.App.FileReader("compareFiles.zip")
|
|
require.Nil(b, appErr)
|
|
defer func() {
|
|
err = zipFileRd.Close()
|
|
require.NoError(b, err)
|
|
}()
|
|
|
|
for _, fileSizeLabel := range fileSizeLabels {
|
|
fileSize := fileSizesMap[fileSizeLabel]
|
|
for _, bufSizeLabel := range bufSizeLabels {
|
|
bufSize := bufSizesMap[bufSizeLabel]
|
|
b.Run("bufSize-fileSize"+fileSizeLabel+"-bufSize"+bufSizeLabel, func(b *testing.B) {
|
|
for b.Loop() {
|
|
b.StopTimer()
|
|
_, err := zipFileRd.Seek(0, io.SeekStart)
|
|
require.NoError(b, err)
|
|
zipRd, err := zip.NewReader(zipFileRd.(io.ReaderAt), zipFileSize)
|
|
require.NoError(b, err)
|
|
|
|
zipFileA, err := zipRd.Open("compareFileA")
|
|
require.NoError(b, err)
|
|
|
|
zipFileB, err := zipRd.Open("compareFileB")
|
|
require.NoError(b, err)
|
|
|
|
b.StartTimer()
|
|
ok, err := compareFilesContent(&io.LimitedReader{
|
|
R: zipFileA,
|
|
N: fileSize,
|
|
}, &io.LimitedReader{
|
|
R: zipFileB,
|
|
N: fileSize,
|
|
}, bufSize)
|
|
require.NoError(b, err)
|
|
require.True(b, ok)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
})
|
|
})
|
|
}
|