Skip to content

Commit

Permalink
Merge pull request #11 from hashicorp/nywilken/update-windows-symlink…
Browse files Browse the repository at this point in the history
…-test

Update test to work on Windows

* Fix up test for HttpGetter to handle git failure due to repository not actually existing.
  • Loading branch information
nywilken committed May 19, 2022
2 parents 8bae039 + 6fb9692 commit 1e36fc9
Show file tree
Hide file tree
Showing 5 changed files with 306 additions and 18 deletions.
2 changes: 2 additions & 0 deletions get_file_test.go
@@ -1,3 +1,5 @@
// +build test unix

package getter

import (
Expand Down
263 changes: 263 additions & 0 deletions get_file_windows_test.go
@@ -0,0 +1,263 @@
// +build test windows

package getter

import (
"context"
"os"
"path/filepath"
"testing"

testing_helper "github.com/hashicorp/go-getter/v2/helper/testing"
urlhelper "github.com/hashicorp/go-getter/v2/helper/url"
)

func TestFileGetter_impl(t *testing.T) {
var _ Getter = new(FileGetter)
}

func TestFileGetter(t *testing.T) {
g := new(FileGetter)
dst := testing_helper.TempDir(t)
ctx := context.Background()

req := &Request{
Dst: dst,
u: testModuleURL("basic"),
}

// With a dir that doesn't exist
if err := g.Get(ctx, req); err != nil {
t.Fatalf("err: %s", err)
}

// Verify the destination folder is a symlink
fi, err := os.Lstat(dst)
if err != nil {
t.Fatalf("err: %s", err)
}
if fi.Mode()&os.ModeSymlink == 0 {
t.Fatal("destination is not a symlink")
}

// Verify the main file exists
mainPath := filepath.Join(dst, "main.tf")
if _, err := os.Stat(mainPath); err != nil {
t.Fatalf("err: %s", err)
}
}

func TestFileGetter_sourceFile(t *testing.T) {
g := new(FileGetter)
dst := testing_helper.TempDir(t)
ctx := context.Background()

// With a source URL that is a path to a file
u := testModuleURL("basic")
u.Path += "/main.tf"
u.RawPath = u.Path

req := &Request{
Dst: dst,
u: u,
}
if err := g.Get(ctx, req); err == nil {
t.Fatal("should error")
}
}

func TestFileGetter_sourceNoExist(t *testing.T) {
g := new(FileGetter)
dst := testing_helper.TempDir(t)
ctx := context.Background()

// With a source URL that doesn't exist
u := testModuleURL("basic")
u.Path += "/main"
u.RawPath = u.Path

req := &Request{
Dst: dst,
u: u,
}
if err := g.Get(ctx, req); err == nil {
t.Fatal("should error")
}
}

func TestFileGetter_dir(t *testing.T) {
g := new(FileGetter)
dst := testing_helper.TempDir(t)
ctx := context.Background()

if err := os.MkdirAll(dst, 0755); err != nil {
t.Fatalf("err: %s", err)
}

req := &Request{
Dst: dst,
u: testModuleURL("basic"),
}
// With a dir that exists that isn't a symlink
if err := g.Get(ctx, req); err == nil {
t.Fatal("should error")
}
}

func TestFileGetter_dirSymlink(t *testing.T) {
g := new(FileGetter)
dst := testing_helper.TempDir(t)
ctx := context.Background()

dst2 := testing_helper.TempDir(t)

// Make parents
if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
t.Fatalf("err: %s", err)
}
if err := os.MkdirAll(dst2, 0755); err != nil {
t.Fatalf("err: %s", err)
}

// Make a symlink
if err := os.Symlink(dst2, dst); err != nil {
t.Fatalf("err: %s", err)
}

req := &Request{
Dst: dst,
u: testModuleURL("basic"),
}

// With a dir that exists that isn't a symlink
if err := g.Get(ctx, req); err != nil {
t.Fatalf("err: %s", err)
}

// Verify the main file exists
mainPath := filepath.Join(dst, "main.tf")
if _, err := os.Stat(mainPath); err != nil {
t.Fatalf("err: %s", err)
}
}

func TestFileGetter_GetFile(t *testing.T) {
g := new(FileGetter)
dst := testing_helper.TempTestFile(t)
defer os.RemoveAll(filepath.Dir(dst))
ctx := context.Background()

req := &Request{
Dst: dst,
u: testModuleURL("basic-file/foo.txt"),
}

// With a dir that doesn't exist
if err := g.GetFile(ctx, req); err != nil {
t.Fatalf("err: %s", err)
}

// Verify the destination folder is a symlink
fi, err := os.Lstat(dst)
if err != nil {
t.Fatalf("err: %s", err)
}
if fi.Mode()&os.ModeSymlink == 0 {
t.Fatal("destination is not a symlink")
}

// Verify the main file exists
testing_helper.AssertContents(t, dst, "Hello\r\n")
}

func TestFileGetter_GetFile_Copy(t *testing.T) {
g := new(FileGetter)

dst := testing_helper.TempTestFile(t)
defer os.RemoveAll(filepath.Dir(dst))
ctx := context.Background()

req := &Request{
Dst: dst,
u: testModuleURL("basic-file/foo.txt"),
Copy: true,
}

// With a dir that doesn't exist
if err := g.GetFile(ctx, req); err != nil {
t.Fatalf("err: %s", err)
}

// Verify the destination folder is a symlink
fi, err := os.Lstat(dst)
if err != nil {
t.Fatalf("err: %s", err)
}
if fi.Mode()&os.ModeSymlink != 0 {
t.Fatal("destination is a symlink")
}

// Verify the main file exists
testing_helper.AssertContents(t, dst, "Hello\r\n")
}

// https://github.com/hashicorp/terraform/issues/8418
func TestFileGetter_percent2F(t *testing.T) {
g := new(FileGetter)
dst := testing_helper.TempDir(t)
ctx := context.Background()

req := &Request{
Dst: dst,
u: testModuleURL("basic%2Ftest"),
}

// With a dir that doesn't exist
if err := g.Get(ctx, req); err != nil {
t.Fatalf("err: %s", err)
}

// Verify the main file exists
mainPath := filepath.Join(dst, "main.tf")
if _, err := os.Stat(mainPath); err != nil {
t.Fatalf("err: %s", err)
}
}

func TestFileGetter_Mode_notexist(t *testing.T) {
g := new(FileGetter)
ctx := context.Background()

u := urlhelper.MustParse("nonexistent")
if _, err := g.Mode(ctx, u); err == nil {
t.Fatal("expect source file error")
}
}

func TestFileGetter_Mode_file(t *testing.T) {
g := new(FileGetter)
ctx := context.Background()

// Check the client mode when pointed at a file.
mode, err := g.Mode(ctx, testModuleURL("basic-file/foo.txt"))
if err != nil {
t.Fatalf("err: %s", err)
}
if mode != ModeFile {
t.Fatal("expect ModeFile")
}
}

func TestFileGetter_Mode_dir(t *testing.T) {
g := new(FileGetter)
ctx := context.Background()

// Check the client mode when pointed at a directory.
mode, err := g.Mode(ctx, testModuleURL("basic"))
if err != nil {
t.Fatalf("err: %s", err)
}
if mode != ModeDir {
t.Fatal("expect ModeDir")
}
}
29 changes: 24 additions & 5 deletions get_git_test.go
Expand Up @@ -775,11 +775,30 @@ func TestGitGetter_subdirectory_symlink(t *testing.T) {

ctx := context.Background()
_, err = client.Get(ctx, req)
if err == nil {
t.Fatalf("expected client get to fail")
}
if !errors.Is(err, ErrSymlinkCopy) {
t.Fatalf("unexpected error: %v", err)
if runtime.GOOS == "windows" {
// Windows doesn't handle symlinks as one might expect with git.
//
// https://github.com/git-for-windows/git/wiki/Symbolic-Links
filepath.Walk(dst, func(path string, info os.FileInfo, err error) error {
if strings.Contains(path, "this-is-a-symlink") {
if info.Mode()&os.ModeSymlink == os.ModeSymlink {
// If you see this test fail in the future, you've probably enabled
// symlinks within git on your Windows system. Our CI/CD system does
// not do this, so this is the only way we can make this test
// make any sense.
t.Fatalf("windows git should not have cloned a symlink")
}
}
return nil
})
} else {
// We can rely on POSIX compliant systems running git to do the right thing.
if err == nil {
t.Fatalf("expected client get to fail")
}
if !errors.Is(err, ErrSymlinkCopy) {
t.Fatalf("unexpected error: %v", err)
}
}
}

Expand Down
28 changes: 16 additions & 12 deletions get_http_test.go
Expand Up @@ -702,23 +702,23 @@ func TestHttpGetter__XTerraformGetConfiguredGettersBypass(t *testing.T) {
errExpected bool
}{
{name: "configured getter for git protocol switch", configuredGetters: []Getter{new(GitGetter)}, errExpected: false},
{name: "configured getter for multiple protocol switch", configuredGetters: []Getter{new(HgGetter), new(GitGetter), new(FileGetter)}, errExpected: false},
{name: "configured getter for multiple protocol switch", configuredGetters: []Getter{new(GitGetter), new(HgGetter), new(FileGetter)}, errExpected: false},
{name: "configured getter for file protocol switch", configuredGetters: []Getter{new(FileGetter)}, errExpected: true},
}

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

ln := testHttpServerWithXTerraformGetConfiguredGettersBypass(t)

var u url.URL
u.Scheme = "http"
u.Host = ln.Addr().String()
u.Path = "/start"

for _, tt := range tc {
tt := tt
t.Run(tt.name, func(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

ln := testHttpServerWithXTerraformGetConfiguredGettersBypass(t)

var u url.URL
u.Scheme = "http"
u.Host = ln.Addr().String()
u.Path = "/start"

dst := testing_helper.TempDir(t)

rt := hookableHTTPRoundTripper{
Expand Down Expand Up @@ -747,11 +747,15 @@ func TestHttpGetter__XTerraformGetConfiguredGettersBypass(t *testing.T) {
GetMode: ModeDir,
}


_, err := client.Get(ctx, &req)
// For configured getters that support git, the git repository doesn't exist so error will not be nil.
// If we get a nil error when we expect one other than the git error git exited with -1 we should fail.
if tt.errExpected && err == nil {
t.Fatalf("error expected")
}
if err != nil {
// We only care about the error messages that indicate that we can download the git header URL
if tt.errExpected && err != nil {
if !strings.Contains(err.Error(), "download not supported for scheme") {
t.Fatalf("expected download not supported for scheme, got: %v", err)
}
Expand Down
2 changes: 1 addition & 1 deletion helper/testing/utils.go
Expand Up @@ -34,7 +34,7 @@ func AssertContents(t *testing.T, path string, contents string) {
}

if !reflect.DeepEqual(data, []byte(contents)) {
t.Fatalf("bad. expected:\n\n%s\n\nGot:\n\n%s", contents, string(data))
t.Fatalf("bad. expected:\n\n%q\n\nGot:\n\n%q", contents, string(data))
}
}

Expand Down

0 comments on commit 1e36fc9

Please sign in to comment.