package common import ( "fmt" "io/ioutil" "os" "path/filepath" "runtime" "strings" "testing" ) func TestChooseString(t *testing.T) { cases := []struct { Input []string Output string }{ { []string{"", "foo", ""}, "foo", }, { []string{"", "foo", "bar"}, "foo", }, { []string{"", "", ""}, "", }, } for _, tc := range cases { result := ChooseString(tc.Input...) if result != tc.Output { t.Fatalf("bad: %#v", tc.Input) } } } func TestValidatedURL(t *testing.T) { // Invalid URL: has hex code in host _, err := ValidatedURL("http://what%20.com") if err == nil { t.Fatalf("expected err : %s", err) } // Invalid: unsupported scheme _, err = ValidatedURL("ftp://host.com/path") if err == nil { t.Fatalf("expected err : %s", err) } // Valid: http u, err := ValidatedURL("HTTP://packer.io/path") if err != nil { t.Fatalf("err: %s", err) } if u != "http://packer.io/path" { t.Fatalf("bad: %s", u) } cases := []struct { InputString string OutputURL string ErrExpected bool }{ // Invalid URL: has hex code in host {"http://what%20.com", "", true}, // Valid: http {"HTTP://packer.io/path", "http://packer.io/path", false}, // No path {"HTTP://packer.io", "http://packer.io", false}, // Invalid: unsupported scheme {"ftp://host.com/path", "", true}, } for _, tc := range cases { u, err := ValidatedURL(tc.InputString) if u != tc.OutputURL { t.Fatal(fmt.Sprintf("Error with URL %s: got %s but expected %s", tc.InputString, tc.OutputURL, u)) } if (err != nil) != tc.ErrExpected { if tc.ErrExpected == true { t.Fatal(fmt.Sprintf("Error with URL %s: we expected "+ "ValidatedURL to return an error but didn't get one.", tc.InputString)) } else { t.Fatal(fmt.Sprintf("Error with URL %s: we did not expect an "+ " error from ValidatedURL but we got: %s", tc.InputString, err)) } } } } func GetNativePathToTestFixtures(t *testing.T) string { const path = "./test-fixtures" res, err := filepath.Abs(path) if err != nil { t.Fatalf("err converting test-fixtures path into an absolute path : %s", err) } return res } func GetPortablePathToTestFixtures(t *testing.T) string { res := GetNativePathToTestFixtures(t) return filepath.ToSlash(res) } func TestDownloadableURL_WindowsFiles(t *testing.T) { if runtime.GOOS == "windows" { portablepath := GetPortablePathToTestFixtures(t) nativepath := GetNativePathToTestFixtures(t) dirCases := []struct { InputString string OutputURL string ErrExpected bool }{ // TODO: add different directories { fmt.Sprintf("%s\\SomeDir\\myfile.txt", nativepath), fmt.Sprintf("file:///%s/SomeDir/myfile.txt", portablepath), false, }, { // without the drive makes this native path a relative file:// uri "test-fixtures\\SomeDir\\myfile.txt", fmt.Sprintf("file:///%s/SomeDir/myfile.txt", portablepath), false, }, { // without the drive makes this native path a relative file:// uri "test-fixtures/SomeDir/myfile.txt", fmt.Sprintf("file:///%s/SomeDir/myfile.txt", portablepath), false, }, { // UNC paths being promoted to smb:// uri scheme. fmt.Sprintf("\\\\localhost\\C$\\%s\\SomeDir\\myfile.txt", nativepath), fmt.Sprintf("smb://localhost/C$/%s/SomeDir/myfile.txt", portablepath), false, }, { // Absolute uri (incorrect slash type) fmt.Sprintf("file:///%s\\SomeDir\\myfile.txt", nativepath), fmt.Sprintf("file:///%s/SomeDir/myfile.txt", portablepath), false, }, { // Absolute uri (existing and mis-spelled) fmt.Sprintf("file:///%s/Somedir/myfile.txt", nativepath), fmt.Sprintf("file:///%s/SomeDir/myfile.txt", portablepath), false, }, { // Absolute path (non-existing) "\\absolute\\path\\to\\non-existing\\file.txt", "file:///absolute/path/to/non-existing/file.txt", false, }, { // Absolute paths (existing) fmt.Sprintf("%s/SomeDir/myfile.txt", nativepath), fmt.Sprintf("file:///%s/SomeDir/myfile.txt", portablepath), false, }, { // Relative path (non-existing) "./nonexisting/relative/path/to/file.txt", "file://./nonexisting/relative/path/to/file.txt", false, }, { // Relative path (existing) "./test-fixtures/SomeDir/myfile.txt", fmt.Sprintf("file:///%s/SomeDir/myfile.txt", portablepath), false, }, { // Absolute uri (existing and with `/` prefix) fmt.Sprintf("file:///%s/SomeDir/myfile.txt", portablepath), fmt.Sprintf("file:///%s/SomeDir/myfile.txt", portablepath), false, }, { // Absolute uri (non-existing and with `/` prefix) "file:///path/to/non-existing/file.txt", "file:///path/to/non-existing/file.txt", false, }, { // Absolute uri (non-existing and missing `/` prefix) "file://path/to/non-existing/file.txt", "file://path/to/non-existing/file.txt", false, }, { // Absolute uri and volume (non-existing and with `/` prefix) "file:///T:/path/to/non-existing/file.txt", "file:///T:/path/to/non-existing/file.txt", false, }, { // Absolute uri and volume (non-existing and missing `/` prefix) "file://T:/path/to/non-existing/file.txt", "file://T:/path/to/non-existing/file.txt", false, }, } // Run through test cases to make sure they all parse correctly for idx, tc := range dirCases { u, err := DownloadableURL(tc.InputString) if (err != nil) != tc.ErrExpected { t.Fatalf("Test Case %d failed: Expected err = %#v, err = %#v, input = %s", idx, tc.ErrExpected, err, tc.InputString) } if u != tc.OutputURL { t.Fatalf("Test Case %d failed: Expected %s but received %s from input %s", idx, tc.OutputURL, u, tc.InputString) } } } } func TestDownloadableURL_FilePaths(t *testing.T) { tf, err := ioutil.TempFile("", "packer") if err != nil { t.Fatalf("tempfile err: %s", err) } defer os.Remove(tf.Name()) tf.Close() tfPath, err := filepath.EvalSymlinks(tf.Name()) if err != nil { t.Fatalf("tempfile err: %s", err) } tfPath = filepath.Clean(tfPath) filePrefix := "file://" // If we're running windows, then absolute URIs are `/`-prefixed. platformPrefix := "" if runtime.GOOS == "windows" { platformPrefix = "/" } // Relative filepath. We run this test in a func so that // the defers run right away. func() { wd, err := os.Getwd() if err != nil { t.Fatalf("getwd err: %s", err) } err = os.Chdir(filepath.Dir(tfPath)) if err != nil { t.Fatalf("chdir err: %s", err) } defer os.Chdir(wd) filename := filepath.Base(tfPath) u, err := DownloadableURL(filename) if err != nil { t.Fatalf("err: %s", err) } expected := fmt.Sprintf("%s%s%s", filePrefix, platformPrefix, strings.Replace(tfPath, `\`, `/`, -1)) if u != expected { t.Fatalf("unexpected: %#v != %#v", u, expected) } }() // Test some cases with and without a schema prefix for _, prefix := range []string{"", filePrefix + platformPrefix} { // Nonexistent file _, err = DownloadableURL(prefix + "i/dont/exist") if err != nil { t.Fatalf("err: %s", err) } // Good file (absolute) u, err := DownloadableURL(prefix + tfPath) if err != nil { t.Fatalf("err: %s", err) } expected := fmt.Sprintf("%s%s%s", filePrefix, platformPrefix, strings.Replace(tfPath, `\`, `/`, -1)) if u != expected { t.Fatalf("unexpected: %s != %s", u, expected) } } } func TestFileExistsLocally(t *testing.T) { portablepath := GetPortablePathToTestFixtures(t) dirCases := []struct { Input string Output bool }{ // file exists locally {fmt.Sprintf("file://%s/SomeDir/myfile.txt", portablepath), true}, // remote protocols short-circuit and are considered to exist locally {"https://myfile.iso", true}, // non-existent protocols do not exist and hence fail {"nonexistent-protocol://myfile.iso", false}, // file does not exist locally {"file:///C/i/dont/exist", false}, } // Run through test cases to make sure they all parse correctly for _, tc := range dirCases { fileOK := FileExistsLocally(tc.Input) if fileOK != tc.Output { t.Fatalf("Test Case failed: Expected %#v, received = %#v, input = %s", tc.Output, fileOK, tc.Input) } } }