template / ci-testing / files / profile_test.go
Branch ci-testing · default branch · all branches
profile_test.go
c62570e2 2022-09-23 Pavel Safronov | 1 | package main |
| 2 | ||
| 3 | import ( | |
9573ca02 2022-11-16 Pavel Safronov | 4 | "io/fs" |
c3fc7a22 2022-10-30 Pavel Safronov | 5 | "os" |
| 6 | "os/exec" | |
| 7 | "os/user" | |
| 8 | "path/filepath" | |
9573ca02 2022-11-16 Pavel Safronov | 9 | "runtime" |
c62570e2 2022-09-23 Pavel Safronov | 10 | "testing" |
c3fc7a22 2022-10-30 Pavel Safronov | 11 | |
| 12 | "github.com/stretchr/testify/assert" | |
c62570e2 2022-09-23 Pavel Safronov | 13 | ) |
| 14 | ||
763c260d 2022-10-06 Pavel Safronov | 15 | func TestValidateProfile(t *testing.T) { |
| 16 | testSuccess := func(profile Profile) { | |
b0586433 2022-10-21 Pavel Safronov | 17 | err := validateProfile(&profile) |
763c260d 2022-10-06 Pavel Safronov | 18 | if err != nil { |
| 19 | t.Errorf("Expected to validate profile '%v', but failed: %v", profile.Name, err) | |
| 20 | } | |
| 21 | } | |
9573ca02 2022-11-16 Pavel Safronov | 22 | testFailure := func(profile Profile, expectedErrStr string) { |
b0586433 2022-10-21 Pavel Safronov | 23 | err := validateProfile(&profile) |
9573ca02 2022-11-16 Pavel Safronov | 24 | assert.NotNil(t, err, "Expected to fail to validate profile '%v', but succeeded") |
| 25 | assert.Contains(t, err.Error(), expectedErrStr, "Expected error to contain '%v', but it didn't", expectedErrStr) | |
763c260d 2022-10-06 Pavel Safronov | 26 | } |
| 27 | ||
| 28 | testSuccess(Profile{ | |
| 29 | Type: FileType, | |
| 30 | Name: "daily", | |
1a02ef4e 2022-10-21 Pavel Safronov | 31 | NamePatterns: []ParameterizedText{"{{.Date}}"}, |
8c15a714 2022-11-04 Pavel Safronov | 32 | Path: "~/test/dir", |
763c260d 2022-10-06 Pavel Safronov | 33 | }) |
05f9e8ef 2022-10-06 Pavel Safronov | 34 | testSuccess(Profile{ |
| 35 | Type: FileType, | |
| 36 | Name: "daily", | |
1a02ef4e 2022-10-21 Pavel Safronov | 37 | NamePatterns: []ParameterizedText{"{{.Date}}"}, |
b0586433 2022-10-21 Pavel Safronov | 38 | File: File{ |
| 39 | Template: "foo", | |
| 40 | }, | |
8c15a714 2022-11-04 Pavel Safronov | 41 | Path: "~/test/dir", |
05f9e8ef 2022-10-06 Pavel Safronov | 42 | }) |
763c260d 2022-10-06 Pavel Safronov | 43 | |
| 44 | testFailure(Profile{ | |
| 45 | Name: "", | |
9573ca02 2022-11-16 Pavel Safronov | 46 | }, "Profile name is required") |
763c260d 2022-10-06 Pavel Safronov | 47 | testFailure(Profile{ |
| 48 | Name: "list", | |
9573ca02 2022-11-16 Pavel Safronov | 49 | }, "forbidden profile name 'list'") |
763c260d 2022-10-06 Pavel Safronov | 50 | testFailure(Profile{ |
| 51 | Name: "get", | |
9573ca02 2022-11-16 Pavel Safronov | 52 | }, "forbidden profile name 'get'") |
763c260d 2022-10-06 Pavel Safronov | 53 | testFailure(Profile{ |
| 54 | Type: FileType, | |
| 55 | Name: "daily", | |
9573ca02 2022-11-16 Pavel Safronov | 56 | }, "namePatterns is required") |
763c260d 2022-10-06 Pavel Safronov | 57 | testFailure(Profile{ |
9573ca02 2022-11-16 Pavel Safronov | 58 | Type: FileType, |
| 59 | Name: "daily", | |
| 60 | NamePatterns: []ParameterizedText{"blah"}, | |
| 61 | }, "path is not specified for profile daily, which has Type=file") | |
8c15a714 2022-11-04 Pavel Safronov | 62 | |
9573ca02 2022-11-16 Pavel Safronov | 63 | testFailure(Profile{ |
| 64 | Type: FolderType, | |
| 65 | Name: "daily", | |
| 66 | NamePatterns: []ParameterizedText{"test"}, | |
| 67 | }, "path is required for profile daily, which has Type=folder") | |
05f9e8ef 2022-10-06 Pavel Safronov | 68 | testFailure(Profile{ |
| 69 | Type: FolderType, | |
| 70 | Name: "daily", | |
1a02ef4e 2022-10-21 Pavel Safronov | 71 | NamePatterns: []ParameterizedText{"test"}, |
b0586433 2022-10-21 Pavel Safronov | 72 | File: File{ |
| 73 | Template: "bar", | |
| 74 | }, | |
9573ca02 2022-11-16 Pavel Safronov | 75 | }, "file template is not supported for profile daily, which has Type=folder") |
05f9e8ef 2022-10-06 Pavel Safronov | 76 | testFailure(Profile{ |
| 77 | Type: ScriptType, | |
| 78 | Name: "daily", | |
1a02ef4e 2022-10-21 Pavel Safronov | 79 | NamePatterns: []ParameterizedText{"test", "test2"}, |
9573ca02 2022-11-16 Pavel Safronov | 80 | }, "multiple name patterns are not supported for profile daily, which has Type=script") |
| 81 | testFailure(Profile{ | |
| 82 | Type: FileType, | |
| 83 | Name: "daily", | |
| 84 | NamePatterns: []ParameterizedText{"test", "test2"}, | |
| 85 | }, "path is not specified for profile daily, which has Type=file") | |
| 86 | testFailure(Profile{ | |
| 87 | Type: FileType, | |
| 88 | Name: "daily", | |
| 89 | NamePatterns: []ParameterizedText{"test", ""}, | |
| 90 | }, "name pattern is required for pattern index 1 of profile daily") | |
763c260d 2022-10-06 Pavel Safronov | 91 | |
| 92 | for _, profile := range defaultConfig().Profiles { | |
| 93 | testSuccess(profile) | |
| 94 | } | |
| 95 | } | |
| 96 | ||
ae89a42a 2022-11-02 Pavel Safronov | 97 | func TestFindProfileIndex(t *testing.T) { |
c62570e2 2022-09-23 Pavel Safronov | 98 | config := Config{ |
| 99 | Profiles: []Profile{ | |
| 100 | { | |
| 101 | Name: "daily", | |
| 102 | }, | |
| 103 | { | |
| 104 | IsDefault: true, | |
| 105 | Name: "notes", | |
| 106 | }, | |
| 107 | }, | |
| 108 | } | |
| 109 | testSuccess := func(profileName string, expectedProfileName string) { | |
ae89a42a 2022-11-02 Pavel Safronov | 110 | index, err := findProfileIndex(config.Profiles, profileName) |
c62570e2 2022-09-23 Pavel Safronov | 111 | if err != nil { |
| 112 | t.Errorf("Failed to find profile '%v': %v", profileName, err) | |
| 113 | } | |
ae89a42a 2022-11-02 Pavel Safronov | 114 | profile := config.Profiles[index] |
c62570e2 2022-09-23 Pavel Safronov | 115 | if profile.Name != expectedProfileName { |
| 116 | t.Errorf("Asked for profile '%v', expected '%v', got '%v'", profileName, expectedProfileName, profile.Name) | |
| 117 | } | |
| 118 | } | |
| 119 | testFailure := func(profileName string) { | |
ae89a42a 2022-11-02 Pavel Safronov | 120 | _, err := findProfileIndex(config.Profiles, profileName) |
c62570e2 2022-09-23 Pavel Safronov | 121 | if err == nil { |
| 122 | t.Errorf("Expected to fail to find profile '%v', but succeeded", profileName) | |
| 123 | } | |
| 124 | } | |
| 125 | ||
| 126 | testSuccess("daily", "daily") | |
| 127 | testSuccess("notes", "notes") | |
| 128 | ||
ae89a42a 2022-11-02 Pavel Safronov | 129 | testFailure("") |
c62570e2 2022-09-23 Pavel Safronov | 130 | testFailure("non-existent") |
05f9e8ef 2022-10-06 Pavel Safronov | 131 | |
| 132 | config.Profiles[1].IsDefault = false | |
| 133 | testFailure("") | |
| 134 | testFailure("non-default") | |
c62570e2 2022-09-23 Pavel Safronov | 135 | } |
c3fc7a22 2022-10-30 Pavel Safronov | 136 | |
ae89a42a 2022-11-02 Pavel Safronov | 137 | func TestFindDefaultProfile(t *testing.T) { |
| 138 | _, err := findDefaultProfile(defaultConfig().Profiles) | |
| 139 | assert.Nil(t, err, "Expected to find default profile, but failed") | |
| 140 | ||
| 141 | _, err = findDefaultProfile([]Profile{}) | |
| 142 | assert.NotNil(t, err, "Expected to fail to find default profile, but succeeded") | |
| 143 | } | |
| 144 | ||
c3fc7a22 2022-10-30 Pavel Safronov | 145 | func TestCreateEntity(t *testing.T) { |
| 146 | // setup | |
| 147 | now := testNow() | |
| 148 | cwd := "~/test/dir" | |
| 149 | projectName := "project-name" | |
| 150 | extras := map[string]string{ | |
| 151 | "foo": "bar", | |
| 152 | } | |
| 153 | patternData := testPrePatternData() | |
| 154 | ||
| 155 | testFolder := func() { | |
| 156 | monkeyPatchCalls := applyTestMonkeyPatch(t, monkeyPatch{ | |
| 157 | OSMkdir: func(path string, perm os.FileMode) error { return nil }, | |
| 158 | OSChdir: func(dir string) error { return nil }, | |
| 159 | OSWriteFile: func(filename string, data []byte, perm os.FileMode) error { return nil }, | |
| 160 | }) | |
| 161 | ||
| 162 | profile := Profile{ | |
| 163 | Type: FolderType, | |
| 164 | Files: []FileInFolder{ | |
| 165 | { | |
| 166 | Name: "readme.md", | |
| 167 | File: File{ | |
| 168 | Template: "blah", | |
| 169 | }, | |
| 170 | }, | |
| 171 | { | |
| 172 | Name: "test.txt", | |
| 173 | File: File{ | |
| 174 | Template: "foo", | |
| 175 | }, | |
| 176 | }, | |
| 177 | }, | |
| 178 | } | |
| 179 | ||
| 180 | newName := "new-name" | |
| 181 | expectedFullPath := filepath.Clean("~/test/dir/" + newName) | |
| 182 | fullPath, err := createEntity(now, profile, cwd, newName, projectName, extras, patternData) | |
| 183 | assert.Nil(t, err) | |
| 184 | assert.Equal(t, expectedFullPath, fullPath) | |
| 185 | assert.Equal(t, 1, len(monkeyPatchCalls.OSChdirCalls)) | |
| 186 | assert.Equal(t, expectedFullPath, monkeyPatchCalls.OSChdirCalls[0].dir) | |
5e424f1b 2022-11-12 Pavel Safronov | 187 | assert.Equal(t, 3, len(monkeyPatchCalls.OSMkdirCalls)) |
c3fc7a22 2022-10-30 Pavel Safronov | 188 | assert.Equal(t, expectedFullPath, monkeyPatchCalls.OSMkdirCalls[0].path) |
| 189 | assert.Equal(t, 2, len(monkeyPatchCalls.OSWriteFileCalls)) | |
| 190 | assert.Equal(t, filepath.Clean(expectedFullPath+"/readme.md"), monkeyPatchCalls.OSWriteFileCalls[0].filename) | |
| 191 | assert.Equal(t, []byte("blah"), monkeyPatchCalls.OSWriteFileCalls[0].data) | |
| 192 | assert.Equal(t, filepath.Clean(expectedFullPath+"/test.txt"), monkeyPatchCalls.OSWriteFileCalls[1].filename) | |
| 193 | assert.Equal(t, []byte("foo"), monkeyPatchCalls.OSWriteFileCalls[1].data) | |
| 194 | } | |
| 195 | ||
| 196 | testFile := func() { | |
| 197 | monkeyPatchCalls := applyTestMonkeyPatch(t, monkeyPatch{ | |
| 198 | OSWriteFile: func(filename string, data []byte, perm os.FileMode) error { return nil }, | |
| 199 | }) | |
| 200 | ||
| 201 | profile := Profile{ | |
| 202 | Type: FileType, | |
| 203 | File: File{ | |
| 204 | Template: "blah", | |
| 205 | }, | |
| 206 | } | |
| 207 | newName := "new-name.md" | |
| 208 | expectedFullPath := filepath.Clean("~/test/dir/" + newName) | |
| 209 | fullPath, err := createEntity(now, profile, cwd, newName, projectName, extras, patternData) | |
| 210 | assert.Nil(t, err) | |
| 211 | assert.Equal(t, expectedFullPath, fullPath) | |
| 212 | assert.Equal(t, 1, len(monkeyPatchCalls.OSWriteFileCalls)) | |
| 213 | assert.Equal(t, expectedFullPath, monkeyPatchCalls.OSWriteFileCalls[0].filename) | |
| 214 | assert.Equal(t, []byte("blah"), monkeyPatchCalls.OSWriteFileCalls[0].data) | |
| 215 | } | |
| 216 | ||
| 217 | testScript := func() { | |
| 218 | profile := Profile{ | |
| 219 | Type: ScriptType, | |
| 220 | PostScripts: []ParameterizedText{ | |
| 221 | "{{.ProjectName}}-{{.Year}}-{{.Month}}-{{.Day}}-{{.Hour}}-{{.Minute}}-{{.Second}}-{{.Extras.key1}}", | |
| 222 | }, | |
| 223 | } | |
| 224 | newName := "new-name.md" | |
| 225 | expectedFullPath := filepath.Clean("~/test/dir/" + newName) | |
| 226 | fullPath, err := createEntity(now, profile, cwd, newName, projectName, extras, patternData) | |
| 227 | assert.Nil(t, err) | |
| 228 | assert.Equal(t, expectedFullPath, fullPath) | |
| 229 | } | |
| 230 | ||
| 231 | testFolder() | |
| 232 | ||
| 233 | testFile() | |
| 234 | ||
| 235 | testScript() | |
| 236 | } | |
| 237 | ||
9573ca02 2022-11-16 Pavel Safronov | 238 | type testFile struct { |
| 239 | name string | |
| 240 | isDir bool | |
| 241 | } | |
| 242 | ||
| 243 | func (f testFile) Name() string { return f.name } | |
| 244 | func (f testFile) IsDir() bool { return f.isDir } | |
| 245 | func (f testFile) Type() fs.FileMode { return 0 } | |
| 246 | func (f testFile) Info() (fs.FileInfo, error) { return nil, nil } | |
| 247 | ||
c3fc7a22 2022-10-30 Pavel Safronov | 248 | func TestProcessProfile(t *testing.T) { |
| 249 | cwd := filepath.Clean("~/test/dir") | |
9573ca02 2022-11-16 Pavel Safronov | 250 | createDirEntry := func(name string, isDir bool) os.DirEntry { |
| 251 | entry := testFile{name: name, isDir: isDir} | |
| 252 | return entry | |
| 253 | } | |
| 254 | var monkeyPatchCalls *monkeyPatchCalls | |
| 255 | configureMonkeyPatching := func() { | |
| 256 | monkeyPatchCalls = applyTestMonkeyPatch(t, monkeyPatch{ | |
| 257 | ExecCommand: func(command string, args ...string) *exec.Cmd { | |
748e3056 2022-11-19 Pavel Safronov | 258 | shell, shellArgs := shellCommandAndArgs("echo") |
| 259 | return exec.Command(shell, shellArgs...) | |
9573ca02 2022-11-16 Pavel Safronov | 260 | }, |
| 261 | OSChdir: func(dir string) error { return nil }, | |
| 262 | OSGetwd: func() (dir string, err error) { return cwd, nil }, | |
| 263 | OSReadDir: func(dirname string) ([]os.DirEntry, error) { | |
| 264 | return []os.DirEntry{ | |
| 265 | createDirEntry("dir1", true), | |
| 266 | createDirEntry("dir2", true), | |
| 267 | createDirEntry("file1", false), | |
| 268 | createDirEntry("file2", false), | |
| 269 | }, nil | |
| 270 | }, | |
| 271 | OSWriteFile: func(filename string, data []byte, perm os.FileMode) error { | |
| 272 | return nil | |
| 273 | }, | |
| 274 | }) | |
| 275 | } | |
c3fc7a22 2022-10-30 Pavel Safronov | 276 | |
| 277 | projectName := "project-name" | |
| 278 | extras := map[string]string{ | |
| 279 | "foo": "bar", | |
| 280 | } | |
a5ad914b 2022-10-30 Pavel Safronov | 281 | |
9573ca02 2022-11-16 Pavel Safronov | 282 | usr, err := user.Current() |
| 283 | assert.Nil(t, err) | |
| 284 | assert.NotNil(t, usr) | |
a5ad914b 2022-10-30 Pavel Safronov | 285 | |
9573ca02 2022-11-16 Pavel Safronov | 286 | testSuccess := func(profile Profile) { |
| 287 | configureMonkeyPatching() | |
a5ad914b 2022-10-30 Pavel Safronov | 288 | errors := processProfile(profile, projectName, extras, *usr) |
| 289 | assert.Equal(t, 0, len(errors)) | |
9573ca02 2022-11-16 Pavel Safronov | 290 | for _, error := range errors { |
| 291 | assert.Nil(t, error) | |
| 292 | } | |
a5ad914b 2022-10-30 Pavel Safronov | 293 | } |
9573ca02 2022-11-16 Pavel Safronov | 294 | testFailure := func(profile Profile, errorCount int, errorStr string) { |
| 295 | configureMonkeyPatching() | |
| 296 | errors := processProfile(profile, projectName, extras, *usr) | |
| 297 | assert.Equal(t, errorCount, len(errors)) | |
| 298 | allErrorsText := "" | |
| 299 | for _, err := range errors { | |
| 300 | allErrorsText += err.Error() | |
a5ad914b 2022-10-30 Pavel Safronov | 301 | } |
9573ca02 2022-11-16 Pavel Safronov | 302 | assert.Contains(t, allErrorsText, errorStr) |
| 303 | } | |
| 304 | testSingleFailure := func(profile Profile, errorStr string) { | |
| 305 | testFailure(profile, 1, errorStr) | |
| 306 | } | |
a5ad914b 2022-10-30 Pavel Safronov | 307 | |
9573ca02 2022-11-16 Pavel Safronov | 308 | // this profile will be built up from failing to eventually passing |
| 309 | currentOS := getCurrentOs() | |
| 310 | profile := Profile{ | |
| 311 | IsDisabled: true, | |
a5ad914b 2022-10-30 Pavel Safronov | 312 | } |
9573ca02 2022-11-16 Pavel Safronov | 313 | testSingleFailure(profile, "Profile is disabled, doing nothing") |
| 314 | profile.IsDisabled = false | |
| 315 | profile.OS = getOtherOs(currentOS) | |
| 316 | testSingleFailure(profile, "This profile is not supported on this OS, doing nothing.") | |
| 317 | profile.OS = currentOS | |
| 318 | // testSingleFailure(profile, "unable to create post scripts: no post scripts specified") | |
a5ad914b 2022-10-30 Pavel Safronov | 319 | |
9573ca02 2022-11-16 Pavel Safronov | 320 | profile.NamePatterns = []ParameterizedText{} |
| 321 | profile.Type = FileType | |
| 322 | testSingleFailure(profile, "couldn't find a good new name") | |
a5ad914b 2022-10-30 Pavel Safronov | 323 | |
9573ca02 2022-11-16 Pavel Safronov | 324 | profile.NamePatterns = []ParameterizedText{"file1"} |
| 325 | profile.RunPostscriptOnFailure = true | |
| 326 | testSingleFailure(profile, "couldn't find a good new name") | |
| 327 | ||
| 328 | profile.NamePatterns = []ParameterizedText{"file3"} | |
| 329 | profile.PostScripts = []ParameterizedText{"echo {{.ProjectName}}-{{.Year}}"} | |
| 330 | profile.Path = "~/test/dir" | |
| 331 | testSuccess(profile) | |
| 332 | assert.Equal(t, 1, len(monkeyPatchCalls.ExecCommandCalls), "calls to ExecCommand") | |
| 333 | assert.Equal(t, 1, len(monkeyPatchCalls.OSChdirCalls), "calls to OSChdir") | |
| 334 | assert.Equal(t, 1, len(monkeyPatchCalls.OSGetwdCalls), "calls to OSGetwd") | |
| 335 | assert.Equal(t, 1, len(monkeyPatchCalls.OSReadDirCalls), "calls to OSReadDir") | |
| 336 | assert.Equal(t, 1, len(monkeyPatchCalls.OSWriteFileCalls), "calls to OSWriteFile") | |
| 337 | ||
| 338 | profile.PostScripts = []ParameterizedText{"echo ''"} | |
| 339 | testSuccess(profile) | |
| 340 | assert.Equal(t, 1, len(monkeyPatchCalls.ExecCommandCalls), "calls to ExecCommand") | |
| 341 | assert.Equal(t, 1, len(monkeyPatchCalls.OSChdirCalls), "calls to OSChdir") | |
| 342 | assert.Equal(t, 1, len(monkeyPatchCalls.OSGetwdCalls), "calls to OSGetwd") | |
| 343 | assert.Equal(t, 1, len(monkeyPatchCalls.OSReadDirCalls), "calls to OSReadDir") | |
| 344 | assert.Equal(t, 1, len(monkeyPatchCalls.OSWriteFileCalls), "calls to OSWriteFile") | |
| 345 | } | |
| 346 | ||
| 347 | func getCurrentOs() OSType { | |
| 348 | os := runtime.GOOS | |
| 349 | if os == "windows" { | |
| 350 | return "Windows" | |
| 351 | } else { | |
| 352 | return "Mac" | |
| 353 | } | |
| 354 | } | |
| 355 | func getOtherOs(currentOs OSType) OSType { | |
9b0177be 2022-11-19 Pavel Safronov | 356 | if currentOs == "Windows" { |
9573ca02 2022-11-16 Pavel Safronov | 357 | return "Mac" |
| 358 | } | |
| 359 | return "Windows" | |
c3fc7a22 2022-10-30 Pavel Safronov | 360 | } |