github.com/masterhung0112/hk_server/v5@v5.0.0-20220302090640-ec71aef15e1c/testlib/resources.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package testlib
     5  
     6  import (
     7  	"fmt"
     8  	"io/ioutil"
     9  	"os"
    10  	"path"
    11  	"path/filepath"
    12  	"runtime"
    13  
    14  	"github.com/pkg/errors"
    15  
    16  	"github.com/masterhung0112/hk_server/v5/model"
    17  	"github.com/masterhung0112/hk_server/v5/shared/filestore"
    18  	"github.com/masterhung0112/hk_server/v5/utils"
    19  	"github.com/masterhung0112/hk_server/v5/utils/fileutils"
    20  )
    21  
    22  const (
    23  	resourceTypeFile = iota
    24  	resourceTypeFolder
    25  )
    26  
    27  const (
    28  	actionCopy = iota
    29  	actionSymlink
    30  )
    31  
    32  const root = "___hk_server"
    33  
    34  type testResourceDetails struct {
    35  	src     string
    36  	dest    string
    37  	resType int8
    38  	action  int8
    39  }
    40  
    41  // getCommonBaseSearchPaths() is a custom version of what fileutils exposes. At some point, consolidate.
    42  func getCommonBaseSearchPaths() []string {
    43  	paths := []string{
    44  		".",
    45  		"..",
    46  		"../..",
    47  		"../../..",
    48  		"../../../..",
    49  	}
    50  
    51  	// this enables the server to be used in tests from a different repository
    52  	if mmPath := os.Getenv("HK_SERVER_PATH"); mmPath != "" {
    53  		paths = append(paths, mmPath)
    54  	}
    55  
    56  	return paths
    57  }
    58  
    59  func findFile(path string) string {
    60  	return fileutils.FindPath(path, getCommonBaseSearchPaths(), func(fileInfo os.FileInfo) bool {
    61  		return !fileInfo.IsDir()
    62  	})
    63  }
    64  
    65  func findDir(dir string) (string, bool) {
    66  	if dir == root {
    67  		srcPath := findFile("go.mod")
    68  		if srcPath == "" {
    69  			return "./", false
    70  		}
    71  
    72  		rootAbs, err := filepath.Abs(filepath.Dir(srcPath))
    73  		if err != nil {
    74  			return "./", false
    75  		}
    76  		return rootAbs, true
    77  	}
    78  
    79  	found := fileutils.FindPath(dir, getCommonBaseSearchPaths(), func(fileInfo os.FileInfo) bool {
    80  		return fileInfo.IsDir()
    81  	})
    82  	if found == "" {
    83  		return "./", false
    84  	}
    85  
    86  	return found, true
    87  }
    88  
    89  func getTestResourcesToSetup() []testResourceDetails {
    90  	var srcPath string
    91  	var found bool
    92  
    93  	var testResourcesToSetup = []testResourceDetails{
    94  		{root, "hk_server", resourceTypeFolder, actionSymlink},
    95  		{"go.mod", "go.mod", resourceTypeFile, actionSymlink},
    96  		{"testlib/testdata", "testlib/testdata", resourceTypeFolder, actionSymlink},
    97  		{"i18n", "i18n", resourceTypeFolder, actionSymlink},
    98  		{"templates", "templates", resourceTypeFolder, actionSymlink},
    99  		{"tests", "tests", resourceTypeFolder, actionSymlink},
   100  		{"fonts", "fonts", resourceTypeFolder, actionSymlink},
   101  		{"utils/policies-roles-mapping.json", "utils/policies-roles-mapping.json", resourceTypeFile, actionSymlink},
   102  	}
   103  
   104  	// Finding resources and setting full path to source to be used for further processing
   105  	for i, testResource := range testResourcesToSetup {
   106  		if testResource.resType == resourceTypeFile {
   107  			srcPath = findFile(testResource.src)
   108  			if srcPath == "" {
   109  				panic(fmt.Sprintf("Failed to find file %s", testResource.src))
   110  			}
   111  
   112  			testResourcesToSetup[i].src = srcPath
   113  		} else if testResource.resType == resourceTypeFolder {
   114  			srcPath, found = findDir(testResource.src)
   115  			if !found {
   116  				panic(fmt.Sprintf("Failed to find folder %s", testResource.src))
   117  			}
   118  
   119  			testResourcesToSetup[i].src = srcPath
   120  		} else {
   121  			panic(fmt.Sprintf("Invalid resource type: %d", testResource.resType))
   122  		}
   123  	}
   124  
   125  	return testResourcesToSetup
   126  }
   127  
   128  func CopyFile(src, dst string) error {
   129  	fileBackend, err := filestore.NewFileBackend(filestore.FileBackendSettings{DriverName: "local", Directory: ""})
   130  	if err != nil {
   131  		return errors.Wrapf(err, "failed to copy file %s to %s", src, dst)
   132  	}
   133  	if err = fileBackend.CopyFile(src, dst); err != nil {
   134  		return errors.Wrapf(err, "failed to copy file %s to %s", src, dst)
   135  	}
   136  	return nil
   137  }
   138  
   139  func SetupTestResources() (string, error) {
   140  	testResourcesToSetup := getTestResourcesToSetup()
   141  
   142  	tempDir, err := ioutil.TempDir("", "testlib")
   143  	if err != nil {
   144  		return "", errors.Wrap(err, "failed to create temporary directory")
   145  	}
   146  
   147  	pluginsDir := path.Join(tempDir, "plugins")
   148  	err = os.Mkdir(pluginsDir, 0700)
   149  	if err != nil {
   150  		return "", errors.Wrapf(err, "failed to create plugins directory %s", pluginsDir)
   151  	}
   152  
   153  	clientDir := path.Join(tempDir, "client")
   154  	err = os.Mkdir(clientDir, 0700)
   155  	if err != nil {
   156  		return "", errors.Wrapf(err, "failed to create client directory %s", clientDir)
   157  	}
   158  
   159  	err = setupConfig(path.Join(tempDir, "config"))
   160  	if err != nil {
   161  		return "", errors.Wrap(err, "failed to setup config")
   162  	}
   163  
   164  	var resourceDestInTemp string
   165  
   166  	// Setting up test resources in temp.
   167  	// Action in each resource tells whether it needs to be copied or just symlinked
   168  	for _, testResource := range testResourcesToSetup {
   169  		resourceDestInTemp = filepath.Join(tempDir, testResource.dest)
   170  
   171  		// For Windows, we cannot symlink, so we forcely copy the file
   172  		if testResource.action == actionCopy || runtime.GOOS == "windows" {
   173  			if testResource.resType == resourceTypeFile {
   174  				err = utils.CopyFile(testResource.src, resourceDestInTemp)
   175  				if err != nil {
   176  					return "", errors.Wrapf(err, "failed to copy file %s to %s", testResource.src, resourceDestInTemp)
   177  				}
   178  			} else if testResource.resType == resourceTypeFolder {
   179  				err = utils.CopyDir(testResource.src, resourceDestInTemp)
   180  				if err != nil {
   181  					return "", errors.Wrapf(err, "failed to copy folder %s to %s", testResource.src, resourceDestInTemp)
   182  				}
   183  			}
   184  		} else if testResource.action == actionSymlink {
   185  			destDir := path.Dir(resourceDestInTemp)
   186  			if destDir != "." {
   187  				err = os.MkdirAll(destDir, os.ModePerm)
   188  				if err != nil {
   189  					return "", errors.Wrapf(err, "failed to make dir %s", destDir)
   190  				}
   191  			}
   192  
   193  			err = os.Symlink(testResource.src, resourceDestInTemp)
   194  			if err != nil {
   195  				return "", errors.Wrapf(err, "failed to symlink %s to %s", testResource.src, resourceDestInTemp)
   196  			}
   197  		} else {
   198  			return "", errors.Wrapf(err, "Invalid action: %d", testResource.action)
   199  		}
   200  
   201  	}
   202  
   203  	return tempDir, nil
   204  }
   205  
   206  func setupConfig(configDir string) error {
   207  	var err error
   208  	var config model.Config
   209  
   210  	config.SetDefaults()
   211  
   212  	err = os.Mkdir(configDir, 0700)
   213  	if err != nil {
   214  		return errors.Wrapf(err, "failed to create config directory %s", configDir)
   215  	}
   216  
   217  	configJSON := path.Join(configDir, "config.json")
   218  	err = ioutil.WriteFile(configJSON, []byte(config.ToJson()), 0644)
   219  	if err != nil {
   220  		return errors.Wrapf(err, "failed to write config to %s", configJSON)
   221  	}
   222  
   223  	return nil
   224  }