github.com/wfusion/gofusion@v1.1.14/test/suite.go (about) 1 package test 2 3 import ( 4 "context" 5 "fmt" 6 "io" 7 "os" 8 "path/filepath" 9 "runtime" 10 "runtime/debug" 11 "strings" 12 13 "github.com/stretchr/testify/suite" 14 15 "github.com/wfusion/gofusion/common/constant" 16 "github.com/wfusion/gofusion/common/env" 17 "github.com/wfusion/gofusion/common/utils" 18 "github.com/wfusion/gofusion/config" 19 "github.com/wfusion/gofusion/log" 20 ) 21 22 type Suite struct { 23 suite.Suite 24 } 25 26 func (t *Suite) SetupSuite() { 27 t.Catch(func() { 28 log.Info(context.Background(), "============ setup test suite ============") 29 }) 30 } 31 32 func (t *Suite) TearDownSuite() { 33 t.Catch(func() { 34 log.Info(context.Background(), "============ tear down test suite ============") 35 }) 36 } 37 38 func (t *Suite) Catch(f func()) { 39 defer func() { 40 if r := recover(); r != nil { 41 t.FailNow(fmt.Sprintf("panic: %s =>\n%s", r, debug.Stack())) 42 } 43 }() 44 45 f() 46 } 47 48 func (t *Suite) RawCopy(filenames []string, stackSkip int) (cleanFn func()) { 49 stackSkip++ 50 t.clearAllFiles(filenames, stackSkip) 51 for _, filename := range filenames { 52 t.copyFile(filename, filename, stackSkip) 53 } 54 return func() { 55 t.clearAllFiles(filenames, stackSkip) 56 } 57 } 58 59 func (t *Suite) Copy(src []string, testName string, stackSkip int) (cleanFn func()) { 60 _, filename, _, ok := runtime.Caller(stackSkip) 61 t.True(ok) 62 component := t.componentName(filename) 63 fileMapping, others := t.mappingFilenames(t.appName(component, testName), src) 64 allFilenames := append(others, utils.MapValues(fileMapping)...) 65 66 stackSkip++ 67 // t.clearAllFiles(allFilenames, stackSkip) 68 for src, dst := range fileMapping { 69 t.copyFile(dst, src, stackSkip) 70 } 71 for _, filename := range others { 72 t.copyFile(filename, filename, stackSkip) 73 } 74 return func() { 75 t.clearAllFiles(allFilenames, stackSkip) 76 } 77 } 78 79 func (t *Suite) Init(src []string, testName string, stackSkip int) (cleanFn func()) { 80 _, filename, _, ok := runtime.Caller(stackSkip) 81 t.True(ok) 82 componentName := t.componentName(filename) 83 appName := t.appName(componentName, testName) 84 fileMapping, _ := t.mappingFilenames(appName, src) 85 cfgNames := utils.MapValues(fileMapping) 86 for i := 0; i < len(cfgNames); i++ { 87 cfgNames[i] = env.WorkDir + "/configs/" + cfgNames[i] 88 } 89 90 appCfg := &struct{}{} 91 gracefullyExitFn := config.New(appName).Init(&appCfg, config.Files(cfgNames)) 92 return func() { 93 gracefullyExitFn() 94 } 95 } 96 97 func (t *Suite) ConfigFiles() []string { 98 return []string{ 99 "app.local.yml", 100 "app.yml", 101 } 102 } 103 104 func (t *Suite) AllConfigFiles() []string { 105 return []string{ 106 "app.local.yml", 107 "app.yml", 108 "app.json", 109 "app.toml", 110 } 111 } 112 113 func (t *Suite) appName(componentName, testName string) string { 114 return fmt.Sprintf("%s.%s", componentName, testName) 115 } 116 117 func (t *Suite) isConfigFile(name string) (ok bool) { 118 return strings.Contains(name, "app") 119 } 120 121 func (t *Suite) mappingFilenames(appName string, filenames []string) (cfgMapping map[string]string, others []string) { 122 others = make([]string, 0, len(filenames)) 123 cfgMapping = make(map[string]string, len(filenames)) 124 for _, filename := range filenames { 125 if t.isConfigFile(filename) { 126 cfgMapping[filename] = appName + "." + filename 127 } else { 128 others = append(others, filename) 129 } 130 } 131 return 132 } 133 134 func (t *Suite) componentName(filename string) (name string) { 135 fpath := filepath.Clean("github.com/wfusion/gofusion/test") 136 moduleDir := filepath.Dir(filename) 137 component := moduleDir[strings.Index(moduleDir, fpath):] 138 return component[len(fpath)+1:] 139 } 140 141 func (t *Suite) clearAllFiles(filenames []string, stackSkip int) { 142 // locate project conf path & current conf path 143 _, filename, _, ok := runtime.Caller(stackSkip) 144 t.Require().True(ok) 145 projectRoot := filepath.Dir(filename) 146 147 projectConfDir := filepath.Join(strings.TrimSuffix(projectRoot, constant.PathSeparator+"cases"), "configs") 148 currentConfDir := filepath.Join(env.WorkDir, "configs") 149 if utils.IsStrBlank(currentConfDir) || projectConfDir == currentConfDir { 150 return 151 } 152 153 files, err := filepath.Glob(currentConfDir + "/*") 154 t.Require().NoError(err) 155 156 toBeDeleted := func(filePath string) (ok bool) { 157 filename := filepath.Base(filePath) 158 for _, name := range filenames { 159 if strings.EqualFold(filename, name) { 160 return true 161 } 162 } 163 return 164 } 165 166 for _, filePath := range files { 167 f, err := os.Stat(filePath) 168 if err != nil { 169 continue 170 } 171 if !toBeDeleted(filePath) { 172 continue 173 } 174 if f.IsDir() { 175 t.Require().NoError(os.RemoveAll(filePath)) 176 } else { 177 t.Require().NoError(os.Remove(filePath)) 178 } 179 } 180 } 181 182 func (t *Suite) copyFile(to, from string, stackSkip int) { 183 _, filename, _, ok := runtime.Caller(stackSkip) 184 t.Require().True(ok) 185 projectRoot := filepath.Dir(filename) 186 187 projectConfDir := filepath.Join(strings.TrimSuffix(projectRoot, "/cases"), "configs") 188 currentConfDir := filepath.Join(env.WorkDir, "configs") 189 if utils.IsStrBlank(currentConfDir) || projectConfDir == currentConfDir { 190 return 191 } 192 193 // create current conf dir 194 err := os.MkdirAll(currentConfDir, os.ModePerm) 195 if err != nil { 196 t.Require().ErrorIs(err, os.ErrExist) 197 } 198 199 // copy files 200 copyFileFn := func(dst, src string) { 201 from, err := os.Open(src) 202 t.Require().NoError(err) 203 defer func() { t.Nil(from.Close()) }() 204 205 to, err := os.Create(dst) 206 t.Require().NoError(err) 207 defer func() { t.Nil(to.Close()) }() 208 209 _, err = io.Copy(to, from) 210 t.Require().NoError(err) 211 t.T().Logf("copy file from %s to %s success\n", src, dst) 212 } 213 214 currentConfPath := filepath.Join(currentConfDir, to) 215 projectConfPath := filepath.Join(projectConfDir, from) 216 217 var f os.FileInfo 218 if f, err = os.Stat(projectConfPath); err == nil && !f.IsDir() { 219 copyFileFn(currentConfPath, projectConfPath) 220 return 221 } 222 t.Require().ErrorIs(err, os.ErrNotExist) 223 224 files, err := filepath.Glob(projectConfPath) 225 t.Require().NoError(err) 226 for _, filePath := range files { 227 filePath = strings.TrimPrefix(filePath, projectConfDir) 228 229 // mkdir -p 230 subDir := filepath.Dir(filepath.Join(currentConfDir, filePath)) 231 if err := os.MkdirAll(subDir, os.ModePerm); err != nil { 232 t.Require().ErrorIs(err, os.ErrExist) 233 } 234 235 // skip dir 236 projectConfPath := filepath.Join(projectConfDir, filePath) 237 currentConfPath := filepath.Join(currentConfDir, filePath) 238 if f, err = os.Stat(projectConfPath); err == nil && !f.IsDir() { 239 copyFileFn(projectConfPath, currentConfPath) 240 continue 241 } 242 t.Require().ErrorIs(err, os.ErrNotExist) 243 } 244 }