mirror of
https://github.com/hanzoai/team.git
synced 2026-09-30 01:57:35 +00:00
* ci: shard server Postgres tests into 4 parallel runners (#35739) Cherry-pick of00296f9b49from master. * updated go to version 1.25.8 (#35817) Cherry-pick of32a10bac62from master. * Move password hashers from server/v8 to server/public (#35805) Cherry-pick ofcca3f08574from master. * Generate instead of hard-coding test passwords, enforce new minimum for FIPS, shard CI, fix FIPS builds (#35905) Cherry-pick of1bdd985b41from master. * upgrade golangci-lint (#35845) Cherry-pick of157e0400b2from master. On release-11.4 (unlike 11.5), UpdatePostsChannelTypeByChannelId and BackfillPostsChannelType exist in the elasticsearch/opensearch files, so the imports they require (fmt, updatebyquery, scriptlanguage) must be added — they were not in the cherry-pick diff since they already existed on master. Also updates html2text/tablewriter/olekukonko deps to fix a workspace conflict where enterprise's Go 1.25.8 bump pulled in a newer html2text that requires tablewriter ≥ 1.1 (was pinned to 0.0.5 via a replace directive). Matches the subset of866f759e4b(Mm 66662 bump deps) relevant to this incompatibility. * Fix FIPS-incompatible passwords and config in e2e test suites (#36001) Cherry-pick ofb51b4a8937from master. release-11.4 differences vs release-11.5: - demo_plugin_installation.spec.ts also deleted (modify/delete conflict, git rm) - authentication_2_spec.ts conflict: HEAD missing check() call; took incoming (check + FIPS-length passwords) - member_invitation_ui_spec.ts: HEAD has 'Create Account' (capital A) matching release-11.4 button text; kept HEAD's button text with incoming's newTestPassword() * fix(cypress): demo plugin (#36056) Cherry-pick of39f1979aa5from master. demo_plugin_installation.spec.ts was deleted in step 10 (modify/delete); re-created here with both the FIPS-password change and the URL fix. * test: clean up channel store data after TestChannelStore (#36066) TestChannelStore sub-tests create channels, members, and team members using fake TeamIds and UserIds (model.NewId() for non-existent rows). These records are left in the database and cause integrity tests (TestCheck*) running in the same binary to fail their full-table scans. Register a t.Cleanup on TestChannelStore that purges the affected tables entirely. A blanket purge is safe: the schema enforces no FK constraints, and every test suite creates its own data independently. * Fix command injection in server-test-template workflow (#36080) Cherry-pick of9223935f16from master. * fix(ci): restore testname format in sharded gotestsum runs (#36078) run-shard-tests.sh called gotestsum directly without --format, so it fell back to gotestsum's default (pkgname) instead of the testname format set by the Makefile. Pass --format "${GOTESTSUM_FORMAT:-testname}" to match the Makefile default. Co-authored-by: Mattermost Build <[email protected]> * fixup: drop demo_plugin playwright specs — master-only APIs demo_plugin/helpers.ts and demo_plugin_installation.spec.ts use installAndEnablePlugin and isPluginActive which don't exist on release-11.4's PlaywrightExtended type. These files were re-created by the step-11 cherry-pick of39f1979aa5, but they don't compile on this branch (same class of problem as actions.spec.ts in step 10). * fixup: add missing await in PluginLinkTooltip test The test added in39f1979aa5is missing an await on renderWithContext, causing the pointer-events assertion to race. Fix from 0c7d3f27c6 (on a feature branch, not yet on master). * fixup: drop pointer-events test incompatible with jsdom@20 The 'should not block interaction with elements outside the tooltip' test checks getComputedStyle for pointer-events: none, which is set only in SCSS. release-11.4 uses jest-environment-jsdom@29 (jsdom@20), which does not apply stylesheets, so getComputedStyle always returns "". The test passes on release-11.5+ only because they use jest-environment-jsdom@30 (jsdom@25+). Drop the test rather than backport the jsdom upgrade. * fixup: add missing i18n keys for elasticsearch/opensearch functions BackfillPostsChannelType and UpdatePostsChannelTypeByChannelId exist on release-11.4 (unlike release-11.5+). The golangci-lint cherry-pick added new error strings to those functions referencing i18n keys that weren't in en.json. * fixup: run make i18n-extract to reorder keys correctly * fixup: drop terms-and-privacy checkbox from MM-T1774 on release-11.4 The #signup-body-card-form-check-terms-and-privacy element did not exist on release-11.4's signup page. It was added to master after this branch was cut, so the check() call from the incoming cherry-pick causes the test to fail with "element never found". * fixup: remove UpdatePostsChannelTypeByChannelId/BackfillPostsChannelType These functions were introduced by MM-67540 (allow searching public channel messages without channel membership), which never landed on release-11.4. The golangci-lint cherry-pick only modernizes existing code; the rerere resolution incorrectly added the full function bodies from master. Remove both functions and their now-unused imports (fmt, updatebyquery, scriptlanguage) from elasticsearch.go and opensearch.go. Also remove the two i18n keys added to support them. Same treatment as release-11.5, where these functions were also absent. --------- Co-authored-by: Mattermost Build <[email protected]>
469 lines
19 KiB
Go
469 lines
19 KiB
Go
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
package web
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/mattermost/mattermost/server/public/model"
|
|
"github.com/mattermost/mattermost/server/public/plugin"
|
|
"github.com/mattermost/mattermost/server/public/plugin/utils"
|
|
"github.com/mattermost/mattermost/server/public/shared/mlog"
|
|
"github.com/mattermost/mattermost/server/public/shared/request"
|
|
"github.com/mattermost/mattermost/server/v8/channels/app"
|
|
"github.com/mattermost/mattermost/server/v8/channels/store/storetest/mocks"
|
|
"github.com/mattermost/mattermost/server/v8/config"
|
|
)
|
|
|
|
var apiClient *model.Client4
|
|
var URL string
|
|
|
|
type TestHelper struct {
|
|
App *app.App
|
|
Context request.CTX
|
|
Server *app.Server
|
|
Web *Web
|
|
|
|
BasicUser *model.User
|
|
BasicChannel *model.Channel
|
|
BasicTeam *model.Team
|
|
|
|
SystemAdminUser *model.User
|
|
|
|
tempWorkspace string
|
|
|
|
IncludeCacheLayer bool
|
|
|
|
TestLogger *mlog.Logger
|
|
}
|
|
|
|
func SetupWithStoreMock(tb testing.TB) *TestHelper {
|
|
if testing.Short() {
|
|
tb.SkipNow()
|
|
}
|
|
|
|
th := setupTestHelper(tb, false, nil)
|
|
emptyMockStore := mocks.Store{}
|
|
emptyMockStore.On("Close").Return(nil)
|
|
th.App.Srv().SetStore(&emptyMockStore)
|
|
return th
|
|
}
|
|
|
|
func Setup(tb testing.TB) *TestHelper {
|
|
if testing.Short() {
|
|
tb.SkipNow()
|
|
}
|
|
store := mainHelper.GetStore()
|
|
store.DropAllTables()
|
|
return setupTestHelper(tb, true, nil)
|
|
}
|
|
|
|
func setupTestHelper(tb testing.TB, includeCacheLayer bool, options []app.Option) *TestHelper {
|
|
memoryStore := config.NewTestMemoryStore()
|
|
newConfig := memoryStore.Get().Clone()
|
|
newConfig.SqlSettings = *mainHelper.GetSQLSettings()
|
|
*newConfig.AnnouncementSettings.AdminNoticesEnabled = false
|
|
*newConfig.AnnouncementSettings.UserNoticesEnabled = false
|
|
*newConfig.PluginSettings.AutomaticPrepackagedPlugins = false
|
|
*newConfig.LogSettings.EnableSentry = false // disable error reporting during tests
|
|
*newConfig.LogSettings.ConsoleJson = false
|
|
|
|
// Check for environment variable override for console log level (useful for debugging tests)
|
|
consoleLevel := os.Getenv("MM_LOGSETTINGS_CONSOLELEVEL")
|
|
if consoleLevel == "" {
|
|
consoleLevel = mlog.LvlStdLog.Name
|
|
}
|
|
*newConfig.LogSettings.ConsoleLevel = consoleLevel
|
|
|
|
_, _, err := memoryStore.Set(newConfig)
|
|
require.NoError(tb, err)
|
|
options = append(options, app.ConfigStore(memoryStore))
|
|
if includeCacheLayer {
|
|
// Adds the cache layer to the test store
|
|
options = append(options, app.StoreOverrideWithCache(mainHelper.Store))
|
|
} else {
|
|
options = append(options, app.StoreOverride(mainHelper.Store))
|
|
}
|
|
|
|
testLogger, err := mlog.NewLogger()
|
|
require.NoError(tb, err)
|
|
logCfg, err := config.MloggerConfigFromLoggerConfig(&newConfig.LogSettings, nil, config.GetLogFileLocation)
|
|
require.NoError(tb, err)
|
|
err = testLogger.ConfigureTargets(logCfg, nil)
|
|
require.NoError(tb, err, "failed to configure test logger")
|
|
// lock logger config so server init cannot override it during testing.
|
|
testLogger.LockConfiguration()
|
|
options = append(options, app.SetLogger(testLogger))
|
|
|
|
s, err := app.NewServer(options...)
|
|
require.NoError(tb, err)
|
|
|
|
a := app.New(app.ServerConnector(s.Channels()))
|
|
prevListenAddress := *s.Config().ServiceSettings.ListenAddress
|
|
a.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = "localhost:0" })
|
|
err = s.Start()
|
|
require.NoError(tb, err)
|
|
a.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = prevListenAddress })
|
|
|
|
web := New(s)
|
|
URL = fmt.Sprintf("http://localhost:%v", s.ListenAddr.Port)
|
|
apiClient = model.NewAPIv4Client(URL)
|
|
|
|
s.Store().MarkSystemRanUnitTests()
|
|
|
|
a.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.TeamSettings.EnableOpenServer = true
|
|
})
|
|
|
|
th := &TestHelper{
|
|
App: a,
|
|
Context: request.EmptyContext(testLogger),
|
|
Server: s,
|
|
Web: web,
|
|
IncludeCacheLayer: includeCacheLayer,
|
|
TestLogger: testLogger,
|
|
}
|
|
|
|
tb.Cleanup(func() {
|
|
if th.IncludeCacheLayer {
|
|
// Clean all the caches
|
|
appErr := th.App.Srv().InvalidateAllCaches()
|
|
require.Nil(tb, appErr)
|
|
}
|
|
th.Server.Shutdown()
|
|
})
|
|
|
|
return th
|
|
}
|
|
|
|
func (th *TestHelper) InitPlugins() *TestHelper {
|
|
pluginDir := filepath.Join(th.tempWorkspace, "plugins")
|
|
webappDir := filepath.Join(th.tempWorkspace, "webapp")
|
|
|
|
th.App.InitPlugins(th.Context, pluginDir, webappDir)
|
|
|
|
return th
|
|
}
|
|
|
|
func (th *TestHelper) NewPluginAPI(manifest *model.Manifest) plugin.API {
|
|
return th.App.NewPluginAPI(th.Context, manifest)
|
|
}
|
|
|
|
func (th *TestHelper) InitBasic(tb testing.TB) *TestHelper {
|
|
tb.Helper()
|
|
|
|
var appErr *model.AppError
|
|
th.SystemAdminUser, appErr = th.App.CreateUser(th.Context, &model.User{Email: model.NewId() + "[email protected]", Nickname: "Corey Hulen", Password: model.NewTestPassword(), EmailVerified: true, Roles: model.SystemAdminRoleId})
|
|
require.Nil(tb, appErr)
|
|
|
|
th.BasicUser, appErr = th.App.CreateUser(th.Context, &model.User{Email: model.NewId() + "[email protected]", Nickname: "Corey Hulen", Password: model.NewTestPassword(), EmailVerified: true, Roles: model.SystemUserRoleId})
|
|
require.Nil(tb, appErr)
|
|
|
|
th.BasicTeam, appErr = th.App.CreateTeam(th.Context, &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: th.BasicUser.Email, Type: model.TeamOpen})
|
|
require.Nil(tb, appErr)
|
|
|
|
_, appErr = th.App.JoinUserToTeam(th.Context, th.BasicTeam, th.BasicUser, "")
|
|
require.Nil(tb, appErr)
|
|
|
|
th.BasicChannel, appErr = th.App.CreateChannel(th.Context, &model.Channel{DisplayName: "Test API Name", Name: "zz" + model.NewId() + "a", Type: model.ChannelTypeOpen, TeamId: th.BasicTeam.Id, CreatorId: th.BasicUser.Id}, true)
|
|
require.Nil(tb, appErr)
|
|
|
|
return th
|
|
}
|
|
|
|
func TestStaticFilesRequest(t *testing.T) {
|
|
th := Setup(t).InitPlugins()
|
|
|
|
pluginID := "com.mattermost.sample"
|
|
|
|
// Setup the directory directly in the plugin working path.
|
|
pluginDir := filepath.Join(*th.App.Config().PluginSettings.Directory, pluginID)
|
|
err := os.MkdirAll(pluginDir, 0777)
|
|
require.NoError(t, err)
|
|
pluginDir, err = filepath.Abs(pluginDir)
|
|
require.NoError(t, err)
|
|
|
|
// Compile the backend
|
|
backend := filepath.Join(pluginDir, "backend.exe")
|
|
pluginCode := `
|
|
package main
|
|
|
|
import (
|
|
"github.com/mattermost/mattermost/server/public/plugin"
|
|
)
|
|
|
|
type MyPlugin struct {
|
|
plugin.MattermostPlugin
|
|
}
|
|
|
|
func main() {
|
|
plugin.ClientMain(&MyPlugin{})
|
|
}
|
|
`
|
|
utils.CompileGo(t, pluginCode, backend)
|
|
|
|
// Write out the frontend
|
|
mainJS := `var x = alert();`
|
|
mainJSPath := filepath.Join(pluginDir, "main.js")
|
|
require.NoError(t, err)
|
|
err = os.WriteFile(mainJSPath, []byte(mainJS), 0777)
|
|
require.NoError(t, err)
|
|
|
|
// Write the plugin.json manifest
|
|
pluginManifest := `{"id": "com.mattermost.sample", "server": {"executable": "backend.exe"}, "webapp": {"bundle_path":"main.js"}, "settings_schema": {"settings": []}}`
|
|
err = os.WriteFile(filepath.Join(pluginDir, "plugin.json"), []byte(pluginManifest), 0600)
|
|
require.NoError(t, err)
|
|
|
|
// Activate the plugin
|
|
manifest, activated, reterr := th.App.GetPluginsEnvironment().Activate(pluginID)
|
|
require.NoError(t, reterr)
|
|
require.NotNil(t, manifest)
|
|
require.True(t, activated)
|
|
|
|
// Verify access to the bundle with requisite headers
|
|
req, err := http.NewRequest("GET", "/static/plugins/com.mattermost.sample/com.mattermost.sample_724ed0e2ebb2b841_bundle.js", nil)
|
|
require.NoError(t, err)
|
|
res := httptest.NewRecorder()
|
|
th.Web.MainRouter.ServeHTTP(res, req)
|
|
assert.Equal(t, http.StatusOK, res.Code)
|
|
assert.Equal(t, mainJS, res.Body.String())
|
|
assert.Equal(t, []string{"max-age=31556926, public"}, res.Result().Header[http.CanonicalHeaderKey("Cache-Control")])
|
|
|
|
// Verify cached access to the bundle with an If-Modified-Since timestamp in the future
|
|
future := time.Now().Add(24 * time.Hour)
|
|
req, err = http.NewRequest("GET", "/static/plugins/com.mattermost.sample/com.mattermost.sample_724ed0e2ebb2b841_bundle.js", nil)
|
|
require.NoError(t, err)
|
|
req.Header.Add("If-Modified-Since", future.Format(time.RFC850))
|
|
res = httptest.NewRecorder()
|
|
th.Web.MainRouter.ServeHTTP(res, req)
|
|
assert.Equal(t, http.StatusNotModified, res.Code)
|
|
assert.Empty(t, res.Body.String())
|
|
assert.Equal(t, []string{"max-age=31556926, public"}, res.Result().Header[http.CanonicalHeaderKey("Cache-Control")])
|
|
|
|
// Verify access to the bundle with an If-Modified-Since timestamp in the past
|
|
past := time.Now().Add(-24 * time.Hour)
|
|
req, err = http.NewRequest("GET", "/static/plugins/com.mattermost.sample/com.mattermost.sample_724ed0e2ebb2b841_bundle.js", nil)
|
|
require.NoError(t, err)
|
|
req.Header.Add("If-Modified-Since", past.Format(time.RFC850))
|
|
res = httptest.NewRecorder()
|
|
th.Web.MainRouter.ServeHTTP(res, req)
|
|
assert.Equal(t, http.StatusOK, res.Code)
|
|
assert.Equal(t, mainJS, res.Body.String())
|
|
assert.Equal(t, []string{"max-age=31556926, public"}, res.Result().Header[http.CanonicalHeaderKey("Cache-Control")])
|
|
|
|
// Verify handling of 404.
|
|
req, err = http.NewRequest("GET", "/static/plugins/com.mattermost.sample/404.js", nil)
|
|
require.NoError(t, err)
|
|
res = httptest.NewRecorder()
|
|
th.Web.MainRouter.ServeHTTP(res, req)
|
|
assert.Equal(t, http.StatusNotFound, res.Code)
|
|
assert.Equal(t, "404 page not found\n", res.Body.String())
|
|
assert.Equal(t, []string{"no-cache, public"}, res.Result().Header[http.CanonicalHeaderKey("Cache-Control")])
|
|
}
|
|
|
|
func TestPublicFilesRequest(t *testing.T) {
|
|
th := Setup(t).InitPlugins()
|
|
|
|
pluginDir, err := os.MkdirTemp("", "")
|
|
require.NoError(t, err)
|
|
webappPluginDir, err := os.MkdirTemp("", "")
|
|
require.NoError(t, err)
|
|
defer os.RemoveAll(pluginDir)
|
|
defer os.RemoveAll(webappPluginDir)
|
|
|
|
env, err := plugin.NewEnvironment(th.NewPluginAPI, app.NewDriverImpl(th.Server), pluginDir, webappPluginDir, th.App.Log(), nil)
|
|
require.NoError(t, err)
|
|
|
|
pluginID := "com.mattermost.sample"
|
|
pluginCode :=
|
|
`
|
|
package main
|
|
|
|
import (
|
|
"github.com/mattermost/mattermost/server/public/plugin"
|
|
)
|
|
|
|
type MyPlugin struct {
|
|
plugin.MattermostPlugin
|
|
}
|
|
|
|
func main() {
|
|
plugin.ClientMain(&MyPlugin{})
|
|
}
|
|
|
|
`
|
|
// Compile and write the plugin
|
|
backend := filepath.Join(pluginDir, pluginID, "backend.exe")
|
|
utils.CompileGo(t, pluginCode, backend)
|
|
|
|
// Write the plugin.json manifest
|
|
pluginManifest := `{"id": "com.mattermost.sample", "server": {"executable": "backend.exe"}, "settings_schema": {"settings": []}}`
|
|
err = os.WriteFile(filepath.Join(pluginDir, pluginID, "plugin.json"), []byte(pluginManifest), 0600)
|
|
require.NoError(t, err)
|
|
|
|
// Write the test public file
|
|
helloHTML := `Hello from the static files public folder for the com.mattermost.sample plugin!`
|
|
htmlFolderPath := filepath.Join(pluginDir, pluginID, "public")
|
|
err = os.MkdirAll(htmlFolderPath, os.ModePerm)
|
|
require.NoError(t, err)
|
|
htmlFilePath := filepath.Join(htmlFolderPath, "hello.html")
|
|
|
|
htmlFileErr := os.WriteFile(htmlFilePath, []byte(helloHTML), 0600)
|
|
assert.NoError(t, htmlFileErr)
|
|
|
|
nefariousHTML := `You shouldn't be able to get here!`
|
|
htmlFileErr = os.WriteFile(filepath.Join(pluginDir, pluginID, "nefarious-file-access.html"), []byte(nefariousHTML), 0600)
|
|
assert.NoError(t, htmlFileErr)
|
|
|
|
manifest, activated, reterr := env.Activate(pluginID)
|
|
require.NoError(t, reterr)
|
|
require.NotNil(t, manifest)
|
|
require.True(t, activated)
|
|
|
|
th.App.Channels().SetPluginsEnvironment(env)
|
|
|
|
req, err := http.NewRequest("GET", "/plugins/com.mattermost.sample/public/hello.html", nil)
|
|
require.NoError(t, err)
|
|
res := httptest.NewRecorder()
|
|
th.Web.MainRouter.ServeHTTP(res, req)
|
|
assert.Equal(t, helloHTML, res.Body.String())
|
|
|
|
req, err = http.NewRequest("GET", "/plugins/com.mattermost.sample/nefarious-file-access.html", nil)
|
|
require.NoError(t, err)
|
|
res = httptest.NewRecorder()
|
|
th.Web.MainRouter.ServeHTTP(res, req)
|
|
assert.Equal(t, 404, res.Code)
|
|
|
|
req, err = http.NewRequest("GET", "/plugins/com.mattermost.sample/public/../nefarious-file-access.html", nil)
|
|
require.NoError(t, err)
|
|
res = httptest.NewRecorder()
|
|
th.Web.MainRouter.ServeHTTP(res, req)
|
|
assert.Equal(t, 301, res.Code)
|
|
}
|
|
|
|
/* Test disabled for now so we don't require the client to build. Maybe re-enable after client gets moved out.
|
|
func TestStatic(t *testing.T) {
|
|
Setup()
|
|
|
|
// add a short delay to make sure the server is ready to receive requests
|
|
time.Sleep(1 * time.Second)
|
|
|
|
resp, err := http.Get(URL + "/static/root.html")
|
|
|
|
assert.NoErrorf(t, err, "got error while trying to get static files %v", err)
|
|
assert.Equalf(t, resp.StatusCode, http.StatusOK, "couldn't get static files %v", resp.StatusCode)
|
|
}
|
|
*/
|
|
|
|
func TestStaticFilesCaching(t *testing.T) {
|
|
th := Setup(t).InitPlugins()
|
|
|
|
fakeMainBundleName := "main.1234ab.js"
|
|
fakeRootHTML := `<html>
|
|
<head>
|
|
<title>Mattermost</title>
|
|
</head>
|
|
</html>`
|
|
fakeMainBundle := `module.exports = 'main';`
|
|
fakeRemoteEntry := `module.exports = 'remote';`
|
|
|
|
err := os.WriteFile("./client/root.html", []byte(fakeRootHTML), 0600)
|
|
require.NoError(t, err)
|
|
err = os.WriteFile("./client/"+fakeMainBundleName, []byte(fakeMainBundle), 0600)
|
|
require.NoError(t, err)
|
|
err = os.WriteFile("./client/remote_entry.js", []byte(fakeRemoteEntry), 0600)
|
|
require.NoError(t, err)
|
|
|
|
err = os.MkdirAll("./client/products/boards", 0777)
|
|
require.NoError(t, err)
|
|
err = os.WriteFile("./client/products/boards/remote_entry.js", []byte(fakeRemoteEntry), 0600)
|
|
require.NoError(t, err)
|
|
|
|
req, err := http.NewRequest("GET", "/", nil)
|
|
require.NoError(t, err)
|
|
res := httptest.NewRecorder()
|
|
th.Web.MainRouter.ServeHTTP(res, req)
|
|
require.Equal(t, http.StatusOK, res.Code)
|
|
require.Equal(t, fakeRootHTML, res.Body.String())
|
|
require.Equal(t, []string{"no-cache, max-age=31556926, public"}, res.Result().Header[http.CanonicalHeaderKey("Cache-Control")])
|
|
|
|
// Checking for HEAD method as well.
|
|
req, err = http.NewRequest(http.MethodHead, "/", nil)
|
|
require.NoError(t, err)
|
|
res = httptest.NewRecorder()
|
|
th.Web.MainRouter.ServeHTTP(res, req)
|
|
require.Equal(t, http.StatusOK, res.Code)
|
|
require.Equal(t, fakeRootHTML, res.Body.String())
|
|
require.Equal(t, []string{"no-cache, max-age=31556926, public"}, res.Result().Header[http.CanonicalHeaderKey("Cache-Control")])
|
|
|
|
req, err = http.NewRequest("GET", "/static/"+fakeMainBundleName, nil)
|
|
require.NoError(t, err)
|
|
res = httptest.NewRecorder()
|
|
th.Web.MainRouter.ServeHTTP(res, req)
|
|
require.Equal(t, http.StatusOK, res.Code)
|
|
require.Equal(t, fakeMainBundle, res.Body.String())
|
|
require.Equal(t, []string{"max-age=31556926, public"}, res.Result().Header[http.CanonicalHeaderKey("Cache-Control")])
|
|
|
|
req, err = http.NewRequest("GET", "/static/remote_entry.js", nil)
|
|
require.NoError(t, err)
|
|
res = httptest.NewRecorder()
|
|
th.Web.MainRouter.ServeHTTP(res, req)
|
|
require.Equal(t, http.StatusOK, res.Code)
|
|
require.Equal(t, fakeRemoteEntry, res.Body.String())
|
|
require.Equal(t, []string{"no-cache, max-age=31556926, public"}, res.Result().Header[http.CanonicalHeaderKey("Cache-Control")])
|
|
|
|
req, err = http.NewRequest("GET", "/static/products/boards/remote_entry.js", nil)
|
|
require.NoError(t, err)
|
|
res = httptest.NewRecorder()
|
|
th.Web.MainRouter.ServeHTTP(res, req)
|
|
require.Equal(t, http.StatusOK, res.Code)
|
|
require.Equal(t, fakeRemoteEntry, res.Body.String())
|
|
require.Equal(t, []string{"no-cache, max-age=31556926, public"}, res.Result().Header[http.CanonicalHeaderKey("Cache-Control")])
|
|
}
|
|
|
|
func TestCheckClientCompatability(t *testing.T) {
|
|
//Browser Name, UA String, expected result (if the browser should fail the test false and if it should pass the true)
|
|
type uaTest struct {
|
|
Name string // Name of Browser
|
|
UserAgent string // Useragent of Browser
|
|
Result bool // Expected result (true if browser should be compatible, false if browser shouldn't be compatible)
|
|
}
|
|
var uaTestParameters = []uaTest{
|
|
{"Mozilla 40.1", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1", true},
|
|
{"Chrome 60", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36", true},
|
|
{"Chrome Mobile", "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Mobile Safari/537.36", true},
|
|
{"MM Classic App", "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 5X Build/OPR6.170623.013; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.81 Mobile Safari/537.36 Web-Atoms-Mobile-WebView", true},
|
|
{"MM App 3.7.1", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Mattermost/3.7.1 Chrome/56.0.2924.87 Electron/1.6.11 Safari/537.36", true},
|
|
{"Franz 4.0.4", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Franz/4.0.4 Chrome/52.0.2743.82 Electron/1.3.1 Safari/537.36", true},
|
|
{"Edge 14", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393", true},
|
|
{"Internet Explorer 9", "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 7.1; Trident/5.0", false},
|
|
{"Internet Explorer 11", "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko", false},
|
|
{"Internet Explorer 11 2", "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; Zoom 3.6.0; rv:11.0) like Gecko", false},
|
|
{"Internet Explorer 11 (Compatibility Mode) 1", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; .NET CLR 1.1.4322; InfoPath.3; Zoom 3.6.0)", false},
|
|
{"Internet Explorer 11 (Compatibility Mode) 2", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; Zoom 3.6.0)", false},
|
|
{"Safari 12", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Safari/605.1.15", true},
|
|
{"Safari 11", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Safari/604.1.38", false},
|
|
{"Safari 10", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/602.4.8 (KHTML, like Gecko) Version/10.0.3 Safari/602.4.8", false},
|
|
{"Safari 9", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/601.4.4 (KHTML, like Gecko) Version/9.0.3 Safari/601.4.4", false},
|
|
{"Safari 8", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/600.7.12 (KHTML, like Gecko) Version/8.0.7 Safari/600.7.12", false},
|
|
{"Safari Mobile 12", "Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like macOS) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/12.0 Mobile/14A5335d Safari/602.1.50", true},
|
|
{"Safari Mobile 9", "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B137 Safari/601.1", false},
|
|
}
|
|
for _, browser := range uaTestParameters {
|
|
t.Run(browser.Name, func(t *testing.T) {
|
|
result := CheckClientCompatibility(browser.UserAgent)
|
|
require.Equalf(t, result, browser.Result, "user agent test failed for %s", browser.Name)
|
|
})
|
|
}
|
|
}
|