From c11ebddbfb6682deb4114478d3e2ff29f8641c06 Mon Sep 17 00:00:00 2001 From: Carlos Tadeu Panato Junior Date: Tue, 7 Aug 2018 19:52:51 +0200 Subject: try to fix the flaky test (#9231) --- app/web_hub_test.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/web_hub_test.go b/app/web_hub_test.go index 62c2552de..8702acb21 100644 --- a/app/web_hub_test.go +++ b/app/web_hub_test.go @@ -53,8 +53,10 @@ func TestHubStopWithMultipleConnections(t *testing.T) { defer s.Close() th.App.HubStart() - registerDummyWebConn(t, th.App, s.Listener.Addr(), th.BasicUser.Id) - registerDummyWebConn(t, th.App, s.Listener.Addr(), th.BasicUser.Id) - registerDummyWebConn(t, th.App, s.Listener.Addr(), th.BasicUser.Id) - th.App.HubStop() + wc1 := registerDummyWebConn(t, th.App, s.Listener.Addr(), th.BasicUser.Id) + wc2 := registerDummyWebConn(t, th.App, s.Listener.Addr(), th.BasicUser.Id) + wc3 := registerDummyWebConn(t, th.App, s.Listener.Addr(), th.BasicUser.Id) + defer wc1.Close() + defer wc2.Close() + defer wc3.Close() } -- cgit v1.2.3-1-g7c22 From 3b640cd51b5b622002d6c9a0d6b1e7a6e9dafb69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Espino?= Date: Wed, 8 Aug 2018 12:04:16 +0200 Subject: Remove global-relay export command from the cli (#9226) --- cmd/mattermost/commands/message_export.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/cmd/mattermost/commands/message_export.go b/cmd/mattermost/commands/message_export.go index e7d82a8c1..953d4ccba 100644 --- a/cmd/mattermost/commands/message_export.go +++ b/cmd/mattermost/commands/message_export.go @@ -44,25 +44,15 @@ var ActianceExportCmd = &cobra.Command{ RunE: buildExportCmdF("actiance"), } -var GlobalRelayExportCmd = &cobra.Command{ - Use: "global-relay", - Short: "Export data from Mattermost in Global Relay format", - Long: "Export data from Mattermost in Global Relay format", - Example: "export global-relay --exportFrom=12345", - RunE: buildExportCmdF("globalrelay"), -} - func init() { ScheduleExportCmd.Flags().String("format", "actiance", "The format to export data") ScheduleExportCmd.Flags().Int64("exportFrom", -1, "The timestamp of the earliest post to export, expressed in seconds since the unix epoch.") ScheduleExportCmd.Flags().Int("timeoutSeconds", -1, "The maximum number of seconds to wait for the job to complete before timing out.") CsvExportCmd.Flags().Int64("exportFrom", -1, "The timestamp of the earliest post to export, expressed in seconds since the unix epoch.") ActianceExportCmd.Flags().Int64("exportFrom", -1, "The timestamp of the earliest post to export, expressed in seconds since the unix epoch.") - GlobalRelayExportCmd.Flags().Int64("exportFrom", -1, "The timestamp of the earliest post to export, expressed in seconds since the unix epoch.") MessageExportCmd.AddCommand(ScheduleExportCmd) MessageExportCmd.AddCommand(CsvExportCmd) MessageExportCmd.AddCommand(ActianceExportCmd) - MessageExportCmd.AddCommand(GlobalRelayExportCmd) RootCmd.AddCommand(MessageExportCmd) } -- cgit v1.2.3-1-g7c22 From 6bf09e2c34c568e3cb0d296142d5abed77332635 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Espino?= Date: Wed, 8 Aug 2018 12:04:36 +0200 Subject: MM-11384: Add system install date information to the client config (#9218) * MM-11384: Add system install date information to the client config * Fixing translation text * Fixes from Peer Review --- app/app.go | 18 +++++ app/config.go | 29 ++++++++ app/config_test.go | 81 ++++++++++++++++++++++ i18n/en.json | 8 +++ model/system.go | 1 + store/sqlstore/user_store.go | 11 +++ store/store.go | 1 + store/storetest/mocks/AuditStore.go | 2 +- store/storetest/mocks/ChannelMemberHistoryStore.go | 2 +- store/storetest/mocks/ChannelStore.go | 18 ++--- store/storetest/mocks/ClusterDiscoveryStore.go | 2 +- store/storetest/mocks/CommandStore.go | 2 +- store/storetest/mocks/CommandWebhookStore.go | 2 +- store/storetest/mocks/ComplianceStore.go | 2 +- store/storetest/mocks/EmojiStore.go | 2 +- store/storetest/mocks/FileInfoStore.go | 2 +- store/storetest/mocks/JobStore.go | 2 +- store/storetest/mocks/LayeredStoreDatabaseLayer.go | 2 +- store/storetest/mocks/LayeredStoreSupplier.go | 2 +- store/storetest/mocks/LicenseStore.go | 2 +- store/storetest/mocks/OAuthStore.go | 2 +- store/storetest/mocks/PluginStore.go | 2 +- store/storetest/mocks/PostStore.go | 2 +- store/storetest/mocks/PreferenceStore.go | 2 +- store/storetest/mocks/ReactionStore.go | 2 +- store/storetest/mocks/RoleStore.go | 2 +- store/storetest/mocks/SchemeStore.go | 2 +- store/storetest/mocks/SessionStore.go | 2 +- store/storetest/mocks/SqlStore.go | 2 +- store/storetest/mocks/StatusStore.go | 2 +- store/storetest/mocks/Store.go | 2 +- store/storetest/mocks/SystemStore.go | 2 +- store/storetest/mocks/TeamStore.go | 2 +- store/storetest/mocks/TokenStore.go | 2 +- store/storetest/mocks/UserAccessTokenStore.go | 2 +- store/storetest/mocks/UserStore.go | 18 ++++- store/storetest/mocks/WebhookStore.go | 2 +- 37 files changed, 203 insertions(+), 38 deletions(-) diff --git a/app/app.go b/app/app.go index 5cedca2ad..b704bb449 100644 --- a/app/app.go +++ b/app/app.go @@ -11,6 +11,7 @@ import ( "net/http" "path" "reflect" + "strconv" "strings" "sync" "sync/atomic" @@ -212,6 +213,10 @@ func New(options ...Option) (outApp *App, outErr error) { return nil, errors.Wrapf(err, "unable to ensure asymmetric signing key") } + if err := app.ensureInstallationDate(); err != nil { + return nil, errors.Wrapf(err, "unable to ensure installation date") + } + app.EnsureDiagnosticId() app.regenerateClientConfig() @@ -740,3 +745,16 @@ func (a *App) StartElasticsearch() { } }) } + +func (a *App) getSystemInstallDate() (int64, *model.AppError) { + result := <-a.Srv.Store.System().GetByName(model.SYSTEM_INSTALLATION_DATE_KEY) + if result.Err != nil { + return 0, result.Err + } + systemData := result.Data.(*model.System) + value, err := strconv.ParseInt(systemData.Value, 10, 64) + if err != nil { + return 0, model.NewAppError("getSystemInstallDate", "app.system_install_date.parse_int.app_error", nil, err.Error(), http.StatusInternalServerError) + } + return value, nil +} diff --git a/app/config.go b/app/config.go index 21571f291..1e96fd4fa 100644 --- a/app/config.go +++ b/app/config.go @@ -16,6 +16,7 @@ import ( "runtime/debug" "strconv" "strings" + "time" "github.com/mattermost/mattermost-server/mlog" "github.com/mattermost/mattermost-server/model" @@ -208,6 +209,30 @@ func (a *App) ensureAsymmetricSigningKey() error { return nil } +func (a *App) ensureInstallationDate() error { + _, err := a.getSystemInstallDate() + if err == nil { + return nil + } + + result := <-a.Srv.Store.User().InferSystemInstallDate() + var installationDate int64 + if result.Err == nil && result.Data.(int64) > 0 { + installationDate = result.Data.(int64) + } else { + installationDate = utils.MillisFromTime(time.Now()) + } + + result = <-a.Srv.Store.System().SaveOrUpdate(&model.System{ + Name: model.SYSTEM_INSTALLATION_DATE_KEY, + Value: strconv.FormatInt(installationDate, 10), + }) + if result.Err != nil { + return result.Err + } + return nil +} + // AsymmetricSigningKey will return a private key that can be used for asymmetric signing. func (a *App) AsymmetricSigningKey() *ecdsa.PrivateKey { return a.asymmetricSigningKey @@ -296,6 +321,10 @@ func (a *App) ClientConfigWithComputed() map[string]string { // by the client. respCfg["NoAccounts"] = strconv.FormatBool(a.IsFirstUserAccount()) respCfg["MaxPostSize"] = strconv.Itoa(a.MaxPostSize()) + respCfg["InstallationDate"] = "" + if installationDate, err := a.getSystemInstallDate(); err == nil { + respCfg["InstallationDate"] = strconv.FormatInt(installationDate, 10) + } return respCfg } diff --git a/app/config_test.go b/app/config_test.go index 4fc7df5e2..eb3fa8a53 100644 --- a/app/config_test.go +++ b/app/config_test.go @@ -4,11 +4,15 @@ package app import ( + "strconv" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/mattermost/mattermost-server/model" + "github.com/mattermost/mattermost-server/store/sqlstore" + "github.com/mattermost/mattermost-server/utils" ) func TestConfigListener(t *testing.T) { @@ -76,3 +80,80 @@ func TestClientConfigWithComputed(t *testing.T) { t.Fatal("expected MaxPostSize in returned config") } } + +func TestEnsureInstallationDate(t *testing.T) { + th := Setup() + defer th.TearDown() + + tt := []struct { + Name string + PrevInstallationDate *int64 + UsersCreationDates []int64 + ExpectedInstallationDate *int64 + }{ + { + Name: "New installation: no users, no installation date", + PrevInstallationDate: nil, + UsersCreationDates: nil, + ExpectedInstallationDate: model.NewInt64(utils.MillisFromTime(time.Now())), + }, + { + Name: "Old installation: users, no installation date", + PrevInstallationDate: nil, + UsersCreationDates: []int64{10000000000, 30000000000, 20000000000}, + ExpectedInstallationDate: model.NewInt64(10000000000), + }, + { + Name: "New installation, second run: no users, installation date", + PrevInstallationDate: model.NewInt64(80000000000), + UsersCreationDates: []int64{10000000000, 30000000000, 20000000000}, + ExpectedInstallationDate: model.NewInt64(80000000000), + }, + { + Name: "Old installation already updated: users, installation date", + PrevInstallationDate: model.NewInt64(90000000000), + UsersCreationDates: []int64{10000000000, 30000000000, 20000000000}, + ExpectedInstallationDate: model.NewInt64(90000000000), + }, + } + + for _, tc := range tt { + t.Run(tc.Name, func(t *testing.T) { + sqlStore := th.App.Srv.Store.User().(*sqlstore.SqlUserStore) + sqlStore.GetMaster().Exec("DELETE FROM Users") + + var users []*model.User + for _, createAt := range tc.UsersCreationDates { + user := th.CreateUser() + user.CreateAt = createAt + sqlStore.GetMaster().Exec("UPDATE Users SET CreateAt = :CreateAt WHERE Id = :UserId", map[string]interface{}{"CreateAt": createAt, "UserId": user.Id}) + users = append(users, user) + } + + if tc.PrevInstallationDate == nil { + <-th.App.Srv.Store.System().PermanentDeleteByName(model.SYSTEM_INSTALLATION_DATE_KEY) + } else { + <-th.App.Srv.Store.System().SaveOrUpdate(&model.System{ + Name: model.SYSTEM_INSTALLATION_DATE_KEY, + Value: strconv.FormatInt(*tc.PrevInstallationDate, 10), + }) + } + + err := th.App.ensureInstallationDate() + + if tc.ExpectedInstallationDate == nil { + assert.Error(t, err) + } else { + assert.NoError(t, err) + + result := <-th.App.Srv.Store.System().GetByName(model.SYSTEM_INSTALLATION_DATE_KEY) + assert.Nil(t, result.Err) + data, _ := result.Data.(*model.System) + value, _ := strconv.ParseInt(data.Value, 10, 64) + assert.True(t, *tc.ExpectedInstallationDate <= value && *tc.ExpectedInstallationDate+1000 >= value) + } + + sqlStore.GetMaster().Exec("DELETE FROM Users") + }) + } +} diff --git a/i18n/en.json b/i18n/en.json index 3c2cee632..d3ffdebb5 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -3110,6 +3110,10 @@ "id": "app.schemes.is_phase_2_migration_completed.not_completed.app_error", "translation": "This API endpoint is not accessible as required migrations have not yet completed." }, + { + "id": "app.system_install_date.parse_int.app_error", + "translation": "Failed to parse installation date" + }, { "id": "app.team.join_user_to_team.max_accounts.app_error", "translation": "This team has reached the maximum number of allowed accounts. Contact your systems administrator to set a higher limit." @@ -5938,6 +5942,10 @@ "id": "store.sql_user.get_for_login.multiple_users", "translation": "We found multiple users matching your credentials and were unable to log you in. Please contact an administrator." }, + { + "id": "store.sql_user.get_system_install_date.app_error", + "translation": "Unable to infer the system date based on the first user creation date." + }, { "id": "store.sql_user.get_new_users.app_error", "translation": "We encountered an error while finding the new users" diff --git a/model/system.go b/model/system.go index 2a636b14f..4228516d5 100644 --- a/model/system.go +++ b/model/system.go @@ -16,6 +16,7 @@ const ( SYSTEM_ACTIVE_LICENSE_ID = "ActiveLicenseId" SYSTEM_LAST_COMPLIANCE_TIME = "LastComplianceTime" SYSTEM_ASYMMETRIC_SIGNING_KEY = "AsymmetricSigningKey" + SYSTEM_INSTALLATION_DATE_KEY = "InstallationDate" ) type System struct { diff --git a/store/sqlstore/user_store.go b/store/sqlstore/user_store.go index 203ad4c26..d8a77cd9d 100644 --- a/store/sqlstore/user_store.go +++ b/store/sqlstore/user_store.go @@ -1316,3 +1316,14 @@ func (us SqlUserStore) ClearAllCustomRoleAssignments() store.StoreChannel { } }) } + +func (us SqlUserStore) InferSystemInstallDate() store.StoreChannel { + return store.Do(func(result *store.StoreResult) { + createAt, err := us.GetReplica().SelectInt("SELECT CreateAt FROM Users WHERE CreateAt IS NOT NULL ORDER BY CreateAt ASC LIMIT 1") + if err != nil { + result.Err = model.NewAppError("SqlUserStore.GetSystemInstallDate", "store.sql_user.get_system_install_date.app_error", nil, err.Error(), http.StatusInternalServerError) + return + } + result.Data = createAt + }) +} diff --git a/store/store.go b/store/store.go index 2f18a0d8f..89adce188 100644 --- a/store/store.go +++ b/store/store.go @@ -263,6 +263,7 @@ type UserStore interface { GetProfilesNotInTeam(teamId string, offset int, limit int) StoreChannel GetEtagForProfilesNotInTeam(teamId string) StoreChannel ClearAllCustomRoleAssignments() StoreChannel + InferSystemInstallDate() StoreChannel } type SessionStore interface { diff --git a/store/storetest/mocks/AuditStore.go b/store/storetest/mocks/AuditStore.go index df84545bd..d1ee9082e 100644 --- a/store/storetest/mocks/AuditStore.go +++ b/store/storetest/mocks/AuditStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/ChannelMemberHistoryStore.go b/store/storetest/mocks/ChannelMemberHistoryStore.go index 16155b982..ae8d024d1 100644 --- a/store/storetest/mocks/ChannelMemberHistoryStore.go +++ b/store/storetest/mocks/ChannelMemberHistoryStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/ChannelStore.go b/store/storetest/mocks/ChannelStore.go index 4cbf9cb77..8adc98e10 100644 --- a/store/storetest/mocks/ChannelStore.go +++ b/store/storetest/mocks/ChannelStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make store-mocks`. @@ -45,9 +45,9 @@ func (_m *ChannelStore) AnalyticsTypeCount(teamId string, channelType string) st return r0 } -// AutocompleteInTeam provides a mock function with given fields: teamId, term +// AutocompleteInTeam provides a mock function with given fields: teamId, term, includeDeleted func (_m *ChannelStore) AutocompleteInTeam(teamId string, term string, includeDeleted bool) store.StoreChannel { - ret := _m.Called(teamId, term) + ret := _m.Called(teamId, term, includeDeleted) var r0 store.StoreChannel if rf, ok := ret.Get(0).(func(string, string, bool) store.StoreChannel); ok { @@ -146,9 +146,9 @@ func (_m *ChannelStore) GetAll(teamId string) store.StoreChannel { return r0 } -// GetAllChannelMembersForUser provides a mock function with given fields: userId, allowFromCache +// GetAllChannelMembersForUser provides a mock function with given fields: userId, allowFromCache, includeDeleted func (_m *ChannelStore) GetAllChannelMembersForUser(userId string, allowFromCache bool, includeDeleted bool) store.StoreChannel { - ret := _m.Called(userId, allowFromCache) + ret := _m.Called(userId, allowFromCache, includeDeleted) var r0 store.StoreChannel if rf, ok := ret.Get(0).(func(string, bool, bool) store.StoreChannel); ok { @@ -258,9 +258,9 @@ func (_m *ChannelStore) GetChannelUnread(channelId string, userId string) store. return r0 } -// GetChannels provides a mock function with given fields: teamId, userId +// GetChannels provides a mock function with given fields: teamId, userId, includeDeleted func (_m *ChannelStore) GetChannels(teamId string, userId string, includeDeleted bool) store.StoreChannel { - ret := _m.Called(teamId, userId) + ret := _m.Called(teamId, userId, includeDeleted) var r0 store.StoreChannel if rf, ok := ret.Get(0).(func(string, string, bool) store.StoreChannel); ok { @@ -775,9 +775,9 @@ func (_m *ChannelStore) SaveMember(member *model.ChannelMember) store.StoreChann return r0 } -// SearchInTeam provides a mock function with given fields: teamId, term +// SearchInTeam provides a mock function with given fields: teamId, term, includeDeleted func (_m *ChannelStore) SearchInTeam(teamId string, term string, includeDeleted bool) store.StoreChannel { - ret := _m.Called(teamId, term) + ret := _m.Called(teamId, term, includeDeleted) var r0 store.StoreChannel if rf, ok := ret.Get(0).(func(string, string, bool) store.StoreChannel); ok { diff --git a/store/storetest/mocks/ClusterDiscoveryStore.go b/store/storetest/mocks/ClusterDiscoveryStore.go index 997dcf03f..4010006d8 100644 --- a/store/storetest/mocks/ClusterDiscoveryStore.go +++ b/store/storetest/mocks/ClusterDiscoveryStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/CommandStore.go b/store/storetest/mocks/CommandStore.go index de4bc4e34..798bbee4d 100644 --- a/store/storetest/mocks/CommandStore.go +++ b/store/storetest/mocks/CommandStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/CommandWebhookStore.go b/store/storetest/mocks/CommandWebhookStore.go index cede8cdd2..5129388ae 100644 --- a/store/storetest/mocks/CommandWebhookStore.go +++ b/store/storetest/mocks/CommandWebhookStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/ComplianceStore.go b/store/storetest/mocks/ComplianceStore.go index fb828cd4b..dd75941b3 100644 --- a/store/storetest/mocks/ComplianceStore.go +++ b/store/storetest/mocks/ComplianceStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/EmojiStore.go b/store/storetest/mocks/EmojiStore.go index 9871c98aa..b1f0a3217 100644 --- a/store/storetest/mocks/EmojiStore.go +++ b/store/storetest/mocks/EmojiStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/FileInfoStore.go b/store/storetest/mocks/FileInfoStore.go index a33ca0453..fa8ee444f 100644 --- a/store/storetest/mocks/FileInfoStore.go +++ b/store/storetest/mocks/FileInfoStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/JobStore.go b/store/storetest/mocks/JobStore.go index d3558212e..a78a3f94e 100644 --- a/store/storetest/mocks/JobStore.go +++ b/store/storetest/mocks/JobStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/LayeredStoreDatabaseLayer.go b/store/storetest/mocks/LayeredStoreDatabaseLayer.go index 47b594a81..8e82e9494 100644 --- a/store/storetest/mocks/LayeredStoreDatabaseLayer.go +++ b/store/storetest/mocks/LayeredStoreDatabaseLayer.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/LayeredStoreSupplier.go b/store/storetest/mocks/LayeredStoreSupplier.go index 929f077c7..ddd0abf58 100644 --- a/store/storetest/mocks/LayeredStoreSupplier.go +++ b/store/storetest/mocks/LayeredStoreSupplier.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/LicenseStore.go b/store/storetest/mocks/LicenseStore.go index 5c65425ea..f00ebba78 100644 --- a/store/storetest/mocks/LicenseStore.go +++ b/store/storetest/mocks/LicenseStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/OAuthStore.go b/store/storetest/mocks/OAuthStore.go index fb49d715d..a39570b6c 100644 --- a/store/storetest/mocks/OAuthStore.go +++ b/store/storetest/mocks/OAuthStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/PluginStore.go b/store/storetest/mocks/PluginStore.go index 920b0f63c..b6f161a86 100644 --- a/store/storetest/mocks/PluginStore.go +++ b/store/storetest/mocks/PluginStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/PostStore.go b/store/storetest/mocks/PostStore.go index f97b8a2f6..1c1baec7b 100644 --- a/store/storetest/mocks/PostStore.go +++ b/store/storetest/mocks/PostStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/PreferenceStore.go b/store/storetest/mocks/PreferenceStore.go index 5ad56914a..f53ae06d5 100644 --- a/store/storetest/mocks/PreferenceStore.go +++ b/store/storetest/mocks/PreferenceStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/ReactionStore.go b/store/storetest/mocks/ReactionStore.go index ce09f3f76..b3e81a83b 100644 --- a/store/storetest/mocks/ReactionStore.go +++ b/store/storetest/mocks/ReactionStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/RoleStore.go b/store/storetest/mocks/RoleStore.go index c1b14d5dc..95e1914e0 100644 --- a/store/storetest/mocks/RoleStore.go +++ b/store/storetest/mocks/RoleStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/SchemeStore.go b/store/storetest/mocks/SchemeStore.go index ddf24c2c3..d54e73261 100644 --- a/store/storetest/mocks/SchemeStore.go +++ b/store/storetest/mocks/SchemeStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/SessionStore.go b/store/storetest/mocks/SessionStore.go index 70b2bd945..819ae948d 100644 --- a/store/storetest/mocks/SessionStore.go +++ b/store/storetest/mocks/SessionStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/SqlStore.go b/store/storetest/mocks/SqlStore.go index a0cc3f0cc..a93db78c9 100644 --- a/store/storetest/mocks/SqlStore.go +++ b/store/storetest/mocks/SqlStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/StatusStore.go b/store/storetest/mocks/StatusStore.go index 4acb90bdd..68ccdd4ec 100644 --- a/store/storetest/mocks/StatusStore.go +++ b/store/storetest/mocks/StatusStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/Store.go b/store/storetest/mocks/Store.go index 3a5b7726c..e5d0c4290 100644 --- a/store/storetest/mocks/Store.go +++ b/store/storetest/mocks/Store.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/SystemStore.go b/store/storetest/mocks/SystemStore.go index b31e4646d..e36396fe1 100644 --- a/store/storetest/mocks/SystemStore.go +++ b/store/storetest/mocks/SystemStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/TeamStore.go b/store/storetest/mocks/TeamStore.go index 47ea6587b..db5cb658f 100644 --- a/store/storetest/mocks/TeamStore.go +++ b/store/storetest/mocks/TeamStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/TokenStore.go b/store/storetest/mocks/TokenStore.go index b4baacf03..657aeca49 100644 --- a/store/storetest/mocks/TokenStore.go +++ b/store/storetest/mocks/TokenStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/UserAccessTokenStore.go b/store/storetest/mocks/UserAccessTokenStore.go index c5ef0fefe..fd98a8a99 100644 --- a/store/storetest/mocks/UserAccessTokenStore.go +++ b/store/storetest/mocks/UserAccessTokenStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/UserStore.go b/store/storetest/mocks/UserStore.go index 760b6e934..1f9f07e7d 100644 --- a/store/storetest/mocks/UserStore.go +++ b/store/storetest/mocks/UserStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make store-mocks`. @@ -514,6 +514,22 @@ func (_m *UserStore) GetUnreadCountForChannel(userId string, channelId string) s return r0 } +// InferSystemInstallDate provides a mock function with given fields: +func (_m *UserStore) InferSystemInstallDate() store.StoreChannel { + ret := _m.Called() + + var r0 store.StoreChannel + if rf, ok := ret.Get(0).(func() store.StoreChannel); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(store.StoreChannel) + } + } + + return r0 +} + // InvalidatProfileCacheForUser provides a mock function with given fields: userId func (_m *UserStore) InvalidatProfileCacheForUser(userId string) { _m.Called(userId) diff --git a/store/storetest/mocks/WebhookStore.go b/store/storetest/mocks/WebhookStore.go index bf5b636eb..a0b2b0bee 100644 --- a/store/storetest/mocks/WebhookStore.go +++ b/store/storetest/mocks/WebhookStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0 +// Code generated by mockery v1.0.0. DO NOT EDIT. // Regenerate this file using `make store-mocks`. -- cgit v1.2.3-1-g7c22 From 7475cd260a3aba46e0b7524656b42209c1779c22 Mon Sep 17 00:00:00 2001 From: Jesse Hallam Date: Wed, 8 Aug 2018 06:07:38 -0400 Subject: fix plugintest example and docs (#9213) --- plugin/plugintest/doc.go | 11 ++++++ plugin/plugintest/example_hello_user_test.go | 55 ++++++++++++++++++++++++++++ plugin/plugintest/plugintest.go | 48 ------------------------ 3 files changed, 66 insertions(+), 48 deletions(-) create mode 100644 plugin/plugintest/doc.go create mode 100644 plugin/plugintest/example_hello_user_test.go delete mode 100644 plugin/plugintest/plugintest.go diff --git a/plugin/plugintest/doc.go b/plugin/plugintest/doc.go new file mode 100644 index 000000000..69a51bd39 --- /dev/null +++ b/plugin/plugintest/doc.go @@ -0,0 +1,11 @@ +// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +// The plugintest package provides mocks that can be used to test plugins. +// +// The mocks are created using testify's mock package: +// https://godoc.org/github.com/stretchr/testify/mock +// +// If you need to import the mock package, you can import it with +// "github.com/mattermost/mattermost-server/plugin/plugintest/mock". +package plugintest diff --git a/plugin/plugintest/example_hello_user_test.go b/plugin/plugintest/example_hello_user_test.go new file mode 100644 index 000000000..3a12f292c --- /dev/null +++ b/plugin/plugintest/example_hello_user_test.go @@ -0,0 +1,55 @@ +package plugintest_test + +import ( + "fmt" + "io/ioutil" + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/mattermost/mattermost-server/model" + "github.com/mattermost/mattermost-server/plugin" + "github.com/mattermost/mattermost-server/plugin/plugintest" +) + +type HelloUserPlugin struct { + plugin.MattermostPlugin +} + +func (p *HelloUserPlugin) ServeHTTP(context *plugin.Context, w http.ResponseWriter, r *http.Request) { + userId := r.Header.Get("Mattermost-User-Id") + user, err := p.API.GetUser(userId) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + p.API.LogError(err.Error()) + return + } + + fmt.Fprintf(w, "Welcome back, %s!", user.Username) +} + +func Example() { + t := &testing.T{} + user := &model.User{ + Id: model.NewId(), + Username: "billybob", + } + + api := &plugintest.API{} + api.On("GetUser", user.Id).Return(user, nil) + defer api.AssertExpectations(t) + + p := &HelloUserPlugin{} + p.SetAPI(api) + + w := httptest.NewRecorder() + r := httptest.NewRequest("GET", "/", nil) + r.Header.Add("Mattermost-User-Id", user.Id) + p.ServeHTTP(&plugin.Context{}, w, r) + body, err := ioutil.ReadAll(w.Result().Body) + require.NoError(t, err) + assert.Equal(t, "Welcome back, billybob!", string(body)) +} diff --git a/plugin/plugintest/plugintest.go b/plugin/plugintest/plugintest.go deleted file mode 100644 index 0275edd84..000000000 --- a/plugin/plugintest/plugintest.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -// The plugintest package provides mocks that can be used to test plugins. For example, to test the -// ServeHTTP method of the plugin package's HelloUser example: -// -// package plugin_test -// -// import ( -// "io/ioutil" -// "net/http/httptest" -// "testing" -// -// "github.com/stretchr/testify/assert" -// "github.com/stretchr/testify/require" -// -// "github.com/mattermost/mattermost-server/model" -// "github.com/mattermost/mattermost-server/plugin/plugintest" -// ) -// -// func TestHelloUserPlugin(t *testing.T) { -// user := &model.User{ -// Id: model.NewId(), -// Username: "billybob", -// } -// -// api := &plugintest.API{} -// api.On("GetUser", user.Id).Return(user, nil) -// defer api.AssertExpectations(t) -// -// p := &HelloUserPlugin{} -// p.OnActivate(api) -// -// w := httptest.NewRecorder() -// r := httptest.NewRequest("GET", "/", nil) -// r.Header.Add("Mattermost-User-Id", user.Id) -// p.ServeHTTP(w, r) -// body, err := ioutil.ReadAll(w.Result().Body) -// require.NoError(t, err) -// assert.Equal(t, "Welcome back, billybob!", string(body)) -// } -// -// The mocks are created using testify's mock package: -// https://godoc.org/github.com/stretchr/testify/mock -// -// If you need to import the mock package, you can import it with -// "github.com/mattermost/mattermost-server/plugin/plugintest/mock". -package plugintest -- cgit v1.2.3-1-g7c22 From 5fbec91c35d7ea5d9b920b26a01fc21da55bb08e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Espino?= Date: Wed, 8 Aug 2018 12:10:05 +0200 Subject: MM-9747: Small fixes for attachments import (#9225) * MM-9747: Small fixes for attachments import * Adding unit test RootId check in replies --- api4/file.go | 1 + app/import_functions.go | 8 ++++--- app/import_functions_test.go | 54 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 3 deletions(-) diff --git a/api4/file.go b/api4/file.go index f73a54fb4..cfb72cdcb 100644 --- a/api4/file.go +++ b/api4/file.go @@ -285,6 +285,7 @@ func getFilePreview(c *Context, w http.ResponseWriter, r *http.Request) { if err != nil { c.Err = err c.Err.StatusCode = http.StatusNotFound + return } defer fileReader.Close() diff --git a/app/import_functions.go b/app/import_functions.go index f4ff5607f..e370099d9 100644 --- a/app/import_functions.go +++ b/app/import_functions.go @@ -763,7 +763,7 @@ func (a *App) ImportReply(data *ReplyImportData, post *model.Post, teamId string var reply *model.Post for _, r := range replies { - if r.Message == *data.Message { + if r.Message == *data.Message && r.RootId == post.Id { reply = r break } @@ -784,7 +784,7 @@ func (a *App) ImportReply(data *ReplyImportData, post *model.Post, teamId string if err != nil { return err } - reply.FileIds = fileIds + reply.FileIds = append(reply.FileIds, fileIds...) } if reply.Id == "" { @@ -820,6 +820,8 @@ func (a *App) ImportAttachment(data *AttachmentImportData, post *model.Post, tea return nil, fileUploadError } + a.HandleImages([]string{fileInfo.PreviewPath}, []string{fileInfo.ThumbnailPath}, [][]byte{buf.Bytes()}) + mlog.Info(fmt.Sprintf("uploading file with name %s", file.Name())) return fileInfo, nil } @@ -889,7 +891,7 @@ func (a *App) ImportPost(data *PostImportData, dryRun bool) *model.AppError { if err != nil { return err } - post.FileIds = fileIds + post.FileIds = append(post.FileIds, fileIds...) } if post.Id == "" { diff --git a/app/import_functions_test.go b/app/import_functions_test.go index e0859af45..fd8ae462e 100644 --- a/app/import_functions_test.go +++ b/app/import_functions_test.go @@ -1700,6 +1700,60 @@ func TestImportImportPost(t *testing.T) { } } } + + // Update post with replies. + data = &PostImportData{ + Team: &teamName, + Channel: &channelName, + User: &user2.Username, + Message: ptrStr("Message with reply"), + CreateAt: &replyPostTime, + Replies: &[]ReplyImportData{{ + User: &username, + Message: ptrStr("Message reply"), + CreateAt: &replyTime, + }}, + } + if err := th.App.ImportPost(data, false); err != nil { + t.Fatalf("Expected success.") + } + AssertAllPostsCount(t, th.App, initialPostCount, 8, team.Id) + + // Create new post with replies based on the previous one. + data = &PostImportData{ + Team: &teamName, + Channel: &channelName, + User: &user2.Username, + Message: ptrStr("Message with reply 2"), + CreateAt: &replyPostTime, + Replies: &[]ReplyImportData{{ + User: &username, + Message: ptrStr("Message reply"), + CreateAt: &replyTime, + }}, + } + if err := th.App.ImportPost(data, false); err != nil { + t.Fatalf("Expected success.") + } + AssertAllPostsCount(t, th.App, initialPostCount, 10, team.Id) + + // Create new reply for existing post with replies. + data = &PostImportData{ + Team: &teamName, + Channel: &channelName, + User: &user2.Username, + Message: ptrStr("Message with reply"), + CreateAt: &replyPostTime, + Replies: &[]ReplyImportData{{ + User: &username, + Message: ptrStr("Message reply 2"), + CreateAt: &replyTime, + }}, + } + if err := th.App.ImportPost(data, false); err != nil { + t.Fatalf("Expected success.") + } + AssertAllPostsCount(t, th.App, initialPostCount, 11, team.Id) } func TestImportImportDirectChannel(t *testing.T) { -- cgit v1.2.3-1-g7c22