mattermost/server/public/model/utils_test.go

1440 lines
30 KiB
Go
Raw Permalink Normal View History

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
2015-06-15 03:53:32 -04:00
package model
import (
"bytes"
2024-01-09 12:04:16 -05:00
"encoding/json"
"errors"
"fmt"
"net/http"
"reflect"
2015-06-15 03:53:32 -04:00
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
2015-06-15 03:53:32 -04:00
)
func TestNewId(t *testing.T) {
for range 1000 {
2015-06-15 03:53:32 -04:00
id := NewId()
require.LessOrEqual(t, len(id), 26, "ids shouldn't be longer than 26 chars")
2015-06-15 03:53:32 -04:00
}
}
2015-12-09 18:42:48 -05:00
func TestRandomString(t *testing.T) {
for i := range 1000 {
str := NewRandomString(i)
require.Len(t, str, i)
require.NotContains(t, str, "=")
}
}
Generate instead of hard-coding test passwords, enforce new minimum for FIPS, shard CI, fix FIPS builds (#35905) * Replace hardcoded test passwords with model.NewTestPassword() Add model.NewTestPassword() utility that generates 14+ character passwords meeting complexity requirements for FIPS compliance. Replace all short hardcoded test passwords across the test suite with calls to this function. * Enforce FIPS compliance for passwords and HMAC keys FIPS OpenSSL requires HMAC keys to be at least 14 bytes. PBKDF2 uses the password as the HMAC key internally, so short passwords cause PKCS5_PBKDF2_HMAC to fail. - Add FIPSEnabled and PasswordFIPSMinimumLength build-tag constants - Raise the password minimum length floor to 14 when compiled with requirefips, applied in SetDefaults only when unset and validated independently in IsValid - Return ErrMismatchedHashAndPassword for too-short passwords in PBKDF2 CompareHashAndPassword rather than a cryptic OpenSSL error - Validate atmos/camo HMAC key length under FIPS and lengthen test keys accordingly - Adjust password validation tests to use PasswordFIPSMinimumLength so they work under both FIPS and non-FIPS builds * CI: shard FIPS test suite and extract merge template Run FIPS tests on PRs that touch go.mod or have 'fips' in the branch name. Shard FIPS tests across 4 runners matching the normal Postgres suite. Extract the test result merge logic into a reusable workflow template to deduplicate the normal and FIPS merge jobs. * more * Fix email test helper to respect FIPS minimum password length * Fix test helpers to respect FIPS minimum password length * Remove unnecessary "disable strict password requirements" blocks from test helpers * Fix CodeRabbit review comments on PR #35905 - Add server-test-merge-template.yml to server-ci.yml pull_request.paths so changes to the reusable merge workflow trigger Server CI validation - Skip merge-postgres-fips-test-results job when test-postgres-normal-fips was skipped, preventing failures due to missing artifacts - Set guest.Password on returned guest in CreateGuestAndClient helper to keep contract consistent with CreateUserWithClient - Use shared LowercaseLetters/UppercaseLetters/NUMBERS/PasswordFIPSMinimumLength constants in NewTestPassword() to avoid drift if FIPS floor changes https://claude.ai/code/session_01HmE9QkZM3cAoXn2J7XrK2f * Rename FIPS test artifact to match server-ci-report pattern The server-ci-report job searches for artifacts matching "*-test-logs", so rename from postgres-server-test-logs-fips to postgres-server-fips-test-logs to be included in the report. --------- Co-authored-by: Claude <noreply@anthropic.com>
2026-04-08 15:49:43 -04:00
func BenchmarkNewTestPassword(b *testing.B) {
for range b.N {
NewTestPassword()
}
}
func TestGetMillisForTime(t *testing.T) {
thisTimeMillis := int64(1471219200000)
thisTime := time.Date(2016, time.August, 15, 0, 0, 0, 0, time.UTC)
result := GetMillisForTime(thisTime)
require.Equalf(t, thisTimeMillis, result, "millis are not the same: %d and %d", thisTimeMillis, result)
}
func TestGetTimeForMillis(t *testing.T) {
thisTimeMillis := int64(1471219200000)
thisTime := time.Date(2016, time.August, 15, 0, 0, 0, 0, time.UTC)
result := GetTimeForMillis(thisTimeMillis)
require.True(t, thisTime.Equal(result))
}
func TestPadDateStringZeros(t *testing.T) {
for _, testCase := range []struct {
Name string
Input string
Expected string
}{
{
Name: "Valid date",
Input: "2016-08-01",
Expected: "2016-08-01",
},
{
Name: "Valid date but requires padding of zero",
Input: "2016-8-1",
Expected: "2016-08-01",
},
} {
t.Run(testCase.Name, func(t *testing.T) {
assert.Equal(t, testCase.Expected, PadDateStringZeros(testCase.Input))
})
}
}
func TestAppErrorRender(t *testing.T) {
t.Run("Minimal", func(t *testing.T) {
aerr := NewAppError("here", "message", nil, "", http.StatusTeapot)
assert.EqualError(t, aerr, "here: message")
})
t.Run("Without where", func(t *testing.T) {
aerr := NewAppError("", "message", nil, "details", http.StatusTeapot)
assert.EqualError(t, aerr, "message, details")
})
t.Run("Detailed", func(t *testing.T) {
aerr := NewAppError("here", "message", nil, "details", http.StatusTeapot)
assert.EqualError(t, aerr, "here: message, details")
})
t.Run("Wrapped", func(t *testing.T) {
aerr := NewAppError("here", "message", nil, "", http.StatusTeapot).Wrap(fmt.Errorf("my error"))
assert.EqualError(t, aerr, "here: message, my error")
})
t.Run("WrappedMultiple", func(t *testing.T) {
aerr := NewAppError("here", "message", nil, "", http.StatusTeapot).Wrap(fmt.Errorf("my error (%w)", fmt.Errorf("inner error")))
2022-08-18 05:01:37 -04:00
assert.EqualError(t, aerr, "here: message, my error (inner error)")
})
t.Run("DetailedWrappedMultiple", func(t *testing.T) {
aerr := NewAppError("here", "message", nil, "details", http.StatusTeapot).Wrap(fmt.Errorf("my error (%w)", fmt.Errorf("inner error")))
2022-08-18 05:01:37 -04:00
assert.EqualError(t, aerr, "here: message, details, my error (inner error)")
})
t.Run("MaxLength", func(t *testing.T) {
str := strings.Repeat("error", 65536)
msg := "msg"
aerr := NewAppError("id", msg, nil, str, http.StatusTeapot).Wrap(errors.New(str))
assert.Len(t, aerr.Error(), maxErrorLength+len(msg))
})
t.Run("No Translation", func(t *testing.T) {
appErr := NewAppError("TestAppError", NoTranslation, nil, "test error", http.StatusBadRequest)
require.Equal(t, "TestAppError: test error", appErr.Error())
})
}
func TestAppErrorSerialize(t *testing.T) {
t.Run("Junk", func(t *testing.T) {
rerr := AppErrorFromJSON(strings.NewReader("<html><body>This is a broken test</body></html>"))
require.ErrorContains(t, rerr, "failed to decode JSON payload into AppError")
require.ErrorContains(t, rerr, "<html><body>This is a broken test</body></html>")
})
t.Run("Normal", func(t *testing.T) {
aerr := NewAppError("", "message", nil, "", http.StatusTeapot)
js := aerr.ToJSON()
err := AppErrorFromJSON(strings.NewReader(js))
berr, ok := err.(*AppError)
require.True(t, ok)
require.Equal(t, "message", berr.Id)
require.Empty(t, berr.DetailedError)
require.Equal(t, http.StatusTeapot, berr.StatusCode)
require.EqualError(t, berr, aerr.Error())
})
t.Run("Detailed", func(t *testing.T) {
aerr := NewAppError("", "message", nil, "detail", http.StatusTeapot)
js := aerr.ToJSON()
err := AppErrorFromJSON(strings.NewReader(js))
berr, ok := err.(*AppError)
require.True(t, ok)
require.Equal(t, "message", berr.Id)
require.Equal(t, "detail", berr.DetailedError)
require.Equal(t, http.StatusTeapot, berr.StatusCode)
require.EqualError(t, berr, aerr.Error())
})
t.Run("Wipe Detailed", func(t *testing.T) {
aerr := NewAppError("", "message", nil, "detail", http.StatusTeapot)
aerr.WipeDetailed()
js := aerr.ToJSON()
err := AppErrorFromJSON(strings.NewReader(js))
berr, ok := err.(*AppError)
require.True(t, ok)
require.Equal(t, "message", berr.Id)
require.Equal(t, "", berr.DetailedError)
require.Equal(t, http.StatusTeapot, berr.StatusCode)
require.EqualError(t, berr, aerr.Error())
})
t.Run("Wrapped", func(t *testing.T) {
aerr := NewAppError("", "message", nil, "", http.StatusTeapot).Wrap(errors.New("wrapped"))
js := aerr.ToJSON()
err := AppErrorFromJSON(strings.NewReader(js))
berr, ok := err.(*AppError)
require.True(t, ok)
require.Equal(t, "message", berr.Id)
require.Equal(t, "wrapped", berr.DetailedError)
require.Equal(t, http.StatusTeapot, berr.StatusCode)
require.EqualError(t, berr, aerr.Error())
})
t.Run("Wipe Wrapped", func(t *testing.T) {
aerr := NewAppError("", "message", nil, "", http.StatusTeapot).Wrap(errors.New("wrapped"))
aerr.WipeDetailed()
js := aerr.ToJSON()
err := AppErrorFromJSON(strings.NewReader(js))
berr, ok := err.(*AppError)
require.True(t, ok)
require.Equal(t, "message", berr.Id)
require.Equal(t, "", berr.DetailedError)
require.Equal(t, http.StatusTeapot, berr.StatusCode)
require.EqualError(t, berr, aerr.Error())
})
t.Run("Detailed + Wrapped", func(t *testing.T) {
aerr := NewAppError("", "message", nil, "detail", http.StatusTeapot).Wrap(errors.New("wrapped"))
js := aerr.ToJSON()
err := AppErrorFromJSON(strings.NewReader(js))
berr, ok := err.(*AppError)
require.True(t, ok)
require.Equal(t, "message", berr.Id)
require.Equal(t, "detail, wrapped", berr.DetailedError)
require.Equal(t, http.StatusTeapot, berr.StatusCode)
require.EqualError(t, berr, aerr.Error())
})
t.Run("Detailed + Wrapped", func(t *testing.T) {
aerr := NewAppError("", "message", nil, "detail", http.StatusTeapot).Wrap(errors.New("wrapped"))
aerr.WipeDetailed()
js := aerr.ToJSON()
err := AppErrorFromJSON(strings.NewReader(js))
berr, ok := err.(*AppError)
require.True(t, ok)
require.Equal(t, "message", berr.Id)
require.Equal(t, "", berr.DetailedError)
require.Equal(t, http.StatusTeapot, berr.StatusCode)
require.EqualError(t, berr, aerr.Error())
})
t.Run("Where", func(t *testing.T) {
appErr := NewAppError("TestAppError", "message", nil, "", http.StatusInternalServerError)
json := appErr.ToJSON()
err := AppErrorFromJSON(strings.NewReader(json))
rerr, ok := err.(*AppError)
require.True(t, ok)
require.Equal(t, appErr.Message, rerr.Message)
})
t.Run("Returned http.MaxBytesError", func(t *testing.T) {
aerr := (&http.MaxBytesError{}).Error() + "\n"
err := AppErrorFromJSON(strings.NewReader(aerr))
require.EqualError(t, err, "The request was too large. Consider asking your System Admin to raise the FileSettings.MaxFileSize setting.")
})
}
func TestCopyStringMap(t *testing.T) {
itemKey := "item1"
originalMap := make(map[string]string)
originalMap[itemKey] = "val1"
copyMap := CopyStringMap(originalMap)
copyMap[itemKey] = "changed"
assert.Equal(t, "val1", originalMap[itemKey])
}
2015-06-15 03:53:32 -04:00
func TestMapJson(t *testing.T) {
m := make(map[string]string)
m["id"] = "test_id"
[MM-22051] Remove To/From JSON (#18070) * Posts * Add missing translation * Fix internal store marshaling * [MM-22051] Remove To/From JSON (Channels) (#18116) * Channels * Channel members * ChannelSearch * Channel categories, list, sidebar, stats, view * Fix conversions * [MM-22051] Remove To/From JSON (Users) (#18121) * User related structs * Fix return * Team related structures (#18127) * [MM-22051] Remove To/From JSON (Status, Bot, Reaction, Thread, FileInfo) (#18130) * Status * Bot * Reaction * Thread * FileInfo * Some fixes * Translations update from Weblate (#18143) * Translated using Weblate (German) Currently translated at 100.0% (2309 of 2309 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/de/ * Translated using Weblate (Turkish) Currently translated at 100.0% (2309 of 2309 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/tr/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (2309 of 2309 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/hu/ * Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/ Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/ Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/ Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/ * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/de/ * Translated using Weblate (Turkish) Currently translated at 100.0% (2301 of 2301 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/tr/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (2301 of 2301 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/hu/ * Translated using Weblate (English (Australia)) Currently translated at 100.0% (2301 of 2301 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/en_AU/ * Translated using Weblate (Bulgarian) Currently translated at 100.0% (2301 of 2301 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/bg/ * Translated using Weblate (Japanese) Currently translated at 100.0% (2301 of 2301 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/ja/ * Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (2301 of 2301 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/zh_Hans/ Co-authored-by: JtheBAB <srast@bioc.uzh.ch> Co-authored-by: Kaya Zeren <kayazeren@gmail.com> Co-authored-by: Tóth Csaba // Online ERP Hungary Kft <csaba.toth@online-erp.hu> Co-authored-by: Matthew Williams <Matthew.Williams@outlook.com.au> Co-authored-by: Nikolai Zahariev <nikolaiz@yahoo.com> Co-authored-by: kaakaa <stooner.hoe@gmail.com> Co-authored-by: aeomin <lin@aeomin.net> Co-authored-by: Weblate (bot) <hosted@weblate.org> Co-authored-by: JtheBAB <srast@bioc.uzh.ch> Co-authored-by: Kaya Zeren <kayazeren@gmail.com> Co-authored-by: Tóth Csaba // Online ERP Hungary Kft <csaba.toth@online-erp.hu> Co-authored-by: Matthew Williams <Matthew.Williams@outlook.com.au> Co-authored-by: Nikolai Zahariev <nikolaiz@yahoo.com> Co-authored-by: kaakaa <stooner.hoe@gmail.com> Co-authored-by: aeomin <lin@aeomin.net> * [MM-22051] Remove To/From JSON methods from model (#18138) * Scheme * Role * Session * Config * Status * Fix logic * Emoji * GuestsInvite * Group * Command * ClusterInfo * License * Job * System * Plugin * Command2 * IncomingWebhook * OutgoingWebhook * Fix tests * Update traslation * Some fixes * Add missing return * Simplify * Make Config.ToJSONFiltered() return []byte * Make Busy.ToJSON() return []byte * Include error in log * Split logic * [MM-22051] Remove To/From JSON (final) (#18150) * SwitchRequest * PluginEventData * Permalink * PushNotification * SuggestCommand * PluginsResponse * WebSocketMessage * RemoteCluster * SharedChannel * PluginStatuses * InitialLoad * ClusterDiscovery * ClusterStats * MfaSecret * GroupSyncable * SAML * WebSocketRequest * TypingRequest * SecurityBulletin * OAuthApp * IntegrationAction * DataRetention * Preference * FileInfoList * Compliance * Preferences * FileInfoSearchResults * TermsOfService * InstallMarketplacePluginRequest * GitLabUser * UploadSessions * Remove unused helpers * Fix tests * [MM-23280] Fix linting for ToJSON/FromJSON (#18153) * SwitchRequest * PluginEventData * Permalink * PushNotification * SuggestCommand * PluginsResponse * WebSocketMessage * RemoteCluster * SharedChannel * PluginStatuses * InitialLoad * ClusterDiscovery * ClusterStats * MfaSecret * GroupSyncable * SAML * WebSocketRequest * TypingRequest * SecurityBulletin * OAuthApp * IntegrationAction * DataRetention * Preference * FileInfoList * Compliance * Preferences * FileInfoSearchResults * TermsOfService * InstallMarketplacePluginRequest * GitLabUser * UploadSessions * Remove unused helpers * Fix tests * Fix linting for ToJSON/FromJSON * Fix conversions Co-authored-by: Weblate (bot) <hosted@weblate.org> Co-authored-by: JtheBAB <srast@bioc.uzh.ch> Co-authored-by: Kaya Zeren <kayazeren@gmail.com> Co-authored-by: Tóth Csaba // Online ERP Hungary Kft <csaba.toth@online-erp.hu> Co-authored-by: Matthew Williams <Matthew.Williams@outlook.com.au> Co-authored-by: Nikolai Zahariev <nikolaiz@yahoo.com> Co-authored-by: kaakaa <stooner.hoe@gmail.com> Co-authored-by: aeomin <lin@aeomin.net> Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
2021-09-01 08:43:12 -04:00
json := MapToJSON(m)
2015-06-15 03:53:32 -04:00
[MM-22051] Remove To/From JSON (#18070) * Posts * Add missing translation * Fix internal store marshaling * [MM-22051] Remove To/From JSON (Channels) (#18116) * Channels * Channel members * ChannelSearch * Channel categories, list, sidebar, stats, view * Fix conversions * [MM-22051] Remove To/From JSON (Users) (#18121) * User related structs * Fix return * Team related structures (#18127) * [MM-22051] Remove To/From JSON (Status, Bot, Reaction, Thread, FileInfo) (#18130) * Status * Bot * Reaction * Thread * FileInfo * Some fixes * Translations update from Weblate (#18143) * Translated using Weblate (German) Currently translated at 100.0% (2309 of 2309 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/de/ * Translated using Weblate (Turkish) Currently translated at 100.0% (2309 of 2309 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/tr/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (2309 of 2309 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/hu/ * Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/ Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/ Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/ Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/ * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/de/ * Translated using Weblate (Turkish) Currently translated at 100.0% (2301 of 2301 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/tr/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (2301 of 2301 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/hu/ * Translated using Weblate (English (Australia)) Currently translated at 100.0% (2301 of 2301 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/en_AU/ * Translated using Weblate (Bulgarian) Currently translated at 100.0% (2301 of 2301 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/bg/ * Translated using Weblate (Japanese) Currently translated at 100.0% (2301 of 2301 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/ja/ * Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (2301 of 2301 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/zh_Hans/ Co-authored-by: JtheBAB <srast@bioc.uzh.ch> Co-authored-by: Kaya Zeren <kayazeren@gmail.com> Co-authored-by: Tóth Csaba // Online ERP Hungary Kft <csaba.toth@online-erp.hu> Co-authored-by: Matthew Williams <Matthew.Williams@outlook.com.au> Co-authored-by: Nikolai Zahariev <nikolaiz@yahoo.com> Co-authored-by: kaakaa <stooner.hoe@gmail.com> Co-authored-by: aeomin <lin@aeomin.net> Co-authored-by: Weblate (bot) <hosted@weblate.org> Co-authored-by: JtheBAB <srast@bioc.uzh.ch> Co-authored-by: Kaya Zeren <kayazeren@gmail.com> Co-authored-by: Tóth Csaba // Online ERP Hungary Kft <csaba.toth@online-erp.hu> Co-authored-by: Matthew Williams <Matthew.Williams@outlook.com.au> Co-authored-by: Nikolai Zahariev <nikolaiz@yahoo.com> Co-authored-by: kaakaa <stooner.hoe@gmail.com> Co-authored-by: aeomin <lin@aeomin.net> * [MM-22051] Remove To/From JSON methods from model (#18138) * Scheme * Role * Session * Config * Status * Fix logic * Emoji * GuestsInvite * Group * Command * ClusterInfo * License * Job * System * Plugin * Command2 * IncomingWebhook * OutgoingWebhook * Fix tests * Update traslation * Some fixes * Add missing return * Simplify * Make Config.ToJSONFiltered() return []byte * Make Busy.ToJSON() return []byte * Include error in log * Split logic * [MM-22051] Remove To/From JSON (final) (#18150) * SwitchRequest * PluginEventData * Permalink * PushNotification * SuggestCommand * PluginsResponse * WebSocketMessage * RemoteCluster * SharedChannel * PluginStatuses * InitialLoad * ClusterDiscovery * ClusterStats * MfaSecret * GroupSyncable * SAML * WebSocketRequest * TypingRequest * SecurityBulletin * OAuthApp * IntegrationAction * DataRetention * Preference * FileInfoList * Compliance * Preferences * FileInfoSearchResults * TermsOfService * InstallMarketplacePluginRequest * GitLabUser * UploadSessions * Remove unused helpers * Fix tests * [MM-23280] Fix linting for ToJSON/FromJSON (#18153) * SwitchRequest * PluginEventData * Permalink * PushNotification * SuggestCommand * PluginsResponse * WebSocketMessage * RemoteCluster * SharedChannel * PluginStatuses * InitialLoad * ClusterDiscovery * ClusterStats * MfaSecret * GroupSyncable * SAML * WebSocketRequest * TypingRequest * SecurityBulletin * OAuthApp * IntegrationAction * DataRetention * Preference * FileInfoList * Compliance * Preferences * FileInfoSearchResults * TermsOfService * InstallMarketplacePluginRequest * GitLabUser * UploadSessions * Remove unused helpers * Fix tests * Fix linting for ToJSON/FromJSON * Fix conversions Co-authored-by: Weblate (bot) <hosted@weblate.org> Co-authored-by: JtheBAB <srast@bioc.uzh.ch> Co-authored-by: Kaya Zeren <kayazeren@gmail.com> Co-authored-by: Tóth Csaba // Online ERP Hungary Kft <csaba.toth@online-erp.hu> Co-authored-by: Matthew Williams <Matthew.Williams@outlook.com.au> Co-authored-by: Nikolai Zahariev <nikolaiz@yahoo.com> Co-authored-by: kaakaa <stooner.hoe@gmail.com> Co-authored-by: aeomin <lin@aeomin.net> Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
2021-09-01 08:43:12 -04:00
rm := MapFromJSON(strings.NewReader(json))
2015-06-15 03:53:32 -04:00
require.Equal(t, rm["id"], "test_id", "map should be valid")
2015-06-15 03:53:32 -04:00
[MM-22051] Remove To/From JSON (#18070) * Posts * Add missing translation * Fix internal store marshaling * [MM-22051] Remove To/From JSON (Channels) (#18116) * Channels * Channel members * ChannelSearch * Channel categories, list, sidebar, stats, view * Fix conversions * [MM-22051] Remove To/From JSON (Users) (#18121) * User related structs * Fix return * Team related structures (#18127) * [MM-22051] Remove To/From JSON (Status, Bot, Reaction, Thread, FileInfo) (#18130) * Status * Bot * Reaction * Thread * FileInfo * Some fixes * Translations update from Weblate (#18143) * Translated using Weblate (German) Currently translated at 100.0% (2309 of 2309 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/de/ * Translated using Weblate (Turkish) Currently translated at 100.0% (2309 of 2309 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/tr/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (2309 of 2309 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/hu/ * Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/ Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/ Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/ Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/ * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/de/ * Translated using Weblate (Turkish) Currently translated at 100.0% (2301 of 2301 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/tr/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (2301 of 2301 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/hu/ * Translated using Weblate (English (Australia)) Currently translated at 100.0% (2301 of 2301 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/en_AU/ * Translated using Weblate (Bulgarian) Currently translated at 100.0% (2301 of 2301 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/bg/ * Translated using Weblate (Japanese) Currently translated at 100.0% (2301 of 2301 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/ja/ * Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (2301 of 2301 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/zh_Hans/ Co-authored-by: JtheBAB <srast@bioc.uzh.ch> Co-authored-by: Kaya Zeren <kayazeren@gmail.com> Co-authored-by: Tóth Csaba // Online ERP Hungary Kft <csaba.toth@online-erp.hu> Co-authored-by: Matthew Williams <Matthew.Williams@outlook.com.au> Co-authored-by: Nikolai Zahariev <nikolaiz@yahoo.com> Co-authored-by: kaakaa <stooner.hoe@gmail.com> Co-authored-by: aeomin <lin@aeomin.net> Co-authored-by: Weblate (bot) <hosted@weblate.org> Co-authored-by: JtheBAB <srast@bioc.uzh.ch> Co-authored-by: Kaya Zeren <kayazeren@gmail.com> Co-authored-by: Tóth Csaba // Online ERP Hungary Kft <csaba.toth@online-erp.hu> Co-authored-by: Matthew Williams <Matthew.Williams@outlook.com.au> Co-authored-by: Nikolai Zahariev <nikolaiz@yahoo.com> Co-authored-by: kaakaa <stooner.hoe@gmail.com> Co-authored-by: aeomin <lin@aeomin.net> * [MM-22051] Remove To/From JSON methods from model (#18138) * Scheme * Role * Session * Config * Status * Fix logic * Emoji * GuestsInvite * Group * Command * ClusterInfo * License * Job * System * Plugin * Command2 * IncomingWebhook * OutgoingWebhook * Fix tests * Update traslation * Some fixes * Add missing return * Simplify * Make Config.ToJSONFiltered() return []byte * Make Busy.ToJSON() return []byte * Include error in log * Split logic * [MM-22051] Remove To/From JSON (final) (#18150) * SwitchRequest * PluginEventData * Permalink * PushNotification * SuggestCommand * PluginsResponse * WebSocketMessage * RemoteCluster * SharedChannel * PluginStatuses * InitialLoad * ClusterDiscovery * ClusterStats * MfaSecret * GroupSyncable * SAML * WebSocketRequest * TypingRequest * SecurityBulletin * OAuthApp * IntegrationAction * DataRetention * Preference * FileInfoList * Compliance * Preferences * FileInfoSearchResults * TermsOfService * InstallMarketplacePluginRequest * GitLabUser * UploadSessions * Remove unused helpers * Fix tests * [MM-23280] Fix linting for ToJSON/FromJSON (#18153) * SwitchRequest * PluginEventData * Permalink * PushNotification * SuggestCommand * PluginsResponse * WebSocketMessage * RemoteCluster * SharedChannel * PluginStatuses * InitialLoad * ClusterDiscovery * ClusterStats * MfaSecret * GroupSyncable * SAML * WebSocketRequest * TypingRequest * SecurityBulletin * OAuthApp * IntegrationAction * DataRetention * Preference * FileInfoList * Compliance * Preferences * FileInfoSearchResults * TermsOfService * InstallMarketplacePluginRequest * GitLabUser * UploadSessions * Remove unused helpers * Fix tests * Fix linting for ToJSON/FromJSON * Fix conversions Co-authored-by: Weblate (bot) <hosted@weblate.org> Co-authored-by: JtheBAB <srast@bioc.uzh.ch> Co-authored-by: Kaya Zeren <kayazeren@gmail.com> Co-authored-by: Tóth Csaba // Online ERP Hungary Kft <csaba.toth@online-erp.hu> Co-authored-by: Matthew Williams <Matthew.Williams@outlook.com.au> Co-authored-by: Nikolai Zahariev <nikolaiz@yahoo.com> Co-authored-by: kaakaa <stooner.hoe@gmail.com> Co-authored-by: aeomin <lin@aeomin.net> Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
2021-09-01 08:43:12 -04:00
rm2 := MapFromJSON(strings.NewReader(""))
require.LessOrEqual(t, len(rm2), 0, "make should be invalid")
2015-06-15 03:53:32 -04:00
}
2024-01-09 12:04:16 -05:00
func TestSortedArrayFromJSON(t *testing.T) {
t.Run("Successful parse", func(t *testing.T) {
ids := []string{NewId(), NewId(), NewId()}
b, _ := json.Marshal(ids)
a, err := SortedArrayFromJSON(bytes.NewReader(b))
2024-01-09 12:04:16 -05:00
require.NoError(t, err)
require.ElementsMatch(t, ids, a)
})
t.Run("Empty Array", func(t *testing.T) {
ids := []string{}
b, _ := json.Marshal(ids)
a, err := SortedArrayFromJSON(bytes.NewReader(b))
2024-01-09 12:04:16 -05:00
require.NoError(t, err)
require.Empty(t, a)
})
t.Run("Duplicate keys, returns one", func(t *testing.T) {
var ids []string
id := NewId()
for range 10 {
2024-01-09 12:04:16 -05:00
ids = append(ids, id)
}
b, _ := json.Marshal(ids)
a, err := SortedArrayFromJSON(bytes.NewReader(b))
2024-01-09 12:04:16 -05:00
require.NoError(t, err)
require.Len(t, a, 1)
})
}
func TestNonSortedArrayFromJSON(t *testing.T) {
t.Run("Successful parse", func(t *testing.T) {
ids := []string{NewId(), NewId(), NewId()}
b, _ := json.Marshal(ids)
a, err := NonSortedArrayFromJSON(bytes.NewReader(b))
2024-01-09 12:04:16 -05:00
require.NoError(t, err)
require.Equal(t, ids, a)
})
t.Run("Empty Array", func(t *testing.T) {
ids := []string{}
b, _ := json.Marshal(ids)
a, err := NonSortedArrayFromJSON(bytes.NewReader(b))
2024-01-09 12:04:16 -05:00
require.NoError(t, err)
require.Empty(t, a)
})
t.Run("Duplicate keys, returns one", func(t *testing.T) {
var ids []string
id := NewId()
for i := 0; i <= 10; i++ {
ids = append(ids, id)
}
b, _ := json.Marshal(ids)
a, err := NonSortedArrayFromJSON(bytes.NewReader(b))
2024-01-09 12:04:16 -05:00
require.NoError(t, err)
require.Len(t, a, 1)
})
}
func TestIsValidEmail(t *testing.T) {
for _, testCase := range []struct {
Input string
Expected bool
}{
{
Input: "corey",
Expected: false,
},
{
Input: "corey@example.com",
Expected: true,
},
{
Input: "corey+test@example.com",
Expected: true,
},
{
Input: "@corey+test@example.com",
Expected: false,
},
{
Input: "firstname.lastname@example.com",
Expected: true,
},
{
Input: "firstname.lastname@subdomain.example.com",
Expected: true,
},
{
Input: "123454567@domain.com",
Expected: true,
},
{
Input: "email@domain-one.com",
Expected: true,
},
{
Input: "email@domain.co.jp",
Expected: true,
},
{
Input: "firstname-lastname@domain.com",
Expected: true,
},
{
Input: "@domain.com",
Expected: false,
},
{
Input: "Billy Bob <billy@example.com>",
Expected: false,
},
{
Input: "<billy@example.com>",
Expected: false,
},
{
Input: "email.domain.com",
Expected: false,
},
{
Input: "email.@domain.com",
Expected: false,
},
{
Input: "email@domain@domain.com",
Expected: false,
},
{
Input: "(email@domain.com)",
Expected: false,
},
{
Input: "email@汤.中国",
Expected: true,
},
{
Input: "email1@domain.com, email2@domain.com",
Expected: false,
},
{
Input: "\"attacker@attacker.com,admin\"@spaceship.com",
Expected: false,
},
{
Input: "(email)@domain.com",
Expected: false,
},
{
Input: "<email>@domain.com",
Expected: false,
},
{
Input: "[email]@domain.com",
Expected: false,
},
{
Input: "{email}@domain.com",
Expected: true,
},
{
Input: "first\"name@domain.com",
Expected: false,
},
{
Input: "first:name@domain.com",
Expected: false,
},
{
Input: "first;name@domain.com",
Expected: false,
},
{
Input: "first,name@domain.com",
Expected: false,
},
{
Input: "first@name@domain.com",
Expected: false,
},
{
Input: "john..doe@example.com",
Expected: false,
},
} {
t.Run(testCase.Input, func(t *testing.T) {
assert.Equal(t, testCase.Expected, IsValidEmail(testCase.Input))
})
2015-06-15 03:53:32 -04:00
}
}
func TestEtag(t *testing.T) {
etag := Etag("hello", 24)
require.NotEqual(t, "", etag)
2015-06-15 03:53:32 -04:00
}
var hashtags = map[string]string{
"#test": "#test",
"test": "",
"#test123": "#test123",
"#123test123": "",
"#test-test": "#test-test",
"#test?": "#test",
"hi #there": "#there",
"#bug #idea": "#bug #idea",
"#bug or #gif!": "#bug #gif",
"#hüllo": "#hüllo",
"#?test": "",
"#-test": "",
"#yo_yo": "#yo_yo",
"(#brackets)": "#brackets",
")#stekarb(": "#stekarb",
"<#less_than<": "#less_than",
">#greater_than>": "#greater_than",
"-#minus-": "#minus",
"_#under_": "#under",
"+#plus+": "#plus",
"=#equals=": "#equals",
"%#pct%": "#pct",
"&#and&": "#and",
"^#hat^": "#hat",
"##brown#": "#brown",
"*#star*": "#star",
"|#pipe|": "#pipe",
":#colon:": "#colon",
";#semi;": "#semi",
"#Mötley;": "#Mötley",
".#period.": "#period",
"¿#upside¿": "#upside",
"\"#quote\"": "#quote",
"/#slash/": "#slash",
"\\#backslash\\": "#backslash",
"#a": "",
"#1": "",
"foo#bar": "",
}
func TestStringArray_Equal(t *testing.T) {
for name, tc := range map[string]struct {
Array1 StringArray
Array2 StringArray
Expected bool
}{
"Empty": {
nil,
nil,
true,
},
"EqualLength_EqualValue": {
StringArray{"123"},
StringArray{"123"},
true,
},
"DifferentLength": {
StringArray{"123"},
StringArray{"123", "abc"},
false,
},
"DifferentValues_EqualLength": {
StringArray{"123"},
StringArray{"abc"},
false,
},
"EqualLength_EqualValues": {
StringArray{"123", "abc"},
StringArray{"123", "abc"},
true,
},
"EqualLength_EqualValues_DifferentOrder": {
StringArray{"abc", "123"},
StringArray{"123", "abc"},
false,
},
} {
t.Run(name, func(t *testing.T) {
assert.Equal(t, tc.Expected, tc.Array1.Equals(tc.Array2))
})
}
}
func TestParseHashtags(t *testing.T) {
t.Run("basic hashtag extraction", func(t *testing.T) {
for input, output := range hashtags {
o, _ := ParseHashtags(input)
require.Equal(t, o, output, "failed to parse hashtags from input="+input+" expected="+output+" actual="+o)
}
})
t.Run("long hashtag string truncation", func(t *testing.T) {
// Test case where hashtag string exceeds 1000 characters with a space to truncate at
longHashtags := "#test " + strings.Repeat("#verylonghashtag ", 50)
hashtagString, plainString := ParseHashtags(longHashtags)
require.NotEmpty(t, hashtagString)
require.LessOrEqual(t, len(hashtagString), 1000)
require.Empty(t, plainString)
// Ensure it truncated at a space
require.NotEqual(t, "", hashtagString)
require.True(t, hashtagString[len(hashtagString)-1] != ' ')
})
t.Run("long hashtag string truncation without spaces", func(t *testing.T) {
// Test case where hashtag string exceeds 1000 characters with no space after position 999
// Create a single very long hashtag that will be truncated
veryLongHashtag := "#" + strings.Repeat("a", 1010)
hashtagString, plainString := ParseHashtags(veryLongHashtag)
// Should be empty because no space was found to truncate at
require.Equal(t, "", hashtagString)
require.Empty(t, plainString)
})
t.Run("plain text extraction", func(t *testing.T) {
hashtagString, plainString := ParseHashtags("hello #world this is #test plain text")
require.Equal(t, "#world #test", hashtagString)
require.Equal(t, "hello this is plain text", plainString)
})
t.Run("only plain text", func(t *testing.T) {
hashtagString, plainString := ParseHashtags("no hashtags here")
require.Empty(t, hashtagString)
require.Equal(t, "no hashtags here", plainString)
})
t.Run("only hashtags", func(t *testing.T) {
hashtagString, plainString := ParseHashtags("#one #two #three")
require.Equal(t, "#one #two #three", hashtagString)
require.Empty(t, plainString)
})
t.Run("empty string", func(t *testing.T) {
hashtagString, plainString := ParseHashtags("")
require.Empty(t, hashtagString)
require.Empty(t, plainString)
})
}
func TestIsValidAlphaNum(t *testing.T) {
cases := []struct {
Input string
Result bool
}{
{
Input: "test",
Result: true,
},
{
Input: "test-name",
Result: true,
},
{
Input: "test--name",
Result: true,
},
{
Input: "test__name",
Result: true,
},
{
Input: "-",
Result: false,
},
{
Input: "__",
Result: false,
},
{
Input: "test-",
Result: false,
},
{
Input: "test--",
Result: false,
},
{
Input: "test__",
Result: false,
},
{
Input: "test:name",
Result: false,
},
}
for _, tc := range cases {
actual := isValidAlphaNum(tc.Input)
require.Equalf(t, actual, tc.Result, "case: %v\tshould returned: %#v", tc, tc.Result)
}
}
func TestGetServerIPAddress(t *testing.T) {
require.NotEmpty(t, GetServerIPAddress(""), "Should find local ip address")
}
func TestIsValidAlphaNumHyphenUnderscore(t *testing.T) {
casesWithFormat := []struct {
Input string
Result bool
}{
{
Input: "test",
Result: true,
},
{
Input: "test-name",
Result: true,
},
{
Input: "test--name",
Result: true,
},
{
Input: "test__name",
Result: true,
},
{
Input: "test_name",
Result: true,
},
{
Input: "test_-name",
Result: true,
},
{
Input: "-",
Result: false,
},
{
Input: "__",
Result: false,
},
{
Input: "test-",
Result: false,
},
{
Input: "test--",
Result: false,
},
{
Input: "test__",
Result: false,
},
{
Input: "test:name",
Result: false,
},
}
for _, tc := range casesWithFormat {
actual := IsValidAlphaNumHyphenUnderscore(tc.Input, true)
require.Equalf(t, actual, tc.Result, "case: %v\tshould returned: %#v", tc, tc.Result)
}
casesWithoutFormat := []struct {
Input string
Result bool
}{
{
Input: "test",
Result: true,
},
{
Input: "test-name",
Result: true,
},
{
Input: "test--name",
Result: true,
},
{
Input: "test__name",
Result: true,
},
{
Input: "test_name",
Result: true,
},
{
Input: "test_-name",
Result: true,
},
{
Input: "-",
Result: true,
},
{
Input: "_",
Result: true,
},
{
Input: "test-",
Result: true,
},
{
Input: "test--",
Result: true,
},
{
Input: "test__",
Result: true,
},
{
Input: ".",
Result: false,
},
{
Input: "test,",
Result: false,
},
{
Input: "test:name",
Result: false,
},
}
for _, tc := range casesWithoutFormat {
actual := IsValidAlphaNumHyphenUnderscore(tc.Input, false)
require.Equalf(t, actual, tc.Result, "case: '%v'\tshould returned: %#v", tc.Input, tc.Result)
}
}
func TestIsValidAlphaNumHyphenUnderscorePlus(t *testing.T) {
cases := []struct {
Input string
Result bool
}{
{
Input: "test",
Result: true,
},
{
Input: "test+name",
Result: true,
},
{
Input: "test+-name",
Result: true,
},
{
Input: "test_+name",
Result: true,
},
{
Input: "test++name",
Result: true,
},
{
Input: "test_-name",
Result: true,
},
{
Input: "-",
Result: true,
},
{
Input: "_",
Result: true,
},
{
Input: "+",
Result: true,
},
{
Input: "test+",
Result: true,
},
{
Input: "test++",
Result: true,
},
{
Input: "test--",
Result: true,
},
{
Input: "test__",
Result: true,
},
{
Input: ".",
Result: false,
},
{
Input: "test,",
Result: false,
},
{
Input: "test:name",
Result: false,
},
}
for _, tc := range cases {
actual := IsValidAlphaNumHyphenUnderscorePlus(tc.Input)
require.Equalf(t, actual, tc.Result, "case: '%v'\tshould returned: %#v", tc.Input, tc.Result)
}
}
func TestIsValidId(t *testing.T) {
cases := []struct {
Input string
Result bool
}{
{
Input: NewId(),
Result: true,
},
{
Input: "",
Result: false,
},
{
Input: "junk",
Result: false,
},
{
Input: "qwertyuiop1234567890asdfg{",
Result: false,
},
{
Input: NewId() + "}",
Result: false,
},
}
for _, tc := range cases {
actual := IsValidId(tc.Input)
require.Equalf(t, actual, tc.Result, "case: %v\tshould returned: %#v", tc, tc.Result)
}
}
func TestNowhereNil(t *testing.T) {
t.Parallel()
var nilStringPtr *string
var nonNilStringPtr = new(string)
var nilSlice []string
var nilStruct *struct{}
var nilMap map[bool]bool
var nowhereNilStruct = struct {
X *string
Y *string
}{
nonNilStringPtr,
nonNilStringPtr,
}
var somewhereNilStruct = struct {
X *string
Y *string
}{
nonNilStringPtr,
nilStringPtr,
}
var privateSomewhereNilStruct = struct {
X *string
y *string
}{
nonNilStringPtr,
nilStringPtr,
}
testCases := []struct {
Description string
Value any
Expected bool
}{
{
"nil",
nil,
false,
},
{
"empty string",
"",
true,
},
{
"non-empty string",
"not empty!",
true,
},
{
"nil string pointer",
nilStringPtr,
false,
},
{
"non-nil string pointer",
nonNilStringPtr,
true,
},
{
"0",
0,
true,
},
{
"1",
1,
true,
},
{
"0 (int64)",
int64(0),
true,
},
{
"1 (int64)",
int64(1),
true,
},
{
"true",
true,
true,
},
{
"false",
false,
true,
},
{
"nil slice",
nilSlice,
// A nil slice is observably the same as an empty slice, so allow it.
true,
},
{
"empty slice",
[]string{},
true,
},
{
"slice containing nils",
[]*string{nil, nil},
true,
},
{
"nil map",
nilMap,
false,
},
{
"non-nil map",
make(map[bool]bool),
true,
},
{
"non-nil map containing nil",
map[bool]*string{true: nilStringPtr, false: nonNilStringPtr},
// Map values are not checked
true,
},
{
"nil struct",
nilStruct,
false,
},
{
"empty struct",
struct{}{},
true,
},
{
"struct containing no nil",
nowhereNilStruct,
true,
},
{
"struct containing nil",
somewhereNilStruct,
false,
},
{
"struct pointer containing no nil",
&nowhereNilStruct,
true,
},
{
"struct pointer containing nil",
&somewhereNilStruct,
false,
},
{
"struct containing private nil",
privateSomewhereNilStruct,
true,
},
{
"struct pointer containing private nil",
&privateSomewhereNilStruct,
true,
},
}
for _, testCase := range testCases {
t.Run(testCase.Description, func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Errorf("panic: %v", r)
}
}()
t.Parallel()
require.Equal(t, testCase.Expected, checkNowhereNil(t, "value", testCase.Value))
})
}
}
// checkNowhereNil checks that the given interface value is not nil, and if a struct, that all of
// its public fields are also nowhere nil
func checkNowhereNil(t *testing.T, name string, value any) bool {
if value == nil {
return false
}
v := reflect.ValueOf(value)
switch v.Type().Kind() {
case reflect.Ptr:
// Ignoring these 2 settings.
// TODO: remove them completely in v8.0.
if name == "config.ElasticsearchSettings.BulkIndexingTimeWindowSeconds" ||
name == "config.ClusterSettings.EnableExperimentalGossipEncryption" {
return true
}
if v.IsNil() {
t.Logf("%s was nil", name)
return false
}
return checkNowhereNil(t, fmt.Sprintf("(*%s)", name), v.Elem().Interface())
case reflect.Map:
if v.IsNil() {
t.Logf("%s was nil", name)
return false
}
// Don't check map values
return true
case reflect.Struct:
nowhereNil := true
for i := 0; i < v.NumField(); i++ {
f := v.Field(i)
// Ignore unexported fields
if v.Type().Field(i).PkgPath != "" {
continue
}
nowhereNil = nowhereNil && checkNowhereNil(t, fmt.Sprintf("%s.%s", name, v.Type().Field(i).Name), f.Interface())
}
return nowhereNil
case reflect.Array:
fallthrough
case reflect.Chan:
fallthrough
case reflect.Func:
fallthrough
case reflect.Interface:
fallthrough
case reflect.UnsafePointer:
t.Logf("unhandled field %s, type: %s", name, v.Type().Kind())
return false
default:
return true
}
}
func TestSanitizeUnicode(t *testing.T) {
buf := bytes.Buffer{}
buf.WriteString("Hello")
buf.WriteRune(0x1d173)
buf.WriteRune(0x1d17a)
buf.WriteString(" there.")
musicArg := buf.String()
musicWant := "Hello there."
tests := []struct {
name string
arg string
want string
}{
{name: "empty string", arg: "", want: ""},
{name: "ascii only", arg: "Hello There", want: "Hello There"},
{name: "allowed unicode", arg: "Ādam likes Iñtërnâtiônàližætiøn", want: "Ādam likes Iñtërnâtiônàližætiøn"},
{name: "allowed unicode escaped", arg: "\u00eaI like hats\u00e2", want: "êI like hatsâ"},
{name: "blocklist char, don't reverse string", arg: "\u202E2resu", want: "2resu"},
{name: "blocklist chars, scoping musical notation", arg: musicArg, want: musicWant},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := SanitizeUnicode(tt.arg)
assert.Equal(t, tt.want, got)
})
}
}
func TestIsValidChannelIdentifier(t *testing.T) {
cases := []struct {
Description string
Input string
Expected bool
}{
{
Description: "less than min length",
Input: "",
Expected: false,
},
{
Description: "single alphabetical char",
Input: "a",
Expected: true,
},
{
Description: "single underscore",
Input: "_",
Expected: false,
},
{
Description: "single hyphen",
Input: "-",
Expected: false,
},
{
Description: "empty string",
Input: " ",
Expected: false,
},
{
Description: "multiple with hyphen",
Input: "a-a",
Expected: true,
},
{
Description: "multiple with hyphen",
Input: "a_a",
Expected: true,
},
}
for _, tc := range cases {
actual := IsValidChannelIdentifier(tc.Input)
require.Equalf(t, actual, tc.Expected, "case: '%v'\tshould returned: %#v", tc.Input, tc.Expected)
}
}
func TestIsValidHTTPURL(t *testing.T) {
t.Parallel()
testCases := []struct {
Description string
Value string
Expected bool
}{
{
"empty url",
"",
false,
},
{
"bad url",
"bad url",
false,
},
{
"relative url",
"/api/test",
false,
},
{
"relative url ending with slash",
"/some/url/",
false,
},
{
"url with invalid scheme",
"http-bad://mattermost.com",
false,
},
{
"url with just http",
"http://",
false,
},
{
"url with just https",
"https://",
false,
},
{
"url with extra slashes",
"https:///mattermost.com",
false,
},
{
"correct url with http scheme",
"http://mattermost.com",
true,
},
{
"correct url with https scheme",
"https://mattermost.com/api/test",
true,
},
{
"correct url with port",
"https://localhost:8080/test",
true,
},
{
"correct url without scheme",
"mattermost.com/some/url/",
false,
},
{
"correct url with extra slashes",
"https://mattermost.com/some//url",
true,
},
}
for _, testCase := range testCases {
t.Run(testCase.Description, func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Errorf("panic: %v", r)
}
}()
t.Parallel()
require.Equal(t, testCase.Expected, IsValidHTTPURL(testCase.Value))
})
}
}
All Sections to SubSections (#16917) * initial * Revert "initial" This reverts commit 3d631aeecdc2324cd5d17c0ecdc431a8ccc15060. * [MM-32352] Add Experimental Subsections BACKEND (#16887) Automatic Merge * update appiface * Fix app layers * Ancillary Permissions on backend (#17061) Automatic Merge * [MM-32799] Add About Section (#17015) * Add About Section * add mock key * Update role.go * Update role.go Co-authored-by: Mattermod <mattermod@users.noreply.github.com> * [MM-33437] Fix config access tags for experimental settings (#17111) Automatic Merge * [MM-32794] Reporting Sub Section (#17035) * test * revert * add permissions * add new permission stuff * add store mock * fix bad merge * gofmt fix Co-authored-by: Mattermod <mattermod@users.noreply.github.com> * [MM-32343] Environment SubSection (#17054) * pre-checkout commit * fix permission for testSiteURL * pre-merge commit * increase size of Permissions column in Roles table * add entry for ENVIRONMENT to testlib/store.go * use TEXT for Permissions column in Roles table * use environment subsection permissions for API endpoints * use subsections permissions for /config/environment * add suggestions from hahmadia * update tests to use subsection permissions * add permissions column back in * comment out code in upgradeDatabaseToVersion534 Co-authored-by: Mattermod <mattermod@users.noreply.github.com> Co-authored-by: Scott Bishel <scott.bishel@mattermost.com> * MM-32351: Add Compliance Subsections (#17023) * add subsections for compliance sectin * add to mock functions * updates for read job * fixes * fix test * update tests * update tests * another test fix * some cleanup * update mlog * fix linting * Fix bad merges Co-authored-by: Mattermod <mattermod@users.noreply.github.com> Co-authored-by: Hossein <hahmadia@users.noreply.github.com> Co-authored-by: Hossein Ahmadian-Yazdi <hyazdi1997@gmail.com> * MM-32347 Site Subsections (#17095) * Init * Added migration key in testlib store * Fix syntax error * fix bad merge * fix lint Co-authored-by: Mattermod <mattermod@users.noreply.github.com> Co-authored-by: Scott Bishel <scott.bishel@mattermost.com> * MM-32350 Integrations (#17097) * implement server subsections * fix tests * update test * go fmt Co-authored-by: Hossein Ahmadian-Yazdi <hyazdi1997@gmail.com> * patch forgotten endpoints * Adding subsection permissions for Authentication (#17087) * adding new permissions, migrations to do * permission migrations and ancilary permissions * running make app-layers * fixing tests and lint * adding permissions to saml * ldap write permissions * running make app-layers * fixing conflict * making app layers * clean up and fix tests * change job type * fix js error, if site url not returned Co-authored-by: Benjamin Cooke <benjamincooke@Benjamins-MacBook-Pro.local> Co-authored-by: Hossein Ahmadian-Yazdi <hyazdi1997@gmail.com> Co-authored-by: Mattermod <mattermod@users.noreply.github.com> Co-authored-by: Scott Bishel <scott.bishel@mattermost.com> * Update permissions_migrations.go * gofmt * upgrade to 535 * gofmt Co-authored-by: Mattermod <mattermod@users.noreply.github.com> Co-authored-by: Max Erenberg <max.erenberg@mattermost.com> Co-authored-by: Scott Bishel <scott.bishel@mattermost.com> Co-authored-by: Anurag Shivarathri <anurag6713@gmail.com> Co-authored-by: Ben Cooke <benkcooke@gmail.com> Co-authored-by: Benjamin Cooke <benjamincooke@Benjamins-MacBook-Pro.local>
2021-04-06 10:39:48 -04:00
func TestRemoveDuplicateStrings(t *testing.T) {
All Sections to SubSections (#16917) * initial * Revert "initial" This reverts commit 3d631aeecdc2324cd5d17c0ecdc431a8ccc15060. * [MM-32352] Add Experimental Subsections BACKEND (#16887) Automatic Merge * update appiface * Fix app layers * Ancillary Permissions on backend (#17061) Automatic Merge * [MM-32799] Add About Section (#17015) * Add About Section * add mock key * Update role.go * Update role.go Co-authored-by: Mattermod <mattermod@users.noreply.github.com> * [MM-33437] Fix config access tags for experimental settings (#17111) Automatic Merge * [MM-32794] Reporting Sub Section (#17035) * test * revert * add permissions * add new permission stuff * add store mock * fix bad merge * gofmt fix Co-authored-by: Mattermod <mattermod@users.noreply.github.com> * [MM-32343] Environment SubSection (#17054) * pre-checkout commit * fix permission for testSiteURL * pre-merge commit * increase size of Permissions column in Roles table * add entry for ENVIRONMENT to testlib/store.go * use TEXT for Permissions column in Roles table * use environment subsection permissions for API endpoints * use subsections permissions for /config/environment * add suggestions from hahmadia * update tests to use subsection permissions * add permissions column back in * comment out code in upgradeDatabaseToVersion534 Co-authored-by: Mattermod <mattermod@users.noreply.github.com> Co-authored-by: Scott Bishel <scott.bishel@mattermost.com> * MM-32351: Add Compliance Subsections (#17023) * add subsections for compliance sectin * add to mock functions * updates for read job * fixes * fix test * update tests * update tests * another test fix * some cleanup * update mlog * fix linting * Fix bad merges Co-authored-by: Mattermod <mattermod@users.noreply.github.com> Co-authored-by: Hossein <hahmadia@users.noreply.github.com> Co-authored-by: Hossein Ahmadian-Yazdi <hyazdi1997@gmail.com> * MM-32347 Site Subsections (#17095) * Init * Added migration key in testlib store * Fix syntax error * fix bad merge * fix lint Co-authored-by: Mattermod <mattermod@users.noreply.github.com> Co-authored-by: Scott Bishel <scott.bishel@mattermost.com> * MM-32350 Integrations (#17097) * implement server subsections * fix tests * update test * go fmt Co-authored-by: Hossein Ahmadian-Yazdi <hyazdi1997@gmail.com> * patch forgotten endpoints * Adding subsection permissions for Authentication (#17087) * adding new permissions, migrations to do * permission migrations and ancilary permissions * running make app-layers * fixing tests and lint * adding permissions to saml * ldap write permissions * running make app-layers * fixing conflict * making app layers * clean up and fix tests * change job type * fix js error, if site url not returned Co-authored-by: Benjamin Cooke <benjamincooke@Benjamins-MacBook-Pro.local> Co-authored-by: Hossein Ahmadian-Yazdi <hyazdi1997@gmail.com> Co-authored-by: Mattermod <mattermod@users.noreply.github.com> Co-authored-by: Scott Bishel <scott.bishel@mattermost.com> * Update permissions_migrations.go * gofmt * upgrade to 535 * gofmt Co-authored-by: Mattermod <mattermod@users.noreply.github.com> Co-authored-by: Max Erenberg <max.erenberg@mattermost.com> Co-authored-by: Scott Bishel <scott.bishel@mattermost.com> Co-authored-by: Anurag Shivarathri <anurag6713@gmail.com> Co-authored-by: Ben Cooke <benkcooke@gmail.com> Co-authored-by: Benjamin Cooke <benjamincooke@Benjamins-MacBook-Pro.local>
2021-04-06 10:39:48 -04:00
cases := []struct {
Input []string
Result []string
}{
{
Input: []string{"1", "2", "3", "3", "3"},
Result: []string{"1", "2", "3"},
},
{
Input: []string{"1", "2", "3", "4", "5"},
Result: []string{"1", "2", "3", "4", "5"},
},
{
Input: []string{"1", "1", "1", "3", "3"},
Result: []string{"1", "3"},
},
{
Input: []string{"1", "1", "1", "1", "1"},
Result: []string{"1"},
},
{
Input: []string{},
Result: []string{},
},
}
for _, tc := range cases {
actual := RemoveDuplicateStrings(tc.Input)
All Sections to SubSections (#16917) * initial * Revert "initial" This reverts commit 3d631aeecdc2324cd5d17c0ecdc431a8ccc15060. * [MM-32352] Add Experimental Subsections BACKEND (#16887) Automatic Merge * update appiface * Fix app layers * Ancillary Permissions on backend (#17061) Automatic Merge * [MM-32799] Add About Section (#17015) * Add About Section * add mock key * Update role.go * Update role.go Co-authored-by: Mattermod <mattermod@users.noreply.github.com> * [MM-33437] Fix config access tags for experimental settings (#17111) Automatic Merge * [MM-32794] Reporting Sub Section (#17035) * test * revert * add permissions * add new permission stuff * add store mock * fix bad merge * gofmt fix Co-authored-by: Mattermod <mattermod@users.noreply.github.com> * [MM-32343] Environment SubSection (#17054) * pre-checkout commit * fix permission for testSiteURL * pre-merge commit * increase size of Permissions column in Roles table * add entry for ENVIRONMENT to testlib/store.go * use TEXT for Permissions column in Roles table * use environment subsection permissions for API endpoints * use subsections permissions for /config/environment * add suggestions from hahmadia * update tests to use subsection permissions * add permissions column back in * comment out code in upgradeDatabaseToVersion534 Co-authored-by: Mattermod <mattermod@users.noreply.github.com> Co-authored-by: Scott Bishel <scott.bishel@mattermost.com> * MM-32351: Add Compliance Subsections (#17023) * add subsections for compliance sectin * add to mock functions * updates for read job * fixes * fix test * update tests * update tests * another test fix * some cleanup * update mlog * fix linting * Fix bad merges Co-authored-by: Mattermod <mattermod@users.noreply.github.com> Co-authored-by: Hossein <hahmadia@users.noreply.github.com> Co-authored-by: Hossein Ahmadian-Yazdi <hyazdi1997@gmail.com> * MM-32347 Site Subsections (#17095) * Init * Added migration key in testlib store * Fix syntax error * fix bad merge * fix lint Co-authored-by: Mattermod <mattermod@users.noreply.github.com> Co-authored-by: Scott Bishel <scott.bishel@mattermost.com> * MM-32350 Integrations (#17097) * implement server subsections * fix tests * update test * go fmt Co-authored-by: Hossein Ahmadian-Yazdi <hyazdi1997@gmail.com> * patch forgotten endpoints * Adding subsection permissions for Authentication (#17087) * adding new permissions, migrations to do * permission migrations and ancilary permissions * running make app-layers * fixing tests and lint * adding permissions to saml * ldap write permissions * running make app-layers * fixing conflict * making app layers * clean up and fix tests * change job type * fix js error, if site url not returned Co-authored-by: Benjamin Cooke <benjamincooke@Benjamins-MacBook-Pro.local> Co-authored-by: Hossein Ahmadian-Yazdi <hyazdi1997@gmail.com> Co-authored-by: Mattermod <mattermod@users.noreply.github.com> Co-authored-by: Scott Bishel <scott.bishel@mattermost.com> * Update permissions_migrations.go * gofmt * upgrade to 535 * gofmt Co-authored-by: Mattermod <mattermod@users.noreply.github.com> Co-authored-by: Max Erenberg <max.erenberg@mattermost.com> Co-authored-by: Scott Bishel <scott.bishel@mattermost.com> Co-authored-by: Anurag Shivarathri <anurag6713@gmail.com> Co-authored-by: Ben Cooke <benkcooke@gmail.com> Co-authored-by: Benjamin Cooke <benjamincooke@Benjamins-MacBook-Pro.local>
2021-04-06 10:39:48 -04:00
require.Equalf(t, actual, tc.Result, "case: %v\tshould returned: %#v", tc, tc.Result)
}
}
func TestStructFromJSONLimited(t *testing.T) {
t.Run("successfully parses basic struct", func(t *testing.T) {
type TestStruct struct {
StringField string
IntField int
FloatField float32
BoolField bool
}
testStruct := TestStruct{
StringField: "string",
IntField: 2,
FloatField: 3.1415,
BoolField: true,
}
testStructBytes, err := json.Marshal(testStruct)
require.NoError(t, err)
b := &TestStruct{}
err = StructFromJSONLimited(bytes.NewReader(testStructBytes), b)
require.NoError(t, err)
require.Equal(t, b.StringField, "string")
require.Equal(t, b.IntField, 2)
require.Equal(t, b.FloatField, float32(3.1415))
require.Equal(t, b.BoolField, true)
})
t.Run("successfully parses nested struct", func(t *testing.T) {
type TestStruct struct {
StringField string
IntField int
FloatField float32
BoolField bool
}
type NestedStruct struct {
FieldA TestStruct
FieldB TestStruct
FieldC []int
}
testStructA := TestStruct{
StringField: "string A",
IntField: 2,
FloatField: 3.1415,
BoolField: true,
}
testStructB := TestStruct{
StringField: "string B",
IntField: 3,
FloatField: 100,
BoolField: false,
}
nestedStruct := NestedStruct{
FieldA: testStructA,
FieldB: testStructB,
FieldC: []int{5, 9, 1, 5, 7},
}
nestedStructBytes, err := json.Marshal(nestedStruct)
require.NoError(t, err)
b := &NestedStruct{}
err = StructFromJSONLimited(bytes.NewReader(nestedStructBytes), b)
require.NoError(t, err)
require.Equal(t, b.FieldA.StringField, "string A")
require.Equal(t, b.FieldA.IntField, 2)
require.Equal(t, b.FieldA.FloatField, float32(3.1415))
require.Equal(t, b.FieldA.BoolField, true)
require.Equal(t, b.FieldB.StringField, "string B")
require.Equal(t, b.FieldB.IntField, 3)
require.Equal(t, b.FieldB.FloatField, float32(100))
require.Equal(t, b.FieldB.BoolField, false)
require.Equal(t, b.FieldC, []int{5, 9, 1, 5, 7})
})
t.Run("handles empty structs", func(t *testing.T) {
type TestStruct struct{}
testStruct := TestStruct{}
testStructBytes, err := json.Marshal(testStruct)
require.NoError(t, err)
b := &TestStruct{}
err = StructFromJSONLimited(bytes.NewReader(testStructBytes), b)
require.NoError(t, err)
})
}