// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. package utils_test import ( "fmt" "os" "path/filepath" "strings" "testing" "github.com/stretchr/testify/require" "github.com/mattermost/mattermost/server/public/model" "github.com/mattermost/mattermost/server/v8/channels/utils" ) func TestUpdateAssetsSubpathFromConfig(t *testing.T) { t.Run("dev build", func(t *testing.T) { var oldBuildNumber = model.BuildNumber model.BuildNumber = "dev" defer func() { model.BuildNumber = oldBuildNumber }() err := utils.UpdateAssetsSubpathFromConfig(nil) require.NoError(t, err) }) t.Run("IS_CI=true", func(t *testing.T) { err := os.Setenv("IS_CI", "true") require.NoError(t, err) defer func() { err = os.Unsetenv("IS_CI") require.NoError(t, err) }() err = utils.UpdateAssetsSubpathFromConfig(nil) require.NoError(t, err) }) t.Run("no config", func(t *testing.T) { tempDir, err := os.MkdirTemp("", "test_update_assets_subpath") require.NoError(t, err) defer func() { err = os.RemoveAll(tempDir) require.NoError(t, err) }() err = os.Chdir(tempDir) require.NoError(t, err) err = utils.UpdateAssetsSubpathFromConfig(nil) require.Error(t, err) }) } func TestUpdateAssetsSubpath(t *testing.T) { t.Run("no client dir", func(t *testing.T) { tempDir, err := os.MkdirTemp("", "test_update_assets_subpath") require.NoError(t, err) defer func() { err = os.RemoveAll(tempDir) require.NoError(t, err) }() err = os.Chdir(tempDir) require.NoError(t, err) err = utils.UpdateAssetsSubpath("/") require.Error(t, err) }) t.Run("valid", func(t *testing.T) { tempDir, err := os.MkdirTemp("", "test_update_assets_subpath") require.NoError(t, err) defer func() { err = os.RemoveAll(tempDir) require.NoError(t, err) }() err = os.Chdir(tempDir) require.NoError(t, err) err = os.Mkdir(model.ClientDir, 0700) require.NoError(t, err) testCases := []struct { Description string RootHTML string MainCSS string ManifestJSON string Subpath string ExpectedError error ExpectedRootHTML string ExpectedMainCSS string ExpectedManifestJSON string }{ { "no changes required, empty subpath provided", baseRootHTML, baseCSS, baseManifestJSON, "", nil, baseRootHTML, baseCSS, baseManifestJSON, }, { "no changes required", baseRootHTML, baseCSS, baseManifestJSON, "/", nil, baseRootHTML, baseCSS, baseManifestJSON, }, { "content security policy not found (missing quotes)", contentSecurityPolicyNotFoundHTML, baseCSS, baseManifestJSON, "/subpath", fmt.Errorf("failed to update root.html: %w", fmt.Errorf("failed to find 'Content-Security-Policy' meta tag to rewrite")), contentSecurityPolicyNotFoundHTML, baseCSS, baseManifestJSON, }, { "content security policy not found (missing unsafe-eval)", contentSecurityPolicyNotFound2HTML, baseCSS, baseManifestJSON, "/subpath", fmt.Errorf("failed to update root.html: %w", fmt.Errorf("failed to find 'Content-Security-Policy' meta tag to rewrite")), contentSecurityPolicyNotFound2HTML, baseCSS, baseManifestJSON, }, { "subpath", baseRootHTML, baseCSS, baseManifestJSON, "/subpath", nil, subpathRootHTML, subpathCSS, subpathManifestJSON, }, { "new subpath from old", subpathRootHTML, subpathCSS, subpathManifestJSON, "/nested/subpath", nil, newSubpathRootHTML, newSubpathCSS, newSubpathManifestJSON, }, { "resetting to /", subpathRootHTML, subpathCSS, baseManifestJSON, "/", nil, baseRootHTML, baseCSS, baseManifestJSON, }, } for _, testCase := range testCases { t.Run(testCase.Description, func(t *testing.T) { require.NoError(t, os.WriteFile(filepath.Join(tempDir, model.ClientDir, "root.html"), []byte(testCase.RootHTML), 0700)) require.NoError(t, os.WriteFile(filepath.Join(tempDir, model.ClientDir, "main.css"), []byte(testCase.MainCSS), 0700)) require.NoError(t, os.WriteFile(filepath.Join(tempDir, model.ClientDir, "manifest.json"), []byte(testCase.ManifestJSON), 0700)) err := utils.UpdateAssetsSubpath(testCase.Subpath) if testCase.ExpectedError != nil { require.Equal(t, testCase.ExpectedError, err) } else { require.NoError(t, err) } contents, err := os.ReadFile(filepath.Join(tempDir, model.ClientDir, "root.html")) require.NoError(t, err) // Rewrite the expected and contents for simpler diffs when failed. expectedRootHTML := strings.Replace(testCase.ExpectedRootHTML, ">", ">\n", -1) contentsStr := strings.Replace(string(contents), ">", ">\n", -1) require.Equal(t, expectedRootHTML, contentsStr) contents, err = os.ReadFile(filepath.Join(tempDir, model.ClientDir, "main.css")) require.NoError(t, err) require.Equal(t, testCase.ExpectedMainCSS, string(contents)) contents, err = os.ReadFile(filepath.Join(tempDir, model.ClientDir, "manifest.json")) require.NoError(t, err) require.Equal(t, testCase.ExpectedManifestJSON, string(contents)) }) } }) } func TestGetSubpathFromConfig(t *testing.T) { testCases := []struct { Description string SiteURL *string ExpectedError bool ExpectedSubpath string }{ { "empty SiteURL", model.NewPointer(""), false, "/", }, { "invalid SiteURL", model.NewPointer("cache_object:foo/bar"), true, "", }, { "nil SiteURL", nil, false, "/", }, { "no trailing slash", model.NewPointer("http://localhost:8065"), false, "/", }, { "trailing slash", model.NewPointer("http://localhost:8065/"), false, "/", }, { "subpath, no trailing slash", model.NewPointer("http://localhost:8065/subpath"), false, "/subpath", }, { "trailing slash", model.NewPointer("http://localhost:8065/subpath/"), false, "/subpath", }, } for _, testCase := range testCases { t.Run(testCase.Description, func(t *testing.T) { config := &model.Config{ ServiceSettings: model.ServiceSettings{ SiteURL: testCase.SiteURL, }, } subpath, err := utils.GetSubpathFromConfig(config) if testCase.ExpectedError { require.Error(t, err) } else { require.NoError(t, err) } require.Equal(t, testCase.ExpectedSubpath, subpath) }) } } const contentSecurityPolicyNotFoundHTML = `
We're having trouble connecting to Mattermost. If refreshing this page (Ctrl+R or Command+R) does not work, please verify that your computer is connected to the internet.
We're having trouble connecting to Mattermost. If refreshing this page (Ctrl+R or Command+R) does not work, please verify that your computer is connected to the internet.
We're having trouble connecting to Mattermost. If refreshing this page (Ctrl+R or Command+R) does not work, please verify that your computer is connected to the internet.
We're having trouble connecting to Mattermost. If refreshing this page (Ctrl+R or Command+R) does not work, please verify that your computer is connected to the internet.
We're having trouble connecting to Mattermost. If refreshing this page (Ctrl+R or Command+R) does not work, please verify that your computer is connected to the internet.