2017-04-12 08:27:57 -04:00
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
2019-11-29 06:59:40 -05:00
// See LICENSE.txt for license information.
2015-06-15 03:53:32 -04:00
package web
import (
2017-10-16 11:09:43 -04:00
"fmt"
2019-04-05 10:35:51 -04:00
"net/http"
"net/http/httptest"
"os"
"path/filepath"
2015-06-15 03:53:32 -04:00
"testing"
2019-12-05 22:57:30 -05:00
"time"
2015-10-15 14:16:26 -04:00
2021-01-07 12:12:43 -05:00
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
2023-06-11 01:24:35 -04:00
"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"
2023-09-05 03:47:30 -04:00
"github.com/mattermost/mattermost/server/public/shared/request"
2023-06-11 01:24:35 -04:00
"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"
2015-06-15 03:53:32 -04:00
)
2021-08-16 13:46:44 -04:00
var apiClient * model . Client4
2015-06-15 03:53:32 -04:00
var URL string
2018-05-14 10:24:58 -04:00
type TestHelper struct {
2025-01-29 01:45:13 -05:00
App * app . App
2023-11-06 06:26:17 -05:00
Context request . CTX
2021-05-11 06:00:44 -04:00
Server * app . Server
Web * Web
2018-07-06 04:07:36 -04:00
2018-09-26 16:49:22 -04:00
BasicUser * model . User
BasicChannel * model . Channel
BasicTeam * model . Team
2018-07-06 04:07:36 -04:00
2018-09-26 16:49:22 -04:00
SystemAdminUser * model . User
2019-04-05 10:35:51 -04:00
tempWorkspace string
2020-03-04 08:18:03 -05:00
IncludeCacheLayer bool
2021-08-17 16:08:04 -04:00
TestLogger * mlog . Logger
2018-05-14 10:24:58 -04:00
}
2020-03-02 11:13:39 -05:00
func SetupWithStoreMock ( tb testing . TB ) * TestHelper {
if testing . Short ( ) {
tb . SkipNow ( )
}
2021-02-04 00:38:05 -05:00
2024-02-15 07:01:44 -05:00
th := setupTestHelper ( tb , false , nil )
2020-03-02 11:13:39 -05:00
emptyMockStore := mocks . Store { }
emptyMockStore . On ( "Close" ) . Return ( nil )
2022-10-06 04:04:21 -04:00
th . App . Srv ( ) . SetStore ( & emptyMockStore )
2020-03-02 11:13:39 -05:00
return th
}
2020-02-10 13:31:41 -05:00
func Setup ( tb testing . TB ) * TestHelper {
2020-03-02 11:13:39 -05:00
if testing . Short ( ) {
tb . SkipNow ( )
}
2019-02-19 09:20:11 -05:00
store := mainHelper . GetStore ( )
store . DropAllTables ( )
2023-04-18 07:58:33 -04:00
return setupTestHelper ( tb , true , nil )
2020-03-02 11:13:39 -05:00
}
2018-12-06 13:19:32 -05:00
2023-04-18 07:58:33 -04:00
func setupTestHelper ( tb testing . TB , includeCacheLayer bool , options [ ] app . Option ) * TestHelper {
2020-10-29 18:54:39 -04:00
memoryStore := config . NewTestMemoryStore ( )
2020-11-04 04:41:42 -05:00
newConfig := memoryStore . Get ( ) . Clone ( )
2023-04-18 07:58:33 -04:00
newConfig . SqlSettings = * mainHelper . GetSQLSettings ( )
2020-11-04 04:41:42 -05:00
* newConfig . AnnouncementSettings . AdminNoticesEnabled = false
* newConfig . AnnouncementSettings . UserNoticesEnabled = false
2021-01-04 16:21:02 -05:00
* newConfig . PluginSettings . AutomaticPrepackagedPlugins = false
2023-11-30 04:47:04 -05:00
* newConfig . LogSettings . EnableSentry = false // disable error reporting during tests
* newConfig . LogSettings . ConsoleJson = false
2025-10-27 16:54:20 -04:00
// 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
2025-06-06 01:44:43 -04:00
_ , _ , err := memoryStore . Set ( newConfig )
require . NoError ( tb , err )
2019-03-06 15:06:45 -05:00
options = append ( options , app . ConfigStore ( memoryStore ) )
2024-11-15 04:30:56 -05:00
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 ) )
}
2019-02-12 08:37:54 -05:00
2025-05-07 06:41:10 -04:00
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" )
2021-08-17 16:08:04 -04:00
// lock logger config so server init cannot override it during testing.
testLogger . LockConfiguration ( )
options = append ( options , app . SetLogger ( testLogger ) )
2020-09-09 15:25:55 -04:00
2019-02-12 08:37:54 -05:00
s , err := app . NewServer ( options ... )
2025-05-07 06:41:10 -04:00
require . NoError ( tb , err )
2020-03-04 08:18:03 -05:00
2022-08-08 09:52:31 -04:00
a := app . New ( app . ServerConnector ( s . Channels ( ) ) )
2020-06-12 07:43:50 -04:00
prevListenAddress := * s . Config ( ) . ServiceSettings . ListenAddress
2023-04-06 08:59:58 -04:00
a . UpdateConfig ( func ( cfg * model . Config ) { * cfg . ServiceSettings . ListenAddress = "localhost:0" } )
2025-05-07 06:41:10 -04:00
err = s . Start ( )
require . NoError ( tb , err )
2022-08-08 09:52:31 -04:00
a . UpdateConfig ( func ( cfg * model . Config ) { * cfg . ServiceSettings . ListenAddress = prevListenAddress } )
2018-05-14 10:24:58 -04:00
2021-10-15 10:27:05 -04:00
web := New ( s )
2020-06-12 07:43:50 -04:00
URL = fmt . Sprintf ( "http://localhost:%v" , s . ListenAddr . Port )
2021-08-16 13:46:44 -04:00
apiClient = model . NewAPIv4Client ( URL )
2017-10-09 17:59:48 -04:00
2022-10-06 04:04:21 -04:00
s . Store ( ) . MarkSystemRanUnitTests ( )
2017-10-09 17:59:48 -04:00
2022-08-08 09:52:31 -04:00
a . UpdateConfig ( func ( cfg * model . Config ) {
2017-10-31 10:39:31 -04:00
* cfg . TeamSettings . EnableOpenServer = true
} )
2017-10-09 17:59:48 -04:00
2018-05-14 10:24:58 -04:00
th := & TestHelper {
2023-03-27 12:19:29 -04:00
App : a ,
Context : request . EmptyContext ( testLogger ) ,
Server : s ,
Web : web ,
IncludeCacheLayer : includeCacheLayer ,
TestLogger : testLogger ,
2019-04-05 10:35:51 -04:00
}
2025-05-07 06:41:10 -04:00
tb . Cleanup ( func ( ) {
if th . IncludeCacheLayer {
// Clean all the caches
appErr := th . App . Srv ( ) . InvalidateAllCaches ( )
require . Nil ( tb , appErr )
}
th . Server . Shutdown ( )
} )
2019-04-05 10:35:51 -04:00
return th
}
func ( th * TestHelper ) InitPlugins ( ) * TestHelper {
pluginDir := filepath . Join ( th . tempWorkspace , "plugins" )
webappDir := filepath . Join ( th . tempWorkspace , "webapp" )
2021-05-11 06:00:44 -04:00
th . App . InitPlugins ( th . Context , pluginDir , webappDir )
2019-04-05 10:35:51 -04:00
2018-05-14 10:24:58 -04:00
return th
}
2021-05-11 06:00:44 -04:00
func ( th * TestHelper ) NewPluginAPI ( manifest * model . Manifest ) plugin . API {
return th . App . NewPluginAPI ( th . Context , manifest )
}
2025-05-07 06:41:10 -04:00
func ( th * TestHelper ) InitBasic ( tb testing . TB ) * TestHelper {
tb . Helper ( )
2018-07-06 04:07:36 -04:00
2025-05-07 06:41:10 -04:00
var appErr * model . AppError
2026-04-08 15:49:43 -04:00
th . SystemAdminUser , appErr = th . App . CreateUser ( th . Context , & model . User { Email : model . NewId ( ) + "success+test@simulator.amazonses.com" , Nickname : "Corey Hulen" , Password : model . NewTestPassword ( ) , EmailVerified : true , Roles : model . SystemAdminRoleId } )
2025-05-07 06:41:10 -04:00
require . Nil ( tb , appErr )
2018-05-14 10:24:58 -04:00
2026-04-08 15:49:43 -04:00
th . BasicUser , appErr = th . App . CreateUser ( th . Context , & model . User { Email : model . NewId ( ) + "success+test@simulator.amazonses.com" , Nickname : "Corey Hulen" , Password : model . NewTestPassword ( ) , EmailVerified : true , Roles : model . SystemUserRoleId } )
2025-05-07 06:41:10 -04:00
require . Nil ( tb , appErr )
2018-05-14 10:24:58 -04:00
2025-05-07 06:41:10 -04:00
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 )
2018-05-14 10:24:58 -04:00
2025-05-07 06:41:10 -04:00
_ , appErr = th . App . JoinUserToTeam ( th . Context , th . BasicTeam , th . BasicUser , "" )
require . Nil ( tb , appErr )
2018-05-14 10:24:58 -04:00
2025-05-07 06:41:10 -04:00
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 )
2018-05-14 10:24:58 -04:00
return th
2015-06-15 03:53:32 -04:00
}
2019-12-05 22:57:30 -05:00
func TestStaticFilesRequest ( t * testing . T ) {
2020-02-10 13:31:41 -05:00
th := Setup ( t ) . InitPlugins ( )
2019-12-05 22:57:30 -05:00
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 (
2023-06-11 01:24:35 -04:00
"github.com/mattermost/mattermost/server/public/plugin"
2019-12-05 22:57:30 -05:00
)
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 )
2022-08-09 07:25:46 -04:00
err = os . WriteFile ( mainJSPath , [ ] byte ( mainJS ) , 0777 )
2019-12-05 22:57:30 -05:00
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": []}} `
2025-05-07 06:41:10 -04:00
err = os . WriteFile ( filepath . Join ( pluginDir , "plugin.json" ) , [ ] byte ( pluginManifest ) , 0600 )
require . NoError ( t , err )
2019-12-05 22:57:30 -05:00
// Activate the plugin
manifest , activated , reterr := th . App . GetPluginsEnvironment ( ) . Activate ( pluginID )
2021-02-26 01:30:22 -05:00
require . NoError ( t , reterr )
2019-12-05 22:57:30 -05:00
require . NotNil ( t , manifest )
require . True ( t , activated )
// Verify access to the bundle with requisite headers
2025-05-07 06:41:10 -04:00
req , err := http . NewRequest ( "GET" , "/static/plugins/com.mattermost.sample/com.mattermost.sample_724ed0e2ebb2b841_bundle.js" , nil )
require . NoError ( t , err )
2019-12-05 22:57:30 -05:00
res := httptest . NewRecorder ( )
th . Web . MainRouter . ServeHTTP ( res , req )
assert . Equal ( t , http . StatusOK , res . Code )
assert . Equal ( t , mainJS , res . Body . String ( ) )
2020-01-08 15:43:59 -05:00
assert . Equal ( t , [ ] string { "max-age=31556926, public" } , res . Result ( ) . Header [ http . CanonicalHeaderKey ( "Cache-Control" ) ] )
2019-12-05 22:57:30 -05:00
// Verify cached access to the bundle with an If-Modified-Since timestamp in the future
future := time . Now ( ) . Add ( 24 * time . Hour )
2025-05-07 06:41:10 -04:00
req , err = http . NewRequest ( "GET" , "/static/plugins/com.mattermost.sample/com.mattermost.sample_724ed0e2ebb2b841_bundle.js" , nil )
require . NoError ( t , err )
2019-12-05 22:57:30 -05:00
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 ( ) )
2020-01-08 15:43:59 -05:00
assert . Equal ( t , [ ] string { "max-age=31556926, public" } , res . Result ( ) . Header [ http . CanonicalHeaderKey ( "Cache-Control" ) ] )
2019-12-05 22:57:30 -05:00
// Verify access to the bundle with an If-Modified-Since timestamp in the past
past := time . Now ( ) . Add ( - 24 * time . Hour )
2025-05-07 06:41:10 -04:00
req , err = http . NewRequest ( "GET" , "/static/plugins/com.mattermost.sample/com.mattermost.sample_724ed0e2ebb2b841_bundle.js" , nil )
require . NoError ( t , err )
2019-12-05 22:57:30 -05:00
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 ( ) )
2020-01-08 15:43:59 -05:00
assert . Equal ( t , [ ] string { "max-age=31556926, public" } , res . Result ( ) . Header [ http . CanonicalHeaderKey ( "Cache-Control" ) ] )
2019-12-05 22:57:30 -05:00
// Verify handling of 404.
2025-05-07 06:41:10 -04:00
req , err = http . NewRequest ( "GET" , "/static/plugins/com.mattermost.sample/404.js" , nil )
require . NoError ( t , err )
2019-12-05 22:57:30 -05:00
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" ) ] )
}
2019-04-05 10:35:51 -04:00
func TestPublicFilesRequest ( t * testing . T ) {
2020-02-10 13:31:41 -05:00
th := Setup ( t ) . InitPlugins ( )
2019-04-05 10:35:51 -04:00
2022-08-09 07:25:46 -04:00
pluginDir , err := os . MkdirTemp ( "" , "" )
2019-04-05 10:35:51 -04:00
require . NoError ( t , err )
2022-08-09 07:25:46 -04:00
webappPluginDir , err := os . MkdirTemp ( "" , "" )
2019-04-05 10:35:51 -04:00
require . NoError ( t , err )
defer os . RemoveAll ( pluginDir )
defer os . RemoveAll ( webappPluginDir )
2023-05-03 15:04:10 -04:00
env , err := plugin . NewEnvironment ( th . NewPluginAPI , app . NewDriverImpl ( th . Server ) , pluginDir , webappPluginDir , th . App . Log ( ) , nil )
2019-04-05 10:35:51 -04:00
require . NoError ( t , err )
pluginID := "com.mattermost.sample"
pluginCode :=
`
package main
import (
2023-06-11 01:24:35 -04:00
"github.com/mattermost/mattermost/server/public/plugin"
2019-04-05 10:35:51 -04:00
)
type MyPlugin struct {
plugin . MattermostPlugin
}
func main ( ) {
plugin . ClientMain ( & MyPlugin { } )
}
2019-10-21 11:00:21 -04:00
2019-04-05 10:35:51 -04:00
`
// 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": []}} `
2025-05-07 06:41:10 -04:00
err = os . WriteFile ( filepath . Join ( pluginDir , pluginID , "plugin.json" ) , [ ] byte ( pluginManifest ) , 0600 )
require . NoError ( t , err )
2019-04-05 10:35:51 -04:00
// 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" )
2025-05-07 06:41:10 -04:00
err = os . MkdirAll ( htmlFolderPath , os . ModePerm )
require . NoError ( t , err )
2019-04-05 10:35:51 -04:00
htmlFilePath := filepath . Join ( htmlFolderPath , "hello.html" )
2022-08-09 07:25:46 -04:00
htmlFileErr := os . WriteFile ( htmlFilePath , [ ] byte ( helloHTML ) , 0600 )
2019-04-05 10:35:51 -04:00
assert . NoError ( t , htmlFileErr )
nefariousHTML := ` You shouldn't be able to get here! `
2022-08-09 07:25:46 -04:00
htmlFileErr = os . WriteFile ( filepath . Join ( pluginDir , pluginID , "nefarious-file-access.html" ) , [ ] byte ( nefariousHTML ) , 0600 )
2019-04-05 10:35:51 -04:00
assert . NoError ( t , htmlFileErr )
manifest , activated , reterr := env . Activate ( pluginID )
2021-02-26 01:30:22 -05:00
require . NoError ( t , reterr )
2019-04-05 10:35:51 -04:00
require . NotNil ( t , manifest )
require . True ( t , activated )
2022-12-21 14:10:26 -05:00
th . App . Channels ( ) . SetPluginsEnvironment ( env )
2019-04-05 10:35:51 -04:00
2025-05-07 06:41:10 -04:00
req , err := http . NewRequest ( "GET" , "/plugins/com.mattermost.sample/public/hello.html" , nil )
require . NoError ( t , err )
2019-04-05 10:35:51 -04:00
res := httptest . NewRecorder ( )
th . Web . MainRouter . ServeHTTP ( res , req )
assert . Equal ( t , helloHTML , res . Body . String ( ) )
2025-05-07 06:41:10 -04:00
req , err = http . NewRequest ( "GET" , "/plugins/com.mattermost.sample/nefarious-file-access.html" , nil )
require . NoError ( t , err )
2019-04-05 10:35:51 -04:00
res = httptest . NewRecorder ( )
th . Web . MainRouter . ServeHTTP ( res , req )
assert . Equal ( t , 404 , res . Code )
2025-05-07 06:41:10 -04:00
req , err = http . NewRequest ( "GET" , "/plugins/com.mattermost.sample/public/../nefarious-file-access.html" , nil )
require . NoError ( t , err )
2019-04-05 10:35:51 -04:00
res = httptest . NewRecorder ( )
th . Web . MainRouter . ServeHTTP ( res , req )
assert . Equal ( t , 301 , res . Code )
}
2022-01-19 23:37:27 -05:00
/ * Test disabled for now so we don ' t require the client to build . Maybe re - enable after client gets moved out .
2015-06-15 03:53:32 -04:00
func TestStatic ( t * testing . T ) {
Setup ( )
2015-09-11 10:43:33 -04:00
// add a short delay to make sure the server is ready to receive requests
time . Sleep ( 1 * time . Second )
2015-06-15 03:53:32 -04:00
2016-03-14 08:50:46 -04:00
resp , err := http . Get ( URL + "/static/root.html" )
2015-09-11 10:43:33 -04:00
2019-10-21 11:00:21 -04:00
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 )
2015-06-15 03:53:32 -04:00
}
2016-03-22 11:35:39 -04:00
* /
2015-06-15 03:53:32 -04:00
2022-12-12 10:22:35 -05:00
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'; `
2025-06-06 01:44:43 -04:00
err := os . WriteFile ( "./client/root.html" , [ ] byte ( fakeRootHTML ) , 0600 )
2022-12-12 10:22:35 -05:00
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 )
2025-05-07 06:41:10 -04:00
req , err := http . NewRequest ( "GET" , "/" , nil )
require . NoError ( t , err )
2022-12-12 10:22:35 -05:00
res := httptest . NewRecorder ( )
th . Web . MainRouter . ServeHTTP ( res , req )
2024-10-29 10:27:20 -04:00
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.
2025-05-07 06:41:10 -04:00
req , err = http . NewRequest ( http . MethodHead , "/" , nil )
require . NoError ( t , err )
2024-10-29 10:27:20 -04:00
res = httptest . NewRecorder ( )
th . Web . MainRouter . ServeHTTP ( res , req )
2022-12-12 10:22:35 -05:00
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" ) ] )
2025-05-07 06:41:10 -04:00
req , err = http . NewRequest ( "GET" , "/static/" + fakeMainBundleName , nil )
require . NoError ( t , err )
2022-12-12 10:22:35 -05:00
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" ) ] )
2025-05-07 06:41:10 -04:00
req , err = http . NewRequest ( "GET" , "/static/remote_entry.js" , nil )
require . NoError ( t , err )
2022-12-12 10:22:35 -05:00
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" ) ] )
2025-05-07 06:41:10 -04:00
req , err = http . NewRequest ( "GET" , "/static/products/boards/remote_entry.js" , nil )
require . NoError ( t , err )
2022-12-12 10:22:35 -05:00
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" ) ] )
}
2018-03-06 16:22:07 -05:00
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 } ,
2019-08-15 14:30:40 -04:00
{ "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 } ,
2018-04-09 06:14:36 -04:00
{ "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 } ,
2019-11-04 11:01:29 -05:00
{ "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 } ,
2018-03-06 16:22:07 -05:00
{ "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 } ,
2019-11-04 11:01:29 -05:00
{ "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 } ,
2018-03-06 16:22:07 -05:00
}
for _ , browser := range uaTestParameters {
2018-03-12 10:21:20 -04:00
t . Run ( browser . Name , func ( t * testing . T ) {
2020-11-09 05:32:21 -05:00
result := CheckClientCompatibility ( browser . UserAgent )
2019-10-21 11:00:21 -04:00
require . Equalf ( t , result , browser . Result , "user agent test failed for %s" , browser . Name )
2018-03-12 10:21:20 -04:00
} )
2018-03-06 16:22:07 -05:00
}
2017-10-16 11:09:43 -04:00
}
2026-03-04 10:16:11 -05:00
func TestCheckDesktopAppCompatibility ( t * testing . T ) {
tests := [ ] struct {
name string
userAgent string
minVersion string
want bool
} {
{ "blank min version allows all" , "Mattermost/5.0.0" , "" , true } ,
{ "desktop app at min version" , "Mattermost/5.0.0" , "5.0.0" , true } ,
{ "desktop app above min version" , "Mattermost/5.1.0" , "5.0.0" , true } ,
{ "desktop app below min version" , "Mattermost/4.9.0" , "5.0.0" , false } ,
{ "browser user agent not checked" , "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0" , "5.0.0" , true } ,
{ "desktop app version at start of UA" , "Mattermost/5.3.1 Chrome/110.0.5481.177" , "5.0.0" , true } ,
{ "desktop app version at end of UA" , "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 Chrome/126.0.6478.127 Electron/31.2.1 Safari/537.36 Mattermost/5.9.0" , "5.0.0" , true } ,
{ "desktop app old version rejected" , "Mattermost/3.7.1 Chrome/56.0.2924.87 Electron/1.6.11 Safari/537.36" , "5.0.0" , false } ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
got := CheckDesktopAppCompatibility ( tt . userAgent , & tt . minVersion )
require . Equalf ( t , tt . want , got , "CheckDesktopAppCompatibility(%q, %q)" , tt . userAgent , tt . minVersion )
} )
}
}