Added some testcases for the various file uri transforms to download_test.go

Moved some of the code for normalizing a Windows file uri to a regular path into it's own function NormalizeWindowsURL
This commit is contained in:
Ali Rizvi-Santiago 2016-01-18 17:36:47 -06:00
parent 281dd1258a
commit da9c94b345
2 changed files with 151 additions and 42 deletions

View File

@ -101,6 +101,44 @@ func (d *DownloadClient) Cancel() {
// TODO(mitchellh): Implement
}
// Take a uri and convert it to a path that makes sense on the Windows platform
func NormalizeWindowsURL(basepath string, url url.URL) string {
// This logic must correspond to the same logic in the NormalizeWindowsURL
// function found in common/config.go since that function _also_ checks that
// the url actually exists in file form.
const UNCPrefix = string(os.PathSeparator)+string(os.PathSeparator)
// move any extra path components that were parsed into Host due
// to UNC into the url.Path field so that it's PathSeparators get
// normalized
if len(url.Host) >= len(UNCPrefix) && url.Host[:len(UNCPrefix)] == UNCPrefix {
idx := strings.Index(url.Host[len(UNCPrefix):], string(os.PathSeparator))
if idx > -1 {
url.Path = filepath.ToSlash(url.Host[idx+len(UNCPrefix):]) + url.Path
url.Host = url.Host[:idx+len(UNCPrefix)]
}
}
// clean up backward-slashes since they only matter when part of a unc path
urlPath := filepath.ToSlash(url.Path)
// semi-absolute path (current drive letter) -- file:///absolute/path
if url.Host == "" && len(urlPath) > 0 && urlPath[0] == '/' {
return path.Join(filepath.VolumeName(basepath), urlPath)
// relative path -- file://./relative/path
// file://relative/path
} else if url.Host == "" || (len(url.Host) > 0 && url.Host[0] == '.') {
return path.Join(filepath.ToSlash(basepath), urlPath)
}
// absolute path
// UNC -- file://\\host/share/whatever
// drive -- file://c:/absolute/path
return path.Join(url.Host, urlPath)
}
func (d *DownloadClient) Get() (string, error) {
// If we already have the file and it matches, then just return the target path.
if verify, _ := d.VerifyChecksum(d.config.TargetPath); verify {
@ -133,49 +171,17 @@ func (d *DownloadClient) Get() (string, error) {
// locally and we don't make a copy. Normally we would copy or download.
log.Printf("[DEBUG] Using local file: %s", finalPath)
// FIXME:
// cwd should point to the path relative to client.json, but
// since this isn't exposed to us anywhere, we use os.Getwd()
// to figure it out.
cwd,err := os.Getwd()
if err != nil {
return "", fmt.Errorf("Unable to get working directory")
}
// convert the actual file uri to a windowsy path
// (this logic must correspond to the same logic in common/config.go)
// transform the actual file uri to a windowsy path if we're being windowsy.
if runtime.GOOS == "windows" {
const UNCPrefix = string(os.PathSeparator)+string(os.PathSeparator)
// move any extra path components that were parsed into Host due
// to UNC into the url.Path field so that it's PathSeparators get
// normalized
if len(url.Host) >= len(UNCPrefix) && url.Host[:len(UNCPrefix)] == UNCPrefix {
idx := strings.Index(url.Host[len(UNCPrefix):], string(os.PathSeparator))
if idx > -1 {
url.Path = filepath.ToSlash(url.Host[idx+len(UNCPrefix):]) + url.Path
url.Host = url.Host[:idx+len(UNCPrefix)]
}
}
// clean up backward-slashes since they only matter when part of a unc path
urlPath := filepath.ToSlash(url.Path)
// semi-absolute path (current drive letter) -- file:///absolute/path
if url.Host == "" && len(urlPath) > 0 && urlPath[0] == '/' {
finalPath = path.Join(filepath.VolumeName(cwd), urlPath)
// relative path -- file://./relative/path
// file://relative/path
} else if url.Host == "" || (len(url.Host) > 0 && url.Host[0] == '.') {
finalPath = path.Join(filepath.ToSlash(cwd), urlPath)
// absolute path
} else {
// UNC -- file://\\host/share/whatever
// drive -- file://c:/absolute/path
finalPath = path.Join(url.Host, urlPath)
// FIXME: cwd should point to a path relative to the TEMPLATE path,
// but since this isn't exposed to us anywhere, we use os.Getwd()
// and assume the user ran packer in the same directory that
// any relative files are located at.
cwd,err := os.Getwd()
if err != nil {
return "", fmt.Errorf("Unable to get working directory")
}
finalPath = NormalizeWindowsURL(cwd, *url)
}
// Keep track of the source so we can make sure not to delete this later

View File

@ -9,6 +9,8 @@ import (
"net/http/httptest"
"os"
"runtime"
"strings"
"path/filepath"
"testing"
)
@ -382,5 +384,106 @@ func TestDownloadFileUrl(t *testing.T) {
if _, err = os.Stat(sourcePath); err != nil {
t.Errorf("Could not stat source file: %s", sourcePath)
}
}
// SimulateFileUriDownload is a simple utility function that converts a uri
// into a testable file path whilst ignoring a correct checksum match, stripping
// UNC path info, and then calling stat to ensure the correct file exists.
// (used by TestFileUriTransforms)
func SimulateFileUriDownload(t *testing.T, uri string) (string,error) {
// source_path is a file path and source is a network path
source := fmt.Sprintf(uri)
t.Logf("Trying to download %s", source)
config := &DownloadConfig{
Url: source,
// This should be wrong. We want to make sure we don't delete
Checksum: []byte("nope"),
Hash: HashForType("sha256"),
CopyFile: false,
}
// go go go
client := NewDownloadClient(config)
path, err := client.Get()
// ignore any non-important checksum errors if it's not a unc path
if !strings.HasPrefix(path, "\\\\") && err.Error() != "checksums didn't match expected: 6e6f7065" {
t.Fatalf("Unexpected failure; expected checksum not to match")
}
// if it's a unc path, then remove the host and share name so we don't have
// to force the user to enable ADMIN$ and Windows File Sharing
if strings.HasPrefix(path, "\\\\") {
res := strings.SplitN(path, "/", 3)
path = "/" + res[2]
}
if _, err = os.Stat(path); err != nil {
t.Errorf("Could not stat source file: %s", path)
}
return path,err
}
// TestFileUriTransforms tests the case where we use a local file uri
// for iso_url. There's a few different formats that a file uri can exist as
// and so we try to test the most useful and common ones.
func TestFileUriTransforms(t *testing.T) {
const testpath = /* have your */ "test-fixtures/fileurl/cake" /* and eat it too */
const host = "localhost"
var cwd string
var volume string
var share string
cwd, err := os.Getwd()
if err != nil {
t.Fatalf("Unable to detect working directory: %s", err)
return
}
cwd = filepath.ToSlash(cwd)
volume = filepath.VolumeName(cwd)
share = volume
if share[len(share)-1] == ':' {
share = share[:len(share)-1] + "$"
}
cwd = cwd[len(volume):]
t.Logf("TestFileUriTransforms : Running with cwd : '%s'", cwd)
t.Logf("TestFileUriTransforms : Running with volume : '%s'", volume)
// ./relative/path -> ./relative/path
// /absolute/path -> /absolute/path
// c:/windows/absolute -> c:/windows/absolute
// \\host/sharename/file -> \\host/sharename/file
testcases := []string{
"./%s",
cwd + "/%s",
volume + cwd + "/%s",
"\\\\" + host + "/" + share + "/" + cwd[1:] + "/%s",
}
// all regular slashed testcases
for _,testcase := range testcases {
uri := "file://" + fmt.Sprintf(testcase, testpath)
t.Logf("TestFileUriTransforms : Trying Uri '%s'", uri)
res,err := SimulateFileUriDownload(t, uri)
if err != nil {
t.Errorf("Unable to transform uri '%s' into a path : %v", uri, err)
}
t.Errorf("TestFileUriTransforms : Result Path '%s'", res)
}
// ...and finally the oddball windows native path
// \\host\sharename\file -> \\host/sharename/file
testpath_native := filepath.FromSlash(testpath)
testcase_native := "\\\\" + host + "\\" + share + "\\" + filepath.FromSlash(cwd[1:]) + "\\%s"
uri := "file://" + fmt.Sprintf(testcase_native, testpath_native)
t.Logf("TestFileUriTransforms : Trying Uri '%s'", uri)
res,err := SimulateFileUriDownload(t, uri)
if err != nil {
t.Errorf("Unable to transform uri '%s' into a path", uri)
return
}
t.Errorf("TestFileUriTransforms : Result Path '%s'", res)
}