diff --git a/.changes/unreleased/FEATURES-20240806-142303.yaml b/.changes/unreleased/FEATURES-20240806-142303.yaml new file mode 100644 index 00000000..b5134165 --- /dev/null +++ b/.changes/unreleased/FEATURES-20240806-142303.yaml @@ -0,0 +1,5 @@ +kind: FEATURES +body: 'data-source/archive_file: Add support for creating `tar.gz` archive files.' +time: 2024-08-06T14:23:03.200664-04:00 +custom: + Issue: "277" diff --git a/.changes/unreleased/FEATURES-20240806-142529.yaml b/.changes/unreleased/FEATURES-20240806-142529.yaml new file mode 100644 index 00000000..9ade31d5 --- /dev/null +++ b/.changes/unreleased/FEATURES-20240806-142529.yaml @@ -0,0 +1,5 @@ +kind: FEATURES +body: 'resource/archive_file: Add support for creating `tar.gz` archive files.' +time: 2024-08-06T14:25:29.318873-04:00 +custom: + Issue: "277" diff --git a/docs/data-sources/file.md b/docs/data-sources/file.md index f390d0c9..7a6246a5 100644 --- a/docs/data-sources/file.md +++ b/docs/data-sources/file.md @@ -58,7 +58,7 @@ data "archive_file" "lambda_my_function" { ### Required - `output_path` (String) The output of the archive file. -- `type` (String) The type of archive to generate. NOTE: `zip` is supported. +- `type` (String) The type of archive to generate. NOTE: `zip` and `tar.gz` is supported. ### Optional diff --git a/go.mod b/go.mod index 39f50c64..8f03e560 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/hashicorp/terraform-plugin-framework-validators v0.13.0 github.com/hashicorp/terraform-plugin-go v0.23.0 github.com/hashicorp/terraform-plugin-testing v1.9.0 + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 ) require ( @@ -54,12 +55,12 @@ require ( github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/zclconf/go-cty v1.14.4 // indirect golang.org/x/crypto v0.25.0 // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.25.0 // indirect + golang.org/x/mod v0.19.0 // indirect + golang.org/x/net v0.27.0 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.22.0 // indirect golang.org/x/text v0.16.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + golang.org/x/tools v0.23.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect google.golang.org/grpc v1.63.2 // indirect diff --git a/go.sum b/go.sum index e2d3a2f6..ddbbc5e3 100644 --- a/go.sum +++ b/go.sum @@ -164,15 +164,17 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= +golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -204,8 +206,8 @@ golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= +golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= diff --git a/internal/provider/archiver.go b/internal/provider/archiver.go index 5cd4794b..8dcf12b2 100644 --- a/internal/provider/archiver.go +++ b/internal/provider/archiver.go @@ -24,7 +24,8 @@ type Archiver interface { type ArchiverBuilder func(outputPath string) Archiver var archiverBuilders = map[string]ArchiverBuilder{ - "zip": NewZipArchiver, + "zip": NewZipArchiver, + "tar.gz": NewTarGzArchiver, } func getArchiver(archiveType string, outputPath string) Archiver { @@ -42,16 +43,18 @@ func assertValidFile(infilename string) (os.FileInfo, error) { return fi, err } -func assertValidDir(indirname string) (os.FileInfo, error) { +func assertValidDir(indirname string) error { fi, err := os.Stat(indirname) if err != nil { if os.IsNotExist(err) { - return fi, fmt.Errorf("could not archive missing directory: %s", indirname) + return fmt.Errorf("could not archive missing directory: %s", indirname) } - return fi, err + return err } + if !fi.IsDir() { - return fi, fmt.Errorf("could not archive directory that is a file: %s", indirname) + return fmt.Errorf("could not archive directory that is a file: %s", indirname) } - return fi, nil + + return nil } diff --git a/internal/provider/data_source_archive_file.go b/internal/provider/data_source_archive_file.go index 507d1dd5..c65755bf 100644 --- a/internal/provider/data_source_archive_file.go +++ b/internal/provider/data_source_archive_file.go @@ -80,7 +80,7 @@ func (d *archiveFileDataSource) Schema(ctx context.Context, req datasource.Schem Computed: true, }, "type": schema.StringAttribute{ - Description: "The type of archive to generate. NOTE: `zip` is supported.", + Description: "The type of archive to generate. NOTE: `zip` and `tar.gz` is supported.", Required: true, }, "source_content": schema.StringAttribute{ diff --git a/internal/provider/data_source_archive_file_test.go b/internal/provider/data_source_archive_file_test.go index d9afe27f..3585b322 100644 --- a/internal/provider/data_source_archive_file_test.go +++ b/internal/provider/data_source_archive_file_test.go @@ -7,122 +7,12 @@ import ( "fmt" "os" "path/filepath" - "regexp" "testing" r "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" ) -func TestAccArchiveFile_Basic(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - var fileSize string - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: testAccArchiveFileContentConfig(f), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttr( - "data.archive_file.foo", "output_md5", "ea35f0444ea9a3d5641d8760bc2815cc", - ), - r.TestCheckResourceAttr( - "data.archive_file.foo", "output_sha", "019c79c4dc14dbe1edb3e467b2de6a6aad148717", - ), - r.TestCheckResourceAttr( - "data.archive_file.foo", "output_sha256", "3fb55c931a048943b8d7558dde7c2e4bfc8e04be33b1b55691053d1352391fa7", - ), - r.TestCheckResourceAttr( - "data.archive_file.foo", "output_base64sha256", "P7VckxoEiUO411WN3nwuS/yOBL4zsbVWkQU9E1I5H6c=", - ), - r.TestCheckResourceAttr( - "data.archive_file.foo", "output_sha512", "57e2d073dce214609bd61113b90b0b2b7c75034047224d56e35f363c8f2662e3acd561eebf94826a67453411181eca7e1cbf15db1f2fdd496cf13df46b7848c3", - ), - r.TestCheckResourceAttr( - "data.archive_file.foo", "output_base64sha512", "V+LQc9ziFGCb1hETuQsLK3x1A0BHIk1W4182PI8mYuOs1WHuv5SCamdFNBEYHsp+HL8V2x8v3Uls8T30a3hIww==", - ), - ), - }, - { - Config: testAccArchiveFileFileConfig(f), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttr( - "data.archive_file.foo", "output_md5", "59fbc9e62af3cbc2f588f97498240dae", - ), - r.TestCheckResourceAttr( - "data.archive_file.foo", "output_sha", "ce4ee1450ab93ac86e11446649e44cea907b6568", - ), - r.TestCheckResourceAttr( - "data.archive_file.foo", "output_sha256", "5131387f97167da47aa741df3ab2c82f182f17c514c222538d34708d04e0756b", - ), - r.TestCheckResourceAttr( - "data.archive_file.foo", "output_base64sha256", "UTE4f5cWfaR6p0HfOrLILxgvF8UUwiJTjTRwjQTgdWs=", - ), - r.TestCheckResourceAttr( - "data.archive_file.foo", "output_sha512", "eb33eb0f8cd8efe1a5a0b99acbd22ed22dbebb80817f8de6e8fed15c21c52240838d9bb46fb0938846c74f694425551ba60829a6396f91fcfe49d21a1e3bb409", - ), - r.TestCheckResourceAttr( - "data.archive_file.foo", "output_base64sha512", "6zPrD4zY7+GloLmay9Iu0i2+u4CBf43m6P7RXCHFIkCDjZu0b7CTiEbHT2lEJVUbpggppjlvkfz+SdIaHju0CQ==", - ), - ), - }, - { - Config: testAccArchiveFileDirConfig(f), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttr( - "data.archive_file.foo", "output_md5", "b73f64a383716070aa4a29563b8b14d4", - ), - r.TestCheckResourceAttr( - "data.archive_file.foo", "output_sha", "76d20a402eefd1cfbdc47886abd4e0909616c191", - ), - r.TestCheckResourceAttr( - "data.archive_file.foo", "output_sha256", "c9d07cc2dabc9caf6f43bed51fa613c281e6ca58cae3a8d6fae2094b00b3369a", - ), - r.TestCheckResourceAttr( - "data.archive_file.foo", "output_base64sha256", "ydB8wtq8nK9vQ77VH6YTwoHmyljK46jW+uIJSwCzNpo=", - ), - r.TestCheckResourceAttr( - "data.archive_file.foo", "output_sha512", "b96ac6b9554a04473a733be36f190422bf7162b4afdb211a0f551713eadf4092459426750646c70383ce6c8b89171b88582a608e5841bfaaafa17004a2a2ca0a", - ), - r.TestCheckResourceAttr( - "data.archive_file.foo", "output_base64sha512", "uWrGuVVKBEc6czvjbxkEIr9xYrSv2yEaD1UXE+rfQJJFlCZ1BkbHA4PObIuJFxuIWCpgjlhBv6qvoXAEoqLKCg==", - ), - ), - }, - { - Config: testAccArchiveFileDirExcludesConfig(f), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), - ), - }, - { - Config: testAccArchiveFileDirExcludesGlobConfig(f), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), - ), - }, - { - Config: testAccArchiveFileMultiSourceConfig(f), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), - ), - }, - }, - }) -} - func TestDataSource_UpgradeFromVersion2_2_0_ContentConfig(t *testing.T) { td := t.TempDir() @@ -139,7 +29,7 @@ func TestDataSource_UpgradeFromVersion2_2_0_ContentConfig(t *testing.T) { Source: "hashicorp/archive", }, }, - Config: testAccArchiveFileContentConfig(f), + Config: testAccArchiveFileContentConfig("zip", f), Check: r.ComposeTestCheckFunc( testAccArchiveFileSize(f, &fileSize), r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), @@ -156,7 +46,7 @@ func TestDataSource_UpgradeFromVersion2_2_0_ContentConfig(t *testing.T) { }, { ProtoV5ProviderFactories: protoV5ProviderFactories(), - Config: testAccArchiveFileContentConfig(f), + Config: testAccArchiveFileContentConfig("zip", f), Check: r.ComposeTestCheckFunc( r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), r.TestCheckResourceAttr( @@ -190,7 +80,7 @@ func TestDataSource_UpgradeFromVersion2_2_0_FileConfig(t *testing.T) { Source: "hashicorp/archive", }, }, - Config: testAccArchiveFileFileConfig(f), + Config: testAccArchiveFileFileConfig("zip", f), Check: r.ComposeTestCheckFunc( testAccArchiveFileSize(f, &fileSize), r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), @@ -207,7 +97,7 @@ func TestDataSource_UpgradeFromVersion2_2_0_FileConfig(t *testing.T) { }, { ProtoV5ProviderFactories: protoV5ProviderFactories(), - Config: testAccArchiveFileFileConfig(f), + Config: testAccArchiveFileFileConfig("zip", f), Check: r.ComposeTestCheckFunc( r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), r.TestCheckResourceAttr( @@ -241,7 +131,7 @@ func TestDataSource_UpgradeFromVersion2_2_0_DirConfig(t *testing.T) { Source: "hashicorp/archive", }, }, - Config: testAccArchiveFileDirConfig(f), + Config: testAccArchiveFileDirConfig("zip", f), Check: r.ComposeTestCheckFunc( testAccArchiveFileSize(f, &fileSize), r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), @@ -258,7 +148,7 @@ func TestDataSource_UpgradeFromVersion2_2_0_DirConfig(t *testing.T) { }, { ProtoV5ProviderFactories: protoV5ProviderFactories(), - Config: testAccArchiveFileDirConfig(f), + Config: testAccArchiveFileDirConfig("zip", f), Check: r.ComposeTestCheckFunc( r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), r.TestCheckResourceAttr( @@ -292,7 +182,7 @@ func TestDataSource_UpgradeFromVersion2_2_0_DirExcludesConfig(t *testing.T) { Source: "hashicorp/archive", }, }, - Config: testAccArchiveFileDirExcludesConfig(f), + Config: testAccArchiveFileDirExcludesConfig("zip", f), Check: r.ComposeTestCheckFunc( testAccArchiveFileSize(f, &fileSize), testExtractResourceAttr("data.archive_file.foo", "output_sha", &outputSha), @@ -301,7 +191,7 @@ func TestDataSource_UpgradeFromVersion2_2_0_DirExcludesConfig(t *testing.T) { }, { ProtoV5ProviderFactories: protoV5ProviderFactories(), - Config: testAccArchiveFileDirExcludesConfig(f), + Config: testAccArchiveFileDirExcludesConfig("zip", f), Check: r.ComposeTestCheckFunc( r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_sha", &outputSha), @@ -327,7 +217,7 @@ func TestDataSource_UpgradeFromVersion2_2_0_SourceConfig(t *testing.T) { Source: "hashicorp/archive", }, }, - Config: testAccArchiveFileMultiSourceConfig(f), + Config: testAccArchiveFileMultiSourceConfig("zip", f), Check: r.ComposeTestCheckFunc( testAccArchiveFileSize(f, &fileSize), testExtractResourceAttr("data.archive_file.foo", "output_sha", &outputSha), @@ -336,7 +226,7 @@ func TestDataSource_UpgradeFromVersion2_2_0_SourceConfig(t *testing.T) { }, { ProtoV5ProviderFactories: protoV5ProviderFactories(), - Config: testAccArchiveFileMultiSourceConfig(f), + Config: testAccArchiveFileMultiSourceConfig("zip", f), Check: r.ComposeTestCheckFunc( r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_sha", &outputSha), @@ -346,1097 +236,103 @@ func TestDataSource_UpgradeFromVersion2_2_0_SourceConfig(t *testing.T) { }) } -func TestAccArchiveFile_SourceConfigMissing(t *testing.T) { - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: testAccArchiveSourceConfigMissing(), - ExpectError: regexp.MustCompile(`.*At least one of these attributes must be configured:\n\[source,source_content_filename,source_file,source_dir\]`), - }, - }, - }) +func testAccArchiveFileSize(filename string, fileSize *string) r.TestCheckFunc { + return func(s *terraform.State) error { + *fileSize = "" + fi, err := os.Stat(filename) + if err != nil { + return err + } + *fileSize = fmt.Sprintf("%d", fi.Size()) + return nil + } } -func TestAccArchiveFile_SourceConfigConflicting(t *testing.T) { - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: testAccArchiveSourceConfigConflicting(), - ExpectError: regexp.MustCompile(`.*Attribute "source_dir" cannot be specified when "source" is specified`), - }, - }, - }) +func testAccArchiveFileContentConfig(format, outputPath string) string { + return fmt.Sprintf(` +data "archive_file" "foo" { + type = "%s" + source_content = "This is some content" + source_content_filename = "content.txt" + output_path = "%s" } - -// TestAccArchiveFile_SymlinkFile_Relative verifies that a symlink to a file using a relative path generates an -// archive which includes the file. -func TestAccArchiveFile_SymlinkFile_Relative(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - data "archive_file" "foo" { - type = "zip" - source_file = "%s" - output_path = "%s" - output_file_mode = "0666" - } - `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-file/test-symlink.txt"), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-symlink.txt": []byte(`This is test content`), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) +`, format, filepath.ToSlash(outputPath)) } -// TestAccArchiveFile_SymlinkFile_Absolute verifies that a symlink to a file using an absolute path generates an -// archive which includes the file. -func TestAccArchiveFile_SymlinkFile_Absolute(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - symlinkFileAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-file/test-symlink.txt") - if err != nil { - t.Fatal(err) - } - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - data "archive_file" "foo" { - type = "zip" - source_file = "%s" - output_path = "%s" - output_file_mode = "0666" - } - `, filepath.ToSlash(symlinkFileAbs), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-symlink.txt": []byte(`This is test content`), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) +func testAccArchiveFileFileConfig(format, outputPath string) string { + return fmt.Sprintf(` +data "archive_file" "foo" { + type = "%s" + source_file = "test-fixtures/test-dir/test-file.txt" + output_path = "%s" + output_file_mode = "0666" } - -// TestAccArchiveFile_SymlinkDirectory_Relative verifies that a symlink to a directory using a relative path -// generates an archive which includes the files in the directory. -func TestAccArchiveFile_SymlinkDirectory_Relative(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - data "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - output_file_mode = "0666" - } - `, filepath.ToSlash("test-fixtures/test-symlink-dir"), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "file1.txt": []byte(`This is file 1`), - "file2.txt": []byte(`This is file 2`), - "file3.txt": []byte(`This is file 3`), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) +`, format, filepath.ToSlash(outputPath)) } -// TestAccArchiveFile_SymlinkDirectory_Absolute verifies that a symlink to a directory using an absolute path -// generates an archive which includes the files in the directory. -func TestAccArchiveFile_SymlinkDirectory_Absolute(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - symlinkDirWithRegularFilesAbs, err := filepath.Abs("test-fixtures/test-symlink-dir") - if err != nil { - t.Fatal(err) - } - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - data "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - output_file_mode = "0666" - } - `, filepath.ToSlash(symlinkDirWithRegularFilesAbs), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "file1.txt": []byte(`This is file 1`), - "file2.txt": []byte(`This is file 2`), - "file3.txt": []byte(`This is file 3`), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) +func testAccArchiveFileDirConfig(format, outputPath string) string { + return fmt.Sprintf(` +data "archive_file" "foo" { + type = "%s" + source_dir = "test-fixtures/test-dir/test-dir1" + output_path = "%s" + output_file_mode = "0666" } - -// TestAccArchiveFile_DirectoryWithSymlinkFile_Relative verifies that a relative path to a directory containing -// a symlink file generates an archive which includes the files in the directory. -func TestAccArchiveFile_DirectoryWithSymlinkFile_Relative(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - data "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - output_file_mode = "0666" - } - `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-file"), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-file.txt": []byte(`This is test content`), - "test-symlink.txt": []byte(`This is test content`), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) +`, format, filepath.ToSlash(outputPath)) } -// TestAccArchiveFile_DirectoryWithSymlinkFile_Absolute verifies that an absolute path to a directory containing -// a symlink file generates an archive which includes the files in the directory. -func TestAccArchiveFile_DirectoryWithSymlinkFile_Absolute(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") +func testAccArchiveFileDirExcludesConfig(format, outputPath string) string { + return fmt.Sprintf(` +data "archive_file" "foo" { + type = "%s" + source_dir = "test-fixtures/test-dir/test-dir1" + excludes = ["test-fixtures/test-dir/test-dir1/file2.txt"] + output_path = "%s" +} +`, format, filepath.ToSlash(outputPath)) +} - symlinkDirWithSymlinkFilesAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-file") - if err != nil { - t.Fatal(err) - } +func testAccArchiveFileDirExcludesGlobConfig(format, outputPath string) string { + return fmt.Sprintf(` +data "archive_file" "foo" { + type = "%s" + source_dir = "test-fixtures/test-dir/test-dir1" + excludes = ["test-fixtures/test-dir/test-dir1/file2.txt", "**/file[2-3].txt"] + output_path = "%s" +} +`, format, filepath.ToSlash(outputPath)) +} - var fileSize string +func testAccArchiveFileMultiSourceConfig(format, outputPath string) string { + return fmt.Sprintf(` +data "archive_file" "foo" { + type = "%s" + source { + filename = "content_1.txt" + content = "This is the content for content_1.txt" + } + source { + filename = "content_2.txt" + content = "This is the content for content_2.txt" + } + output_path = "%s" +} +`, format, filepath.ToSlash(outputPath)) +} - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - data "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - output_file_mode = "0666" - } - `, filepath.ToSlash(symlinkDirWithSymlinkFilesAbs), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-file.txt": []byte(`This is test content`), - "test-symlink.txt": []byte(`This is test content`), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) +func testAccArchiveSourceConfigMissing(format string) string { + return fmt.Sprintf(` +data "archive_file" "foo" { + type = "%s" + output_path = "path" +} +`, format) } -// TestAccArchiveFile_SymlinkDirectoryWithSymlinkFile_Relative verifies that a relative path to a symlink -// file in a symlink directory generates an archive which includes the files in the directory. -func TestAccArchiveFile_SymlinkDirectoryWithSymlinkFile_Relative(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - data "archive_file" "foo" { - type = "zip" - source_file = "%s" - output_path = "%s" - output_file_mode = "0666" - } - `, filepath.ToSlash("test-fixtures/test-symlink-dir-with-symlink-file/test-symlink.txt"), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-symlink.txt": []byte(`This is test content`), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) -} - -// TestAccArchiveFile_SymlinkDirectoryWithSymlinkFile_Absolute verifies that an absolute path to a symlink -// file in a symlink directory generates an archive which includes the files in the directory. -func TestAccArchiveFile_SymlinkDirectoryWithSymlinkFile_Absolute(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - symlinkFileInSymlinkDirAbs, err := filepath.Abs("test-fixtures/test-symlink-dir-with-symlink-file/test-symlink.txt") - if err != nil { - t.Fatal(err) - } - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - data "archive_file" "foo" { - type = "zip" - source_file = "%s" - output_path = "%s" - output_file_mode = "0666" - } - `, filepath.ToSlash(symlinkFileInSymlinkDirAbs), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-symlink.txt": []byte(`This is test content`), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) -} - -// TestAccArchiveFile_DirectoryWithSymlinkDirectory_Relative verifies that a relative path to a -// directory containing a symlink to a directory generates an archive which includes the directory. -func TestAccArchiveFile_DirectoryWithSymlinkDirectory_Relative(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - data "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - output_file_mode = "0666" - } - `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-dir"), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-symlink-dir/file1.txt": []byte("This is file 1"), - "test-symlink-dir/file2.txt": []byte("This is file 2"), - "test-symlink-dir/file3.txt": []byte("This is file 3"), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) -} - -// TestAccArchiveFile_IncludeDirectoryWithSymlinkDirectory_Absolute verifies that an absolute path to a -// directory containing a symlink to a directory generates an archive which includes the directory. -func TestAccArchiveFile_IncludeDirectoryWithSymlinkDirectory_Absolute(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - symlinkDirInRegularDirAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-dir") - if err != nil { - t.Fatal(err) - } - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - data "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - output_file_mode = "0666" - } - `, filepath.ToSlash(symlinkDirInRegularDirAbs), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-symlink-dir/file1.txt": []byte("This is file 1"), - "test-symlink-dir/file2.txt": []byte("This is file 2"), - "test-symlink-dir/file3.txt": []byte("This is file 3"), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) -} - -// TestAccArchiveFile_Multiple_Relative verifies that a relative path to a directory containing multiple -// directories including symlink directories generates an archive which includes the directories and files. -func TestAccArchiveFile_Multiple_Relative(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - data "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - output_file_mode = "0666" - } - `, filepath.ToSlash("test-fixtures"), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-dir/test-dir1/file1.txt": []byte("This is file 1"), - "test-dir/test-dir1/file2.txt": []byte("This is file 2"), - "test-dir/test-dir1/file3.txt": []byte("This is file 3"), - "test-dir/test-dir2/file1.txt": []byte("This is file 1"), - "test-dir/test-dir2/file2.txt": []byte("This is file 2"), - "test-dir/test-dir2/file3.txt": []byte("This is file 3"), - "test-dir/test-file.txt": []byte("This is test content"), - "test-dir-with-symlink-dir/test-symlink-dir/file1.txt": []byte("This is file 1"), - "test-dir-with-symlink-dir/test-symlink-dir/file2.txt": []byte("This is file 2"), - "test-dir-with-symlink-dir/test-symlink-dir/file3.txt": []byte("This is file 3"), - "test-dir-with-symlink-file/test-file.txt": []byte("This is test content"), - "test-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), - "test-symlink-dir/file1.txt": []byte("This is file 1"), - "test-symlink-dir/file2.txt": []byte("This is file 2"), - "test-symlink-dir/file3.txt": []byte("This is file 3"), - "test-symlink-dir-with-symlink-file/test-file.txt": []byte("This is test content"), - "test-symlink-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) -} - -// TestAccArchiveFile_Multiple_Absolute verifies that an absolute path to a directory containing multiple -// directories including symlink directories generates an archive which includes the directories and files. -func TestAccArchiveFile_Multiple_Absolute(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - multipleDirsAndFilesAbs, err := filepath.Abs("test-fixtures") - if err != nil { - t.Fatal(err) - } - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - data "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - output_file_mode = "0666" - } - `, filepath.ToSlash(multipleDirsAndFilesAbs), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-dir/test-dir1/file1.txt": []byte("This is file 1"), - "test-dir/test-dir1/file2.txt": []byte("This is file 2"), - "test-dir/test-dir1/file3.txt": []byte("This is file 3"), - "test-dir/test-dir2/file1.txt": []byte("This is file 1"), - "test-dir/test-dir2/file2.txt": []byte("This is file 2"), - "test-dir/test-dir2/file3.txt": []byte("This is file 3"), - "test-dir/test-file.txt": []byte("This is test content"), - "test-dir-with-symlink-dir/test-symlink-dir/file1.txt": []byte("This is file 1"), - "test-dir-with-symlink-dir/test-symlink-dir/file2.txt": []byte("This is file 2"), - "test-dir-with-symlink-dir/test-symlink-dir/file3.txt": []byte("This is file 3"), - "test-dir-with-symlink-file/test-file.txt": []byte("This is test content"), - "test-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), - "test-symlink-dir/file1.txt": []byte("This is file 1"), - "test-symlink-dir/file2.txt": []byte("This is file 2"), - "test-symlink-dir/file3.txt": []byte("This is file 3"), - "test-symlink-dir-with-symlink-file/test-file.txt": []byte("This is test content"), - "test-symlink-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) -} - -// TestAccArchiveFile_SymlinkFile_Relative_ExcludeSymlinkDirectories verifies that a symlink to a file using a relative -// path generates an archive which includes the file. -func TestAccArchiveFile_SymlinkFile_Relative_ExcludeSymlinkDirectories(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - data "archive_file" "foo" { - type = "zip" - source_file = "%s" - output_path = "%s" - output_file_mode = "0666" - exclude_symlink_directories = true - } - `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-file/test-symlink.txt"), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-symlink.txt": []byte(`This is test content`), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) -} - -// TestAccArchiveFile_SymlinkFile_Absolute_ExcludeSymlinkDirectories verifies that a symlink to a file using an absolute -// path generates an archive which includes the file. -func TestAccArchiveFile_SymlinkFile_Absolute_ExcludeSymlinkDirectories(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - symlinkFileAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-file/test-symlink.txt") - if err != nil { - t.Fatal(err) - } - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - data "archive_file" "foo" { - type = "zip" - source_file = "%s" - output_path = "%s" - output_file_mode = "0666" - exclude_symlink_directories = true - } - `, filepath.ToSlash(symlinkFileAbs), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-symlink.txt": []byte(`This is test content`), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) -} - -// TestAccArchiveFile_SymlinkDirectory_Relative_ExcludeSymlinkDirectories verifies that an empty archive -// is generated when trying to archive a directory which only contains a symlink to a directory. -func TestAccArchiveFile_SymlinkDirectory_Relative_ExcludeSymlinkDirectories(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - data "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - output_file_mode = "0666" - exclude_symlink_directories = true - } - `, filepath.ToSlash("test-fixtures/test-symlink-dir"), filepath.ToSlash(f)), - ExpectError: regexp.MustCompile(`.*error creating archive: error archiving directory: archive has not been\ncreated as it would be empty`), - }, - }, - }) -} - -// TestAccArchiveFile_SymlinkDirectory_Absolute_ExcludeSymlinkDirectories verifies that an empty archive -// is generated when trying to archive a directory which only contains a symlink to a directory. -func TestAccArchiveFile_SymlinkDirectory_Absolute_ExcludeSymlinkDirectories(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - symlinkDirWithRegularFilesAbs, err := filepath.Abs("test-fixtures/test-symlink-dir") - if err != nil { - t.Fatal(err) - } - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - data "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - output_file_mode = "0666" - exclude_symlink_directories = true - } - `, filepath.ToSlash(symlinkDirWithRegularFilesAbs), filepath.ToSlash(f)), - ExpectError: regexp.MustCompile(`.*error creating archive: error archiving directory: archive has not been\ncreated as it would be empty`), - }, - }, - }) -} - -// TestAccArchiveFile_DirectoryWithSymlinkFile_Relative_ExcludeSymlinkDirectories verifies that a relative path to a -// directory containing a symlink file generates an archive which includes the files in the directory. -func TestAccArchiveFile_DirectoryWithSymlinkFile_Relative_ExcludeSymlinkDirectories(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - data "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - output_file_mode = "0666" - exclude_symlink_directories = true - } - `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-file"), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-file.txt": []byte(`This is test content`), - "test-symlink.txt": []byte(`This is test content`), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) -} - -// TestAccArchiveFile_DirectoryWithSymlinkFile_Absolute_ExcludeSymlinkDirectories verifies that an absolute path to a -// directory containing a symlink file generates an archive which includes the files in the directory. -func TestAccArchiveFile_DirectoryWithSymlinkFile_Absolute_ExcludeSymlinkDirectories(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - symlinkDirWithSymlinkFilesAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-file") - if err != nil { - t.Fatal(err) - } - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - data "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - output_file_mode = "0666" - exclude_symlink_directories = true - } - `, filepath.ToSlash(symlinkDirWithSymlinkFilesAbs), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-file.txt": []byte(`This is test content`), - "test-symlink.txt": []byte(`This is test content`), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) -} - -// TestAccArchiveFile_SymlinkDirectoryWithSymlinkFile_Relative_ExcludeSymlinkDirectories verifies that a relative path -// to a symlink file in a symlink directory generates an archive which includes the files in the directory. -func TestAccArchiveFile_SymlinkDirectoryWithSymlinkFile_Relative_ExcludeSymlinkDirectories(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - data "archive_file" "foo" { - type = "zip" - source_file = "%s" - output_path = "%s" - output_file_mode = "0666" - exclude_symlink_directories = true - } - `, filepath.ToSlash("test-fixtures/test-symlink-dir-with-symlink-file/test-symlink.txt"), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-symlink.txt": []byte(`This is test content`), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) -} - -// TestAccArchiveFile_SymlinkDirectoryWithSymlinkFile_Absolute_ExcludeSymlinkDirectories verifies that an absolute path -// to a symlink file in a symlink directory generates an archive which includes the files in the directory. -func TestAccArchiveFile_SymlinkDirectoryWithSymlinkFile_Absolute_ExcludeSymlinkDirectories(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - symlinkFileInSymlinkDirAbs, err := filepath.Abs("test-fixtures/test-symlink-dir-with-symlink-file/test-symlink.txt") - if err != nil { - t.Fatal(err) - } - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - data "archive_file" "foo" { - type = "zip" - source_file = "%s" - output_path = "%s" - output_file_mode = "0666" - exclude_symlink_directories = true - } - `, filepath.ToSlash(symlinkFileInSymlinkDirAbs), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-symlink.txt": []byte(`This is test content`), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) -} - -// TestAccArchiveFile_DirectoryWithSymlinkDirectory_Relative_ExcludeSymlinkDirectories verifies that an empty archive -// is generated when trying to archive a directory which only contains a symlink to a directory. -func TestAccArchiveFile_DirectoryWithSymlinkDirectory_Relative_ExcludeSymlinkDirectories(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - data "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - exclude_symlink_directories = true - } - `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-dir"), filepath.ToSlash(f)), - ExpectError: regexp.MustCompile(`.*error creating archive: error archiving directory: archive has not been\ncreated as it would be empty`), - }, - }, - }) -} - -// TestAccArchiveFile_IncludeDirectoryWithSymlinkDirectory_Absolute_ExcludeSymlinkDirectories verifies that an empty archive -// is generated when trying to archive a directory which only contains a symlink to a directory. -func TestAccArchiveFile_IncludeDirectoryWithSymlinkDirectory_Absolute_ExcludeSymlinkDirectories(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - symlinkDirInRegularDirAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-dir") - if err != nil { - t.Fatal(err) - } - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - data "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - exclude_symlink_directories = true - } - `, filepath.ToSlash(symlinkDirInRegularDirAbs), filepath.ToSlash(f)), - ExpectError: regexp.MustCompile(`.*error creating archive: error archiving directory: archive has not been\ncreated as it would be empty`), - }, - }, - }) -} - -// TestAccArchiveFile_Multiple_Relative_ExcludeSymlinkDirectories verifies that -// symlinked directories are excluded. -func TestAccArchiveFile_Multiple_Relative_ExcludeSymlinkDirectories(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - data "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - output_file_mode = "0666" - exclude_symlink_directories = true - } - `, filepath.ToSlash("test-fixtures"), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-dir/test-dir1/file1.txt": []byte("This is file 1"), - "test-dir/test-dir1/file2.txt": []byte("This is file 2"), - "test-dir/test-dir1/file3.txt": []byte("This is file 3"), - "test-dir/test-dir2/file1.txt": []byte("This is file 1"), - "test-dir/test-dir2/file2.txt": []byte("This is file 2"), - "test-dir/test-dir2/file3.txt": []byte("This is file 3"), - "test-dir/test-file.txt": []byte("This is test content"), - "test-dir-with-symlink-file/test-file.txt": []byte("This is test content"), - "test-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) -} - -// TestAccArchiveFile_Multiple_Relative_ExcludeSymlinkDirectories verifies that -// symlinked directories are excluded. -func TestAccArchiveFile_Multiple_Absolute_ExcludeSymlinkDirectories(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - multipleDirsAndFilesAbs, err := filepath.Abs("test-fixtures") - if err != nil { - t.Fatal(err) - } - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - data "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - output_file_mode = "0666" - exclude_symlink_directories = true - } - `, filepath.ToSlash(multipleDirsAndFilesAbs), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-dir/test-dir1/file1.txt": []byte("This is file 1"), - "test-dir/test-dir1/file2.txt": []byte("This is file 2"), - "test-dir/test-dir1/file3.txt": []byte("This is file 3"), - "test-dir/test-dir2/file1.txt": []byte("This is file 1"), - "test-dir/test-dir2/file2.txt": []byte("This is file 2"), - "test-dir/test-dir2/file3.txt": []byte("This is file 3"), - "test-dir/test-file.txt": []byte("This is test content"), - "test-dir-with-symlink-file/test-file.txt": []byte("This is test content"), - "test-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) -} - -func testAccArchiveFileSize(filename string, fileSize *string) r.TestCheckFunc { - return func(s *terraform.State) error { - *fileSize = "" - fi, err := os.Stat(filename) - if err != nil { - return err - } - *fileSize = fmt.Sprintf("%d", fi.Size()) - return nil - } -} - -func testAccArchiveFileContentConfig(outputPath string) string { - return fmt.Sprintf(` -data "archive_file" "foo" { - type = "zip" - source_content = "This is some content" - source_content_filename = "content.txt" - output_path = "%s" -} -`, filepath.ToSlash(outputPath)) -} - -func testAccArchiveFileFileConfig(outputPath string) string { - return fmt.Sprintf(` -data "archive_file" "foo" { - type = "zip" - source_file = "test-fixtures/test-dir/test-file.txt" - output_path = "%s" - output_file_mode = "0666" -} -`, filepath.ToSlash(outputPath)) -} - -func testAccArchiveFileDirConfig(outputPath string) string { - return fmt.Sprintf(` -data "archive_file" "foo" { - type = "zip" - source_dir = "test-fixtures/test-dir/test-dir1" - output_path = "%s" - output_file_mode = "0666" -} -`, filepath.ToSlash(outputPath)) -} - -func testAccArchiveFileDirExcludesConfig(outputPath string) string { - return fmt.Sprintf(` -data "archive_file" "foo" { - type = "zip" - source_dir = "test-fixtures/test-dir/test-dir1" - excludes = ["test-fixtures/test-dir/test-dir1/file2.txt"] - output_path = "%s" -} -`, filepath.ToSlash(outputPath)) -} - -func testAccArchiveFileDirExcludesGlobConfig(outputPath string) string { - return fmt.Sprintf(` -data "archive_file" "foo" { - type = "zip" - source_dir = "test-fixtures/test-dir/test-dir1" - excludes = ["test-fixtures/test-dir/test-dir1/file2.txt", "**/file[2-3].txt"] - output_path = "%s" -} -`, filepath.ToSlash(outputPath)) -} - -func testAccArchiveFileMultiSourceConfig(outputPath string) string { +func testAccArchiveSourceConfigConflicting(format string) string { return fmt.Sprintf(` data "archive_file" "foo" { - type = "zip" - source { - filename = "content_1.txt" - content = "This is the content for content_1.txt" - } - source { - filename = "content_2.txt" - content = "This is the content for content_2.txt" - } - output_path = "%s" -} -`, filepath.ToSlash(outputPath)) -} - -func testAccArchiveSourceConfigMissing() string { - return ` -data "archive_file" "foo" { - type = "zip" - output_path = "path" -} -` -} - -func testAccArchiveSourceConfigConflicting() string { - return ` -data "archive_file" "foo" { - type = "zip" + type = "%s" source { filename = "content_1.txt" content = "This is the content for content_1.txt" @@ -1444,7 +340,7 @@ data "archive_file" "foo" { source_dir = "test-fixtures/test-dir" output_path = "path" } -` +`, format) } //nolint:unparam diff --git a/internal/provider/data_source_archive_file_tgz_test.go b/internal/provider/data_source_archive_file_tgz_test.go new file mode 100644 index 00000000..35619fe4 --- /dev/null +++ b/internal/provider/data_source_archive_file_tgz_test.go @@ -0,0 +1,1116 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package archive + +import ( + "fmt" + "path/filepath" + "regexp" + "testing" + + r "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestAccTarGzArchiveFile_Basic(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + var fileSize string + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: testAccArchiveFileContentConfig("tar.gz", f), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_md5", "a09ee39e708c38ccd9ba44cc39e7cacc", + ), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_sha", "6c84af188d367644731196007301c9dc93914b0e", + ), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_sha256", "ae18ec27af576dd62f29cec7ae0df130e7487c1a3cddefdec9f27d5ed3a4ca95", + ), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_base64sha256", "rhjsJ69XbdYvKc7Hrg3xMOdIfBo83e/eyfJ9XtOkypU=", + ), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_sha512", "ce93a8ba072bad42656a41def0c9ed160f9109c1a7087fb0dcf0b9fce9effc25477f9cdbf9cbc5aa593f3ded0e0db11d2c8cf67dc8d2693ff4069aa01071e68d", + ), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_base64sha512", "zpOougcrrUJlakHe8MntFg+RCcGnCH+w3PC5/Onv/CVHf5zb+cvFqlk/Pe0ODbEdLIz2fcjSaT/0BpqgEHHmjQ==", + ), + ), + }, + { + Config: testAccArchiveFileFileConfig("tar.gz", f), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_md5", "39948f8ddedc8914ac2e42dd18dd3c06", + ), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_sha", "d2f26a69cbb920715f797f81c1477c41d8fc9195", + ), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_sha256", "6f1b1a5d17e42fae154f0bdf9301a0ad43394d7fe8485b64dfdb533a0cf07784", + ), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_base64sha256", "bxsaXRfkL64VTwvfkwGgrUM5TX/oSFtk39tTOgzwd4Q=", + ), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_sha512", "e0dc636c3d11095a5b5e97c598185ee3d8a0ed7d1accb69cc28419aeeaeda22b2e774a260f71892a2e85efae1a3aee36669b61dafaed9ac0886d2ca8c5add6e9", + ), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_base64sha512", "4NxjbD0RCVpbXpfFmBhe49ig7X0azLacwoQZrurtoisud0omD3GJKi6F764aOu42Zpth2vrtmsCIbSyoxa3W6Q==", + ), + ), + }, + { + Config: testAccArchiveFileDirConfig("tar.gz", f), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_md5", "6678fae1fe2077c767bac136861e3bdc", + ), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_sha", "3af6ef3c57aaa5ab3681cd25f916d6651b806cb6", + ), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_sha256", "1b10e0f355025819486fb688aa04217939ea976cd271089bc0092e2994dbaaba", + ), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_base64sha256", "GxDg81UCWBlIb7aIqgQheTnql2zScQibwAkuKZTbqro=", + ), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_sha512", "adb56fca1e40420d4f994d031a08ca0d1ee51783f3c5d1631b6ed2b460ff2577f9154cb5f1c06edd0b0162899f7cfa7cc3d1f02ec9c9ae76f7ea64a31ba8cb81", + ), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_base64sha512", "rbVvyh5AQg1PmU0DGgjKDR7lF4PzxdFjG27StGD/JXf5FUy18cBu3QsBYomffPp8w9HwLsnJrnb36mSjG6jLgQ==", + ), + ), + }, + { + Config: testAccArchiveFileDirExcludesConfig("tar.gz", f), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + ), + }, + { + Config: testAccArchiveFileDirExcludesGlobConfig("tar.gz", f), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + ), + }, + { + Config: testAccArchiveFileMultiSourceConfig("tar.gz", f), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + ), + }, + }, + }) +} + +func TestAccTarGzArchiveFile_SourceConfigMissing(t *testing.T) { + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: testAccArchiveSourceConfigMissing("tar.gz"), + ExpectError: regexp.MustCompile(`.*At least one of these attributes must be configured:\n\[source,source_content_filename,source_file,source_dir\]`), + }, + }, + }) +} + +func TestAccTarGzArchiveFile_SourceConfigConflicting(t *testing.T) { + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: testAccArchiveSourceConfigConflicting("tar.gz"), + ExpectError: regexp.MustCompile(`.*Attribute "source_dir" cannot be specified when "source" is specified`), + }, + }, + }) +} + +// TestAccTarGzArchiveFile_SymlinkFile_Relative verifies that a symlink to a file using a relative path generates an +// archive which includes the file. +func TestAccTarGzArchiveFile_SymlinkFile_Relative(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "tar.gz" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-file/test-symlink.txt"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccTarGzArchiveFile_SymlinkFile_Absolute verifies that a symlink to a file using an absolute path generates an +// archive which includes the file. +func TestAccTarGzArchiveFile_SymlinkFile_Absolute(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + symlinkFileAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-file/test-symlink.txt") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "tar.gz" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash(symlinkFileAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccTarGzArchiveFile_SymlinkDirectory_Relative verifies that a symlink to a directory using a relative path +// generates an archive which includes the files in the directory. +func TestAccTarGzArchiveFile_SymlinkDirectory_Relative(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash("test-fixtures/test-symlink-dir"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "file1.txt": []byte(`This is file 1`), + "file2.txt": []byte(`This is file 2`), + "file3.txt": []byte(`This is file 3`), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccTarGzArchiveFile_SymlinkDirectory_Absolute verifies that a symlink to a directory using an absolute path +// generates an archive which includes the files in the directory. +func TestAccTarGzArchiveFile_SymlinkDirectory_Absolute(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + symlinkDirWithRegularFilesAbs, err := filepath.Abs("test-fixtures/test-symlink-dir") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash(symlinkDirWithRegularFilesAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "file1.txt": []byte(`This is file 1`), + "file2.txt": []byte(`This is file 2`), + "file3.txt": []byte(`This is file 3`), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccTarGzArchiveFile_DirectoryWithSymlinkFile_Relative verifies that a relative path to a directory containing +// a symlink file generates an archive which includes the files in the directory. +func TestAccTarGzArchiveFile_DirectoryWithSymlinkFile_Relative(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-file"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-file.txt": []byte(`This is test content`), + "test-symlink.txt": []byte(`This is test content`), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccTarGzArchiveFile_DirectoryWithSymlinkFile_Absolute verifies that an absolute path to a directory containing +// a symlink file generates an archive which includes the files in the directory. +func TestAccTarGzArchiveFile_DirectoryWithSymlinkFile_Absolute(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + symlinkDirWithSymlinkFilesAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-file") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash(symlinkDirWithSymlinkFilesAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-file.txt": []byte(`This is test content`), + "test-symlink.txt": []byte(`This is test content`), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccTarGzArchiveFile_SymlinkDirectoryWithSymlinkFile_Relative verifies that a relative path to a symlink +// file in a symlink directory generates an archive which includes the files in the directory. +func TestAccTarGzArchiveFile_SymlinkDirectoryWithSymlinkFile_Relative(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "tar.gz" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash("test-fixtures/test-symlink-dir-with-symlink-file/test-symlink.txt"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccTarGzArchiveFile_SymlinkDirectoryWithSymlinkFile_Absolute verifies that an absolute path to a symlink +// file in a symlink directory generates an archive which includes the files in the directory. +func TestAccTarGzArchiveFile_SymlinkDirectoryWithSymlinkFile_Absolute(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + symlinkFileInSymlinkDirAbs, err := filepath.Abs("test-fixtures/test-symlink-dir-with-symlink-file/test-symlink.txt") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "tar.gz" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash(symlinkFileInSymlinkDirAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccTarGzArchiveFile_DirectoryWithSymlinkDirectory_Relative verifies that a relative path to a +// directory containing a symlink to a directory generates an archive which includes the directory. +func TestAccTarGzArchiveFile_DirectoryWithSymlinkDirectory_Relative(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-dir"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-symlink-dir/file1.txt": []byte("This is file 1"), + "test-symlink-dir/file2.txt": []byte("This is file 2"), + "test-symlink-dir/file3.txt": []byte("This is file 3"), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccTarGzArchiveFile_IncludeDirectoryWithSymlinkDirectory_Absolute verifies that an absolute path to a +// directory containing a symlink to a directory generates an archive which includes the directory. +func TestAccTarGzArchiveFile_IncludeDirectoryWithSymlinkDirectory_Absolute(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + symlinkDirInRegularDirAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-dir") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash(symlinkDirInRegularDirAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-symlink-dir/file1.txt": []byte("This is file 1"), + "test-symlink-dir/file2.txt": []byte("This is file 2"), + "test-symlink-dir/file3.txt": []byte("This is file 3"), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccTarGzArchiveFile_Multiple_Relative verifies that a relative path to a directory containing multiple +// directories including symlink directories generates an archive which includes the directories and files. +func TestAccTarGzArchiveFile_Multiple_Relative(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash("test-fixtures"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-dir/test-dir1/file1.txt": []byte("This is file 1"), + "test-dir/test-dir1/file2.txt": []byte("This is file 2"), + "test-dir/test-dir1/file3.txt": []byte("This is file 3"), + "test-dir/test-dir2/file1.txt": []byte("This is file 1"), + "test-dir/test-dir2/file2.txt": []byte("This is file 2"), + "test-dir/test-dir2/file3.txt": []byte("This is file 3"), + "test-dir/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-dir/test-symlink-dir/file1.txt": []byte("This is file 1"), + "test-dir-with-symlink-dir/test-symlink-dir/file2.txt": []byte("This is file 2"), + "test-dir-with-symlink-dir/test-symlink-dir/file3.txt": []byte("This is file 3"), + "test-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), + "test-symlink-dir/file1.txt": []byte("This is file 1"), + "test-symlink-dir/file2.txt": []byte("This is file 2"), + "test-symlink-dir/file3.txt": []byte("This is file 3"), + "test-symlink-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + "test-symlink-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccTarGzArchiveFile_Multiple_Absolute verifies that an absolute path to a directory containing multiple +// directories including symlink directories generates an archive which includes the directories and files. +func TestAccTarGzArchiveFile_Multiple_Absolute(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + multipleDirsAndFilesAbs, err := filepath.Abs("test-fixtures") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash(multipleDirsAndFilesAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-dir/test-dir1/file1.txt": []byte("This is file 1"), + "test-dir/test-dir1/file2.txt": []byte("This is file 2"), + "test-dir/test-dir1/file3.txt": []byte("This is file 3"), + "test-dir/test-dir2/file1.txt": []byte("This is file 1"), + "test-dir/test-dir2/file2.txt": []byte("This is file 2"), + "test-dir/test-dir2/file3.txt": []byte("This is file 3"), + "test-dir/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-dir/test-symlink-dir/file1.txt": []byte("This is file 1"), + "test-dir-with-symlink-dir/test-symlink-dir/file2.txt": []byte("This is file 2"), + "test-dir-with-symlink-dir/test-symlink-dir/file3.txt": []byte("This is file 3"), + "test-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), + "test-symlink-dir/file1.txt": []byte("This is file 1"), + "test-symlink-dir/file2.txt": []byte("This is file 2"), + "test-symlink-dir/file3.txt": []byte("This is file 3"), + "test-symlink-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + "test-symlink-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccTarGzArchiveFile_SymlinkFile_Relative_ExcludeSymlinkDirectories verifies that a symlink to a file using a relative +// path generates an archive which includes the file. +func TestAccTarGzArchiveFile_SymlinkFile_Relative_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "tar.gz" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-file/test-symlink.txt"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccTarGzArchiveFile_SymlinkFile_Absolute_ExcludeSymlinkDirectories verifies that a symlink to a file using an absolute +// path generates an archive which includes the file. +func TestAccTarGzArchiveFile_SymlinkFile_Absolute_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + symlinkFileAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-file/test-symlink.txt") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "tar.gz" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash(symlinkFileAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccTarGzArchiveFile_SymlinkDirectory_Relative_ExcludeSymlinkDirectories verifies that an empty archive +// is generated when trying to archive a directory which only contains a symlink to a directory. +func TestAccTarGzArchiveFile_SymlinkDirectory_Relative_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash("test-fixtures/test-symlink-dir"), filepath.ToSlash(f)), + ExpectError: regexp.MustCompile(`.*error creating archive: error archiving directory: archive has not been\ncreated as it would be empty`), + }, + }, + }) +} + +// TestAccTarGzArchiveFile_SymlinkDirectory_Absolute_ExcludeSymlinkDirectories verifies that an empty archive +// is generated when trying to archive a directory which only contains a symlink to a directory. +func TestAccTarGzArchiveFile_SymlinkDirectory_Absolute_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + symlinkDirWithRegularFilesAbs, err := filepath.Abs("test-fixtures/test-symlink-dir") + if err != nil { + t.Fatal(err) + } + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash(symlinkDirWithRegularFilesAbs), filepath.ToSlash(f)), + ExpectError: regexp.MustCompile(`.*error creating archive: error archiving directory: archive has not been\ncreated as it would be empty`), + }, + }, + }) +} + +// TestAccTarGzArchiveFile_DirectoryWithSymlinkFile_Relative_ExcludeSymlinkDirectories verifies that a relative path to a +// directory containing a symlink file generates an archive which includes the files in the directory. +func TestAccTarGzArchiveFile_DirectoryWithSymlinkFile_Relative_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-file"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-file.txt": []byte(`This is test content`), + "test-symlink.txt": []byte(`This is test content`), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccTarGzArchiveFile_DirectoryWithSymlinkFile_Absolute_ExcludeSymlinkDirectories verifies that an absolute path to a +// directory containing a symlink file generates an archive which includes the files in the directory. +func TestAccTarGzArchiveFile_DirectoryWithSymlinkFile_Absolute_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + symlinkDirWithSymlinkFilesAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-file") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash(symlinkDirWithSymlinkFilesAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-file.txt": []byte(`This is test content`), + "test-symlink.txt": []byte(`This is test content`), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccTarGzArchiveFile_SymlinkDirectoryWithSymlinkFile_Relative_ExcludeSymlinkDirectories verifies that a relative path +// to a symlink file in a symlink directory generates an archive which includes the files in the directory. +func TestAccTarGzArchiveFile_SymlinkDirectoryWithSymlinkFile_Relative_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "tar.gz" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash("test-fixtures/test-symlink-dir-with-symlink-file/test-symlink.txt"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccTarGzArchiveFile_SymlinkDirectoryWithSymlinkFile_Absolute_ExcludeSymlinkDirectories verifies that an absolute path +// to a symlink file in a symlink directory generates an archive which includes the files in the directory. +func TestAccTarGzArchiveFile_SymlinkDirectoryWithSymlinkFile_Absolute_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + symlinkFileInSymlinkDirAbs, err := filepath.Abs("test-fixtures/test-symlink-dir-with-symlink-file/test-symlink.txt") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "tar.gz" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash(symlinkFileInSymlinkDirAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccTarGzArchiveFile_DirectoryWithSymlinkDirectory_Relative_ExcludeSymlinkDirectories verifies that an empty archive +// is generated when trying to archive a directory which only contains a symlink to a directory. +func TestAccTarGzArchiveFile_DirectoryWithSymlinkDirectory_Relative_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + exclude_symlink_directories = true + } + `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-dir"), filepath.ToSlash(f)), + ExpectError: regexp.MustCompile(`.*error creating archive: error archiving directory: archive has not been\ncreated as it would be empty`), + }, + }, + }) +} + +// TestAccTarGzArchiveFile_IncludeDirectoryWithSymlinkDirectory_Absolute_ExcludeSymlinkDirectories verifies that an empty archive +// is generated when trying to archive a directory which only contains a symlink to a directory. +func TestAccTarGzArchiveFile_IncludeDirectoryWithSymlinkDirectory_Absolute_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + symlinkDirInRegularDirAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-dir") + if err != nil { + t.Fatal(err) + } + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + exclude_symlink_directories = true + } + `, filepath.ToSlash(symlinkDirInRegularDirAbs), filepath.ToSlash(f)), + ExpectError: regexp.MustCompile(`.*error creating archive: error archiving directory: archive has not been\ncreated as it would be empty`), + }, + }, + }) +} + +// TestAccTarGzArchiveFile_Multiple_Relative_ExcludeSymlinkDirectories verifies that +// symlinked directories are excluded. +func TestAccTarGzArchiveFile_Multiple_Relative_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash("test-fixtures"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-dir/test-dir1/file1.txt": []byte("This is file 1"), + "test-dir/test-dir1/file2.txt": []byte("This is file 2"), + "test-dir/test-dir1/file3.txt": []byte("This is file 3"), + "test-dir/test-dir2/file1.txt": []byte("This is file 1"), + "test-dir/test-dir2/file2.txt": []byte("This is file 2"), + "test-dir/test-dir2/file3.txt": []byte("This is file 3"), + "test-dir/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccTarGzArchiveFile_Multiple_Relative_ExcludeSymlinkDirectories verifies that +// symlinked directories are excluded. +func TestAccTarGzArchiveFile_Multiple_Absolute_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + multipleDirsAndFilesAbs, err := filepath.Abs("test-fixtures") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash(multipleDirsAndFilesAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-dir/test-dir1/file1.txt": []byte("This is file 1"), + "test-dir/test-dir1/file2.txt": []byte("This is file 2"), + "test-dir/test-dir1/file3.txt": []byte("This is file 3"), + "test-dir/test-dir2/file1.txt": []byte("This is file 1"), + "test-dir/test-dir2/file2.txt": []byte("This is file 2"), + "test-dir/test-dir2/file3.txt": []byte("This is file 3"), + "test-dir/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} diff --git a/internal/provider/data_source_archive_file_zip_test.go b/internal/provider/data_source_archive_file_zip_test.go new file mode 100644 index 00000000..10975b7f --- /dev/null +++ b/internal/provider/data_source_archive_file_zip_test.go @@ -0,0 +1,1116 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package archive + +import ( + "fmt" + "path/filepath" + "regexp" + "testing" + + r "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestAccZipArchiveFile_Basic(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + var fileSize string + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: testAccArchiveFileContentConfig("zip", f), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_md5", "ea35f0444ea9a3d5641d8760bc2815cc", + ), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_sha", "019c79c4dc14dbe1edb3e467b2de6a6aad148717", + ), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_sha256", "3fb55c931a048943b8d7558dde7c2e4bfc8e04be33b1b55691053d1352391fa7", + ), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_base64sha256", "P7VckxoEiUO411WN3nwuS/yOBL4zsbVWkQU9E1I5H6c=", + ), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_sha512", "57e2d073dce214609bd61113b90b0b2b7c75034047224d56e35f363c8f2662e3acd561eebf94826a67453411181eca7e1cbf15db1f2fdd496cf13df46b7848c3", + ), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_base64sha512", "V+LQc9ziFGCb1hETuQsLK3x1A0BHIk1W4182PI8mYuOs1WHuv5SCamdFNBEYHsp+HL8V2x8v3Uls8T30a3hIww==", + ), + ), + }, + { + Config: testAccArchiveFileFileConfig("zip", f), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_md5", "59fbc9e62af3cbc2f588f97498240dae", + ), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_sha", "ce4ee1450ab93ac86e11446649e44cea907b6568", + ), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_sha256", "5131387f97167da47aa741df3ab2c82f182f17c514c222538d34708d04e0756b", + ), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_base64sha256", "UTE4f5cWfaR6p0HfOrLILxgvF8UUwiJTjTRwjQTgdWs=", + ), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_sha512", "eb33eb0f8cd8efe1a5a0b99acbd22ed22dbebb80817f8de6e8fed15c21c52240838d9bb46fb0938846c74f694425551ba60829a6396f91fcfe49d21a1e3bb409", + ), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_base64sha512", "6zPrD4zY7+GloLmay9Iu0i2+u4CBf43m6P7RXCHFIkCDjZu0b7CTiEbHT2lEJVUbpggppjlvkfz+SdIaHju0CQ==", + ), + ), + }, + { + Config: testAccArchiveFileDirConfig("zip", f), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_md5", "b73f64a383716070aa4a29563b8b14d4", + ), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_sha", "76d20a402eefd1cfbdc47886abd4e0909616c191", + ), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_sha256", "c9d07cc2dabc9caf6f43bed51fa613c281e6ca58cae3a8d6fae2094b00b3369a", + ), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_base64sha256", "ydB8wtq8nK9vQ77VH6YTwoHmyljK46jW+uIJSwCzNpo=", + ), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_sha512", "b96ac6b9554a04473a733be36f190422bf7162b4afdb211a0f551713eadf4092459426750646c70383ce6c8b89171b88582a608e5841bfaaafa17004a2a2ca0a", + ), + r.TestCheckResourceAttr( + "data.archive_file.foo", "output_base64sha512", "uWrGuVVKBEc6czvjbxkEIr9xYrSv2yEaD1UXE+rfQJJFlCZ1BkbHA4PObIuJFxuIWCpgjlhBv6qvoXAEoqLKCg==", + ), + ), + }, + { + Config: testAccArchiveFileDirExcludesConfig("zip", f), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + ), + }, + { + Config: testAccArchiveFileDirExcludesGlobConfig("zip", f), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + ), + }, + { + Config: testAccArchiveFileMultiSourceConfig("zip", f), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + ), + }, + }, + }) +} + +func TestAccZipArchiveFile_SourceConfigMissing(t *testing.T) { + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: testAccArchiveSourceConfigMissing("zip"), + ExpectError: regexp.MustCompile(`.*At least one of these attributes must be configured:\n\[source,source_content_filename,source_file,source_dir]`), + }, + }, + }) +} + +func TestAccZipArchiveFile_SourceConfigConflicting(t *testing.T) { + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: testAccArchiveSourceConfigConflicting("zip"), + ExpectError: regexp.MustCompile(`.*Attribute "source_dir" cannot be specified when "source" is specified`), + }, + }, + }) +} + +// TestAccZipArchiveFile_SymlinkFile_Relative verifies that a symlink to a file using a relative path generates an +// archive which includes the file. +func TestAccZipArchiveFile_SymlinkFile_Relative(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "zip" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-file/test-symlink.txt"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccZipArchiveFile_SymlinkFile_Absolute verifies that a symlink to a file using an absolute path generates an +// archive which includes the file. +func TestAccZipArchiveFile_SymlinkFile_Absolute(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + symlinkFileAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-file/test-symlink.txt") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "zip" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash(symlinkFileAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccZipArchiveFile_SymlinkDirectory_Relative verifies that a symlink to a directory using a relative path +// generates an archive which includes the files in the directory. +func TestAccZipArchiveFile_SymlinkDirectory_Relative(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash("test-fixtures/test-symlink-dir"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "file1.txt": []byte(`This is file 1`), + "file2.txt": []byte(`This is file 2`), + "file3.txt": []byte(`This is file 3`), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccZipArchiveFile_SymlinkDirectory_Absolute verifies that a symlink to a directory using an absolute path +// generates an archive which includes the files in the directory. +func TestAccZipArchiveFile_SymlinkDirectory_Absolute(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + symlinkDirWithRegularFilesAbs, err := filepath.Abs("test-fixtures/test-symlink-dir") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash(symlinkDirWithRegularFilesAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "file1.txt": []byte(`This is file 1`), + "file2.txt": []byte(`This is file 2`), + "file3.txt": []byte(`This is file 3`), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccZipArchiveFile_DirectoryWithSymlinkFile_Relative verifies that a relative path to a directory containing +// a symlink file generates an archive which includes the files in the directory. +func TestAccZipArchiveFile_DirectoryWithSymlinkFile_Relative(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-file"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-file.txt": []byte(`This is test content`), + "test-symlink.txt": []byte(`This is test content`), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccZipArchiveFile_DirectoryWithSymlinkFile_Absolute verifies that an absolute path to a directory containing +// a symlink file generates an archive which includes the files in the directory. +func TestAccZipArchiveFile_DirectoryWithSymlinkFile_Absolute(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + symlinkDirWithSymlinkFilesAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-file") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash(symlinkDirWithSymlinkFilesAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-file.txt": []byte(`This is test content`), + "test-symlink.txt": []byte(`This is test content`), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccZipArchiveFile_SymlinkDirectoryWithSymlinkFile_Relative verifies that a relative path to a symlink +// file in a symlink directory generates an archive which includes the files in the directory. +func TestAccZipArchiveFile_SymlinkDirectoryWithSymlinkFile_Relative(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "zip" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash("test-fixtures/test-symlink-dir-with-symlink-file/test-symlink.txt"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccZipArchiveFile_SymlinkDirectoryWithSymlinkFile_Absolute verifies that an absolute path to a symlink +// file in a symlink directory generates an archive which includes the files in the directory. +func TestAccZipArchiveFile_SymlinkDirectoryWithSymlinkFile_Absolute(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + symlinkFileInSymlinkDirAbs, err := filepath.Abs("test-fixtures/test-symlink-dir-with-symlink-file/test-symlink.txt") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "zip" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash(symlinkFileInSymlinkDirAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccZipArchiveFile_DirectoryWithSymlinkDirectory_Relative verifies that a relative path to a +// directory containing a symlink to a directory generates an archive which includes the directory. +func TestAccZipArchiveFile_DirectoryWithSymlinkDirectory_Relative(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-dir"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-symlink-dir/file1.txt": []byte("This is file 1"), + "test-symlink-dir/file2.txt": []byte("This is file 2"), + "test-symlink-dir/file3.txt": []byte("This is file 3"), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccZipArchiveFile_IncludeDirectoryWithSymlinkDirectory_Absolute verifies that an absolute path to a +// directory containing a symlink to a directory generates an archive which includes the directory. +func TestAccZipArchiveFile_IncludeDirectoryWithSymlinkDirectory_Absolute(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + symlinkDirInRegularDirAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-dir") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash(symlinkDirInRegularDirAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-symlink-dir/file1.txt": []byte("This is file 1"), + "test-symlink-dir/file2.txt": []byte("This is file 2"), + "test-symlink-dir/file3.txt": []byte("This is file 3"), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccZipArchiveFile_Multiple_Relative verifies that a relative path to a directory containing multiple +// directories including symlink directories generates an archive which includes the directories and files. +func TestAccZipArchiveFile_Multiple_Relative(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash("test-fixtures"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-dir/test-dir1/file1.txt": []byte("This is file 1"), + "test-dir/test-dir1/file2.txt": []byte("This is file 2"), + "test-dir/test-dir1/file3.txt": []byte("This is file 3"), + "test-dir/test-dir2/file1.txt": []byte("This is file 1"), + "test-dir/test-dir2/file2.txt": []byte("This is file 2"), + "test-dir/test-dir2/file3.txt": []byte("This is file 3"), + "test-dir/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-dir/test-symlink-dir/file1.txt": []byte("This is file 1"), + "test-dir-with-symlink-dir/test-symlink-dir/file2.txt": []byte("This is file 2"), + "test-dir-with-symlink-dir/test-symlink-dir/file3.txt": []byte("This is file 3"), + "test-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), + "test-symlink-dir/file1.txt": []byte("This is file 1"), + "test-symlink-dir/file2.txt": []byte("This is file 2"), + "test-symlink-dir/file3.txt": []byte("This is file 3"), + "test-symlink-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + "test-symlink-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccZipArchiveFile_Multiple_Absolute verifies that an absolute path to a directory containing multiple +// directories including symlink directories generates an archive which includes the directories and files. +func TestAccZipArchiveFile_Multiple_Absolute(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + multipleDirsAndFilesAbs, err := filepath.Abs("test-fixtures") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash(multipleDirsAndFilesAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-dir/test-dir1/file1.txt": []byte("This is file 1"), + "test-dir/test-dir1/file2.txt": []byte("This is file 2"), + "test-dir/test-dir1/file3.txt": []byte("This is file 3"), + "test-dir/test-dir2/file1.txt": []byte("This is file 1"), + "test-dir/test-dir2/file2.txt": []byte("This is file 2"), + "test-dir/test-dir2/file3.txt": []byte("This is file 3"), + "test-dir/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-dir/test-symlink-dir/file1.txt": []byte("This is file 1"), + "test-dir-with-symlink-dir/test-symlink-dir/file2.txt": []byte("This is file 2"), + "test-dir-with-symlink-dir/test-symlink-dir/file3.txt": []byte("This is file 3"), + "test-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), + "test-symlink-dir/file1.txt": []byte("This is file 1"), + "test-symlink-dir/file2.txt": []byte("This is file 2"), + "test-symlink-dir/file3.txt": []byte("This is file 3"), + "test-symlink-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + "test-symlink-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccZipArchiveFile_SymlinkFile_Relative_ExcludeSymlinkDirectories verifies that a symlink to a file using a relative +// path generates an archive which includes the file. +func TestAccZipArchiveFile_SymlinkFile_Relative_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "zip" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-file/test-symlink.txt"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccZipArchiveFile_SymlinkFile_Absolute_ExcludeSymlinkDirectories verifies that a symlink to a file using an absolute +// path generates an archive which includes the file. +func TestAccZipArchiveFile_SymlinkFile_Absolute_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + symlinkFileAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-file/test-symlink.txt") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "zip" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash(symlinkFileAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccZipArchiveFile_SymlinkDirectory_Relative_ExcludeSymlinkDirectories verifies that an empty archive +// is generated when trying to archive a directory which only contains a symlink to a directory. +func TestAccZipArchiveFile_SymlinkDirectory_Relative_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash("test-fixtures/test-symlink-dir"), filepath.ToSlash(f)), + ExpectError: regexp.MustCompile(`.*error creating archive: error archiving directory: archive has not been\ncreated as it would be empty`), + }, + }, + }) +} + +// TestAccZipArchiveFile_SymlinkDirectory_Absolute_ExcludeSymlinkDirectories verifies that an empty archive +// is generated when trying to archive a directory which only contains a symlink to a directory. +func TestAccZipArchiveFile_SymlinkDirectory_Absolute_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + symlinkDirWithRegularFilesAbs, err := filepath.Abs("test-fixtures/test-symlink-dir") + if err != nil { + t.Fatal(err) + } + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash(symlinkDirWithRegularFilesAbs), filepath.ToSlash(f)), + ExpectError: regexp.MustCompile(`.*error creating archive: error archiving directory: archive has not been\ncreated as it would be empty`), + }, + }, + }) +} + +// TestAccZipArchiveFile_DirectoryWithSymlinkFile_Relative_ExcludeSymlinkDirectories verifies that a relative path to a +// directory containing a symlink file generates an archive which includes the files in the directory. +func TestAccZipArchiveFile_DirectoryWithSymlinkFile_Relative_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-file"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-file.txt": []byte(`This is test content`), + "test-symlink.txt": []byte(`This is test content`), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccZipArchiveFile_DirectoryWithSymlinkFile_Absolute_ExcludeSymlinkDirectories verifies that an absolute path to a +// directory containing a symlink file generates an archive which includes the files in the directory. +func TestAccZipArchiveFile_DirectoryWithSymlinkFile_Absolute_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + symlinkDirWithSymlinkFilesAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-file") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash(symlinkDirWithSymlinkFilesAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-file.txt": []byte(`This is test content`), + "test-symlink.txt": []byte(`This is test content`), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccZipArchiveFile_SymlinkDirectoryWithSymlinkFile_Relative_ExcludeSymlinkDirectories verifies that a relative path +// to a symlink file in a symlink directory generates an archive which includes the files in the directory. +func TestAccZipArchiveFile_SymlinkDirectoryWithSymlinkFile_Relative_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "zip" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash("test-fixtures/test-symlink-dir-with-symlink-file/test-symlink.txt"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccZipArchiveFile_SymlinkDirectoryWithSymlinkFile_Absolute_ExcludeSymlinkDirectories verifies that an absolute path +// to a symlink file in a symlink directory generates an archive which includes the files in the directory. +func TestAccZipArchiveFile_SymlinkDirectoryWithSymlinkFile_Absolute_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + symlinkFileInSymlinkDirAbs, err := filepath.Abs("test-fixtures/test-symlink-dir-with-symlink-file/test-symlink.txt") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "zip" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash(symlinkFileInSymlinkDirAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccZipArchiveFile_DirectoryWithSymlinkDirectory_Relative_ExcludeSymlinkDirectories verifies that an empty archive +// is generated when trying to archive a directory which only contains a symlink to a directory. +func TestAccZipArchiveFile_DirectoryWithSymlinkDirectory_Relative_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + exclude_symlink_directories = true + } + `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-dir"), filepath.ToSlash(f)), + ExpectError: regexp.MustCompile(`.*error creating archive: error archiving directory: archive has not been\ncreated as it would be empty`), + }, + }, + }) +} + +// TestAccZipArchiveFile_IncludeDirectoryWithSymlinkDirectory_Absolute_ExcludeSymlinkDirectories verifies that an empty archive +// is generated when trying to archive a directory which only contains a symlink to a directory. +func TestAccZipArchiveFile_IncludeDirectoryWithSymlinkDirectory_Absolute_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + symlinkDirInRegularDirAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-dir") + if err != nil { + t.Fatal(err) + } + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + exclude_symlink_directories = true + } + `, filepath.ToSlash(symlinkDirInRegularDirAbs), filepath.ToSlash(f)), + ExpectError: regexp.MustCompile(`.*error creating archive: error archiving directory: archive has not been\ncreated as it would be empty`), + }, + }, + }) +} + +// TestAccZipArchiveFile_Multiple_Relative_ExcludeSymlinkDirectories verifies that +// symlinked directories are excluded. +func TestAccZipArchiveFile_Multiple_Relative_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash("test-fixtures"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-dir/test-dir1/file1.txt": []byte("This is file 1"), + "test-dir/test-dir1/file2.txt": []byte("This is file 2"), + "test-dir/test-dir1/file3.txt": []byte("This is file 3"), + "test-dir/test-dir2/file1.txt": []byte("This is file 1"), + "test-dir/test-dir2/file2.txt": []byte("This is file 2"), + "test-dir/test-dir2/file3.txt": []byte("This is file 3"), + "test-dir/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestAccZipArchiveFile_Multiple_Relative_ExcludeSymlinkDirectories verifies that +// symlinked directories are excluded. +func TestAccZipArchiveFile_Multiple_Absolute_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + multipleDirsAndFilesAbs, err := filepath.Abs("test-fixtures") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + data "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash(multipleDirsAndFilesAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("data.archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-dir/test-dir1/file1.txt": []byte("This is file 1"), + "test-dir/test-dir1/file2.txt": []byte("This is file 2"), + "test-dir/test-dir1/file3.txt": []byte("This is file 3"), + "test-dir/test-dir2/file1.txt": []byte("This is file 1"), + "test-dir/test-dir2/file2.txt": []byte("This is file 2"), + "test-dir/test-dir2/file3.txt": []byte("This is file 3"), + "test-dir/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} diff --git a/internal/provider/resource_archive_file_test.go b/internal/provider/resource_archive_file_test.go index 8c815006..3fc35bc8 100644 --- a/internal/provider/resource_archive_file_test.go +++ b/internal/provider/resource_archive_file_test.go @@ -13,115 +13,6 @@ import ( r "github.com/hashicorp/terraform-plugin-testing/helper/resource" ) -func TestAccArchiveFile_Resource_Basic(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - var fileSize string - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: testAccArchiveFileResourceContentConfig(f), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttr( - "archive_file.foo", "output_md5", "ea35f0444ea9a3d5641d8760bc2815cc", - ), - r.TestCheckResourceAttr( - "archive_file.foo", "output_sha", "019c79c4dc14dbe1edb3e467b2de6a6aad148717", - ), - r.TestCheckResourceAttr( - "archive_file.foo", "output_sha256", "3fb55c931a048943b8d7558dde7c2e4bfc8e04be33b1b55691053d1352391fa7", - ), - r.TestCheckResourceAttr( - "archive_file.foo", "output_base64sha256", "P7VckxoEiUO411WN3nwuS/yOBL4zsbVWkQU9E1I5H6c=", - ), - r.TestCheckResourceAttr( - "archive_file.foo", "output_sha512", "57e2d073dce214609bd61113b90b0b2b7c75034047224d56e35f363c8f2662e3acd561eebf94826a67453411181eca7e1cbf15db1f2fdd496cf13df46b7848c3", - ), - r.TestCheckResourceAttr( - "archive_file.foo", "output_base64sha512", "V+LQc9ziFGCb1hETuQsLK3x1A0BHIk1W4182PI8mYuOs1WHuv5SCamdFNBEYHsp+HL8V2x8v3Uls8T30a3hIww==", - ), - ), - }, - { - Config: testAccArchiveFileResourceFileConfig(f), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttr( - "archive_file.foo", "output_md5", "59fbc9e62af3cbc2f588f97498240dae", - ), - r.TestCheckResourceAttr( - "archive_file.foo", "output_sha", "ce4ee1450ab93ac86e11446649e44cea907b6568", - ), - r.TestCheckResourceAttr( - "archive_file.foo", "output_sha256", "5131387f97167da47aa741df3ab2c82f182f17c514c222538d34708d04e0756b", - ), - r.TestCheckResourceAttr( - "archive_file.foo", "output_base64sha256", "UTE4f5cWfaR6p0HfOrLILxgvF8UUwiJTjTRwjQTgdWs=", - ), - r.TestCheckResourceAttr( - "archive_file.foo", "output_sha512", "eb33eb0f8cd8efe1a5a0b99acbd22ed22dbebb80817f8de6e8fed15c21c52240838d9bb46fb0938846c74f694425551ba60829a6396f91fcfe49d21a1e3bb409", - ), - r.TestCheckResourceAttr( - "archive_file.foo", "output_base64sha512", "6zPrD4zY7+GloLmay9Iu0i2+u4CBf43m6P7RXCHFIkCDjZu0b7CTiEbHT2lEJVUbpggppjlvkfz+SdIaHju0CQ==", - ), - ), - }, - { - Config: testAccArchiveFileResourceDirConfig(f), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttr( - "archive_file.foo", "output_md5", "b73f64a383716070aa4a29563b8b14d4", - ), - r.TestCheckResourceAttr( - "archive_file.foo", "output_sha", "76d20a402eefd1cfbdc47886abd4e0909616c191", - ), - r.TestCheckResourceAttr( - "archive_file.foo", "output_sha256", "c9d07cc2dabc9caf6f43bed51fa613c281e6ca58cae3a8d6fae2094b00b3369a", - ), - r.TestCheckResourceAttr( - "archive_file.foo", "output_base64sha256", "ydB8wtq8nK9vQ77VH6YTwoHmyljK46jW+uIJSwCzNpo=", - ), - r.TestCheckResourceAttr( - "archive_file.foo", "output_sha512", "b96ac6b9554a04473a733be36f190422bf7162b4afdb211a0f551713eadf4092459426750646c70383ce6c8b89171b88582a608e5841bfaaafa17004a2a2ca0a", - ), - r.TestCheckResourceAttr( - "archive_file.foo", "output_base64sha512", "uWrGuVVKBEc6czvjbxkEIr9xYrSv2yEaD1UXE+rfQJJFlCZ1BkbHA4PObIuJFxuIWCpgjlhBv6qvoXAEoqLKCg==", - ), - ), - }, - { - Config: testAccArchiveFileResourceDirExcludesConfig(f), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), - ), - }, - { - Config: testAccArchiveFileResourceDirExcludesGlobConfig(f), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), - ), - }, - { - Config: testAccArchiveFileResourceMultiSourceConfig(f), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), - ), - }, - }, - }) -} - func TestResource_UpgradeFromVersion2_2_0_ContentConfig(t *testing.T) { td := t.TempDir() @@ -138,7 +29,7 @@ func TestResource_UpgradeFromVersion2_2_0_ContentConfig(t *testing.T) { Source: "hashicorp/archive", }, }, - Config: testAccArchiveFileResourceContentConfig(f), + Config: testAccArchiveFileResourceContentConfig("zip", f), Check: r.ComposeTestCheckFunc( testAccArchiveFileSize(f, &fileSize), r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), @@ -155,12 +46,12 @@ func TestResource_UpgradeFromVersion2_2_0_ContentConfig(t *testing.T) { }, { ProtoV5ProviderFactories: protoV5ProviderFactories(), - Config: testAccArchiveFileResourceContentConfig(f), + Config: testAccArchiveFileResourceContentConfig("zip", f), PlanOnly: true, }, { ProtoV5ProviderFactories: protoV5ProviderFactories(), - Config: testAccArchiveFileResourceContentConfig(f), + Config: testAccArchiveFileResourceContentConfig("zip", f), Check: r.ComposeTestCheckFunc( r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), r.TestCheckResourceAttr( @@ -194,7 +85,7 @@ func TestResource_UpgradeFromVersion2_2_0_FileConfig(t *testing.T) { Source: "hashicorp/archive", }, }, - Config: testAccArchiveFileResourceFileConfig(f), + Config: testAccArchiveFileResourceFileConfig("zip", f), Check: r.ComposeTestCheckFunc( testAccArchiveFileSize(f, &fileSize), r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), @@ -211,12 +102,12 @@ func TestResource_UpgradeFromVersion2_2_0_FileConfig(t *testing.T) { }, { ProtoV5ProviderFactories: protoV5ProviderFactories(), - Config: testAccArchiveFileResourceFileConfig(f), + Config: testAccArchiveFileResourceFileConfig("zip", f), PlanOnly: true, }, { ProtoV5ProviderFactories: protoV5ProviderFactories(), - Config: testAccArchiveFileResourceFileConfig(f), + Config: testAccArchiveFileResourceFileConfig("zip", f), Check: r.ComposeTestCheckFunc( r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), r.TestCheckResourceAttr( @@ -250,7 +141,7 @@ func TestResource_UpgradeFromVersion2_2_0_DirConfig(t *testing.T) { Source: "hashicorp/archive", }, }, - Config: testAccArchiveFileResourceDirConfig(f), + Config: testAccArchiveFileResourceDirConfig("zip", f), Check: r.ComposeTestCheckFunc( testAccArchiveFileSize(f, &fileSize), r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), @@ -267,12 +158,12 @@ func TestResource_UpgradeFromVersion2_2_0_DirConfig(t *testing.T) { }, { ProtoV5ProviderFactories: protoV5ProviderFactories(), - Config: testAccArchiveFileResourceDirConfig(f), + Config: testAccArchiveFileResourceDirConfig("zip", f), PlanOnly: true, }, { ProtoV5ProviderFactories: protoV5ProviderFactories(), - Config: testAccArchiveFileResourceDirConfig(f), + Config: testAccArchiveFileResourceDirConfig("zip", f), Check: r.ComposeTestCheckFunc( r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), r.TestCheckResourceAttr( @@ -306,7 +197,7 @@ func TestResource_UpgradeFromVersion2_2_0_DirExcludesConfig(t *testing.T) { Source: "hashicorp/archive", }, }, - Config: testAccArchiveFileResourceDirExcludesConfig(f), + Config: testAccArchiveFileResourceDirExcludesConfig("zip", f), Check: r.ComposeTestCheckFunc( testAccArchiveFileSize(f, &fileSize), testExtractResourceAttr("archive_file.foo", "output_sha", &outputSha), @@ -315,12 +206,12 @@ func TestResource_UpgradeFromVersion2_2_0_DirExcludesConfig(t *testing.T) { }, { ProtoV5ProviderFactories: protoV5ProviderFactories(), - Config: testAccArchiveFileResourceDirExcludesConfig(f), + Config: testAccArchiveFileResourceDirExcludesConfig("zip", f), PlanOnly: true, }, { ProtoV5ProviderFactories: protoV5ProviderFactories(), - Config: testAccArchiveFileResourceDirExcludesConfig(f), + Config: testAccArchiveFileResourceDirExcludesConfig("zip", f), Check: r.ComposeTestCheckFunc( r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), r.TestCheckResourceAttrPtr("archive_file.foo", "output_sha", &outputSha), @@ -346,7 +237,7 @@ func TestResource_UpgradeFromVersion2_2_0_SourceConfig(t *testing.T) { Source: "hashicorp/archive", }, }, - Config: testAccArchiveFileResourceMultiSourceConfig(f), + Config: testAccArchiveFileResourceMultiSourceConfig("zip", f), Check: r.ComposeTestCheckFunc( testAccArchiveFileSize(f, &fileSize), testExtractResourceAttr("archive_file.foo", "output_sha", &outputSha), @@ -355,12 +246,12 @@ func TestResource_UpgradeFromVersion2_2_0_SourceConfig(t *testing.T) { }, { ProtoV5ProviderFactories: protoV5ProviderFactories(), - Config: testAccArchiveFileResourceMultiSourceConfig(f), + Config: testAccArchiveFileResourceMultiSourceConfig("zip", f), PlanOnly: true, }, { ProtoV5ProviderFactories: protoV5ProviderFactories(), - Config: testAccArchiveFileResourceMultiSourceConfig(f), + Config: testAccArchiveFileResourceMultiSourceConfig("zip", f), Check: r.ComposeTestCheckFunc( r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), r.TestCheckResourceAttrPtr("archive_file.foo", "output_sha", &outputSha), @@ -370,69 +261,12 @@ func TestResource_UpgradeFromVersion2_2_0_SourceConfig(t *testing.T) { }) } -// TestResource_FileConfig_ModifiedContents tests that archive_file resource replaces the resource on every read. -// The contents of the source file are altered, but no aspect of the Terraform configuration is changed. -// The change in the output hashes demonstrates that the resource Read function is replacing the resource. -func TestResource_FileConfig_ModifiedContents(t *testing.T) { - td := t.TempDir() - - sourceFilePath := filepath.Join(td, "sourceFile") - outputFilePath := filepath.Join(td, "zip_file_acc_test_upgrade_file_config.zip") - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - Steps: []r.TestStep{ - { - PreConfig: func() { - alterFileContents("content", sourceFilePath) - }, - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Config: testAccArchiveFileResourceFileSourceFileConfig(sourceFilePath, outputFilePath), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(outputFilePath, &fileSize), - r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttr( - "archive_file.foo", "output_base64sha256", "8inOmQJB12dXqCyRTdaRO63yP22Rmuube/A1DLDii10=", - ), - r.TestCheckResourceAttr( - "archive_file.foo", "output_md5", "20d9c8096f99174d128e5042279fe576", - ), - r.TestCheckResourceAttr( - "archive_file.foo", "output_sha", "119d3169ec43fe95bbd38a3824f4e477f4e8d4e7", - ), - ), - }, - { - PreConfig: func() { - alterFileContents("modified content", sourceFilePath) - }, - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Config: testAccArchiveFileResourceFileSourceFileConfig(sourceFilePath, outputFilePath), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(outputFilePath, &fileSize), - r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttr( - "archive_file.foo", "output_base64sha256", "OnzXDJ3jda5RPuINpxKHQsZ+jSNOupxShSmW3iUWw7Q=", - ), - r.TestCheckResourceAttr( - "archive_file.foo", "output_md5", "ce31b13da062764f2975d1ef08ee56fe", - ), - r.TestCheckResourceAttr( - "archive_file.foo", "output_sha", "12c51ec24fc5dc10570abbc0b56ac5a3b4141b83", - ), - ), - }, - }, - }) -} - func TestResource_SourceConfigMissing(t *testing.T) { r.ParallelTest(t, r.TestCase{ ProtoV5ProviderFactories: protoV5ProviderFactories(), Steps: []r.TestStep{ { - Config: testResourceSourceConfigMissing(), + Config: testResourceSourceConfigMissing("zip"), ExpectError: regexp.MustCompile(`.*At least one of these attributes must be configured:\n\[source,source_content_filename,source_file,source_dir]`), }, }, @@ -444,1095 +278,125 @@ func TestResource_SourceConfigConflicting(t *testing.T) { ProtoV5ProviderFactories: protoV5ProviderFactories(), Steps: []r.TestStep{ { - Config: testResourceSourceConfigConflicting(), + Config: testResourceSourceConfigConflicting("zip"), ExpectError: regexp.MustCompile(`.*Attribute "source_dir" cannot be specified when "source" is specified`), }, }, }) } -// TestResource_ArchiveFile_SymlinkFile_Relative verifies that a symlink to a file using a relative path generates an -// archive which includes the file. -func TestResource_ArchiveFile_SymlinkFile_Relative(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - resource "archive_file" "foo" { - type = "zip" - source_file = "%s" - output_path = "%s" - output_file_mode = "0666" - } - `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-file/test-symlink.txt"), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-symlink.txt": []byte(`This is test content`), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) -} - -// TestResource_ArchiveFile_SymlinkFile_Absolute verifies that a symlink to a file using an absolute path generates an -// archive which includes the file. -func TestResource_ArchiveFile_SymlinkFile_Absolute(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - symlinkFileAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-file/test-symlink.txt") +func alterFileContents(content, path string) { + f, err := os.Create(path) if err != nil { - t.Fatal(err) + panic(fmt.Sprintf("error creating file: %s", err)) } - var fileSize string + defer f.Close() - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - resource "archive_file" "foo" { - type = "zip" - source_file = "%s" - output_path = "%s" - output_file_mode = "0666" - } - `, filepath.ToSlash(symlinkFileAbs), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-symlink.txt": []byte(`This is test content`), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) + _, err = f.Write([]byte(content)) + if err != nil { + panic(fmt.Sprintf("error writing file: %s", err)) + } } -// TestResource_ArchiveFile_SymlinkDirectory_Relative verifies that a symlink to a directory using a relative path -// generates an archive which includes the files in the directory. -func TestResource_ArchiveFile_SymlinkDirectory_Relative(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - var fileSize string +func testAccArchiveFileResourceContentConfig(format, outputPath string) string { + return fmt.Sprintf(` +resource "archive_file" "foo" { + type = "%s" + source_content = "This is some content" + source_content_filename = "content.txt" + output_path = "%s" +} +`, format, filepath.ToSlash(outputPath)) +} - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - resource "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - output_file_mode = "0666" - } - `, filepath.ToSlash("test-fixtures/test-symlink-dir"), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "file1.txt": []byte(`This is file 1`), - "file2.txt": []byte(`This is file 2`), - "file3.txt": []byte(`This is file 3`), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) +func testAccArchiveFileResourceFileConfig(format, outputPath string) string { + return fmt.Sprintf(` +resource "archive_file" "foo" { + type = "%s" + source_file = "test-fixtures/test-dir/test-file.txt" + output_path = "%s" + output_file_mode = "0666" +} +`, format, filepath.ToSlash(outputPath)) } -// TestResource_ArchiveFile_SymlinkDirectory_Absolute verifies that a symlink to a directory using an absolute path -// generates an archive which includes the files in the directory. -func TestResource_ArchiveFile_SymlinkDirectory_Absolute(t *testing.T) { - td := t.TempDir() +func testAccArchiveFileResourceFileSourceFileConfig(format, sourceFile, outputPath string) string { + return fmt.Sprintf(` +resource "archive_file" "foo" { + type = "%s" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" +} +`, format, + filepath.ToSlash(sourceFile), + filepath.ToSlash(outputPath)) +} - f := filepath.Join(td, "zip_file_acc_test.zip") +func testAccArchiveFileResourceDirConfig(format, outputPath string) string { + return fmt.Sprintf(` +resource "archive_file" "foo" { + type = "%s" + source_dir = "test-fixtures/test-dir/test-dir1" + output_path = "%s" + output_file_mode = "0666" +} +`, format, filepath.ToSlash(outputPath)) +} - symlinkDirWithRegularFilesAbs, err := filepath.Abs("test-fixtures/test-symlink-dir") - if err != nil { - t.Fatal(err) - } +func testAccArchiveFileResourceDirExcludesConfig(format, outputPath string) string { + return fmt.Sprintf(` +resource "archive_file" "foo" { + type = "%s" + source_dir = "test-fixtures/test-dir" + excludes = ["test-fixtures/test-dir/file2.txt"] + output_path = "%s" +} +`, format, filepath.ToSlash(outputPath)) +} - var fileSize string +func testAccArchiveFileResourceDirExcludesGlobConfig(format, outputPath string) string { + return fmt.Sprintf(` +resource "archive_file" "foo" { + type = "%s" + source_dir = "test-fixtures/test-dir" + excludes = ["test-fixtures/test-dir/file2.txt", "**/file[2-3].txt"] + output_path = "%s" +} +`, format, filepath.ToSlash(outputPath)) +} - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - resource "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - output_file_mode = "0666" - } - `, filepath.ToSlash(symlinkDirWithRegularFilesAbs), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "file1.txt": []byte(`This is file 1`), - "file2.txt": []byte(`This is file 2`), - "file3.txt": []byte(`This is file 3`), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) +func testAccArchiveFileResourceMultiSourceConfig(format, outputPath string) string { + return fmt.Sprintf(` +resource "archive_file" "foo" { + type = "%s" + source { + filename = "content_1.txt" + content = "This is the content for content_1.txt" + } + source { + filename = "content_2.txt" + content = "This is the content for content_2.txt" + } + output_path = "%s" +} +`, format, filepath.ToSlash(outputPath)) } -// TestResource_ArchiveFile_DirectoryWithSymlinkFile_Relative verifies that a relative path to a directory containing -// a symlink file generates an archive which includes the files in the directory. -func TestResource_ArchiveFile_DirectoryWithSymlinkFile_Relative(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - resource "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - output_file_mode = "0666" - } - `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-file"), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-file.txt": []byte(`This is test content`), - "test-symlink.txt": []byte(`This is test content`), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) -} - -// TestResource_ArchiveFile_DirectoryWithSymlinkFile_Absolute verifies that an absolute path to a directory containing -// a symlink file generates an archive which includes the files in the directory. -func TestResource_ArchiveFile_DirectoryWithSymlinkFile_Absolute(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - symlinkDirWithSymlinkFilesAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-file") - if err != nil { - t.Fatal(err) - } - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - resource "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - output_file_mode = "0666" - } - `, filepath.ToSlash(symlinkDirWithSymlinkFilesAbs), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-file.txt": []byte(`This is test content`), - "test-symlink.txt": []byte(`This is test content`), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) -} - -// TestResource_ArchiveFile_SymlinkDirectoryWithSymlinkFile_Relative verifies that a relative path to a symlink -// file in a symlink directory generates an archive which includes the files in the directory. -func TestResource_ArchiveFile_SymlinkDirectoryWithSymlinkFile_Relative(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - resource "archive_file" "foo" { - type = "zip" - source_file = "%s" - output_path = "%s" - output_file_mode = "0666" - } - `, filepath.ToSlash("test-fixtures/test-symlink-dir-with-symlink-file/test-symlink.txt"), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-symlink.txt": []byte(`This is test content`), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) -} - -// TestResource_ArchiveFile_SymlinkDirectoryWithSymlinkFile_Absolute verifies that an absolute path to a symlink -// file in a symlink directory generates an archive which includes the files in the directory. -func TestResource_ArchiveFile_SymlinkDirectoryWithSymlinkFile_Absolute(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - symlinkFileInSymlinkDirAbs, err := filepath.Abs("test-fixtures/test-symlink-dir-with-symlink-file/test-symlink.txt") - if err != nil { - t.Fatal(err) - } - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - resource "archive_file" "foo" { - type = "zip" - source_file = "%s" - output_path = "%s" - output_file_mode = "0666" - } - `, filepath.ToSlash(symlinkFileInSymlinkDirAbs), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-symlink.txt": []byte(`This is test content`), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) -} - -// TestResource_ArchiveFile_DirectoryWithSymlinkDirectory_Relative verifies that a relative path to a -// directory containing a symlink to a directory generates an archive which includes the directory. -func TestResource_ArchiveFile_DirectoryWithSymlinkDirectory_Relative(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - resource "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - output_file_mode = "0666" - } - `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-dir"), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-symlink-dir/file1.txt": []byte("This is file 1"), - "test-symlink-dir/file2.txt": []byte("This is file 2"), - "test-symlink-dir/file3.txt": []byte("This is file 3"), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) -} - -// TestResource_ArchiveFile_IncludeDirectoryWithSymlinkDirectory_Absolute verifies that an absolute path to a -// directory containing a symlink to a directory generates an archive which includes the directory. -func TestResource_ArchiveFile_IncludeDirectoryWithSymlinkDirectory_Absolute(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - symlinkDirInRegularDirAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-dir") - if err != nil { - t.Fatal(err) - } - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - resource "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - output_file_mode = "0666" - } - `, filepath.ToSlash(symlinkDirInRegularDirAbs), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-symlink-dir/file1.txt": []byte("This is file 1"), - "test-symlink-dir/file2.txt": []byte("This is file 2"), - "test-symlink-dir/file3.txt": []byte("This is file 3"), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) -} - -// TestResource_ArchiveFile_Multiple_Relative verifies that a relative path to a directory containing multiple -// directories including symlink directories generates an archive which includes the directories and files. -func TestResource_ArchiveFile_Multiple_Relative(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - resource "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - output_file_mode = "0666" - } - `, filepath.ToSlash("test-fixtures"), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-dir/test-dir1/file1.txt": []byte("This is file 1"), - "test-dir/test-dir1/file2.txt": []byte("This is file 2"), - "test-dir/test-dir1/file3.txt": []byte("This is file 3"), - "test-dir/test-dir2/file1.txt": []byte("This is file 1"), - "test-dir/test-dir2/file2.txt": []byte("This is file 2"), - "test-dir/test-dir2/file3.txt": []byte("This is file 3"), - "test-dir/test-file.txt": []byte("This is test content"), - "test-dir-with-symlink-dir/test-symlink-dir/file1.txt": []byte("This is file 1"), - "test-dir-with-symlink-dir/test-symlink-dir/file2.txt": []byte("This is file 2"), - "test-dir-with-symlink-dir/test-symlink-dir/file3.txt": []byte("This is file 3"), - "test-dir-with-symlink-file/test-file.txt": []byte("This is test content"), - "test-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), - "test-symlink-dir/file1.txt": []byte("This is file 1"), - "test-symlink-dir/file2.txt": []byte("This is file 2"), - "test-symlink-dir/file3.txt": []byte("This is file 3"), - "test-symlink-dir-with-symlink-file/test-file.txt": []byte("This is test content"), - "test-symlink-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) -} - -// TestResource_ArchiveFile_Multiple_Absolute verifies that an absolute path to a directory containing multiple -// directories including symlink directories generates an archive which includes the directories and files. -func TestResource_ArchiveFile_Multiple_Absolute(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - multipleDirsAndFilesAbs, err := filepath.Abs("test-fixtures") - if err != nil { - t.Fatal(err) - } - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - resource "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - output_file_mode = "0666" - } - `, filepath.ToSlash(multipleDirsAndFilesAbs), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-dir/test-dir1/file1.txt": []byte("This is file 1"), - "test-dir/test-dir1/file2.txt": []byte("This is file 2"), - "test-dir/test-dir1/file3.txt": []byte("This is file 3"), - "test-dir/test-dir2/file1.txt": []byte("This is file 1"), - "test-dir/test-dir2/file2.txt": []byte("This is file 2"), - "test-dir/test-dir2/file3.txt": []byte("This is file 3"), - "test-dir/test-file.txt": []byte("This is test content"), - "test-dir-with-symlink-dir/test-symlink-dir/file1.txt": []byte("This is file 1"), - "test-dir-with-symlink-dir/test-symlink-dir/file2.txt": []byte("This is file 2"), - "test-dir-with-symlink-dir/test-symlink-dir/file3.txt": []byte("This is file 3"), - "test-dir-with-symlink-file/test-file.txt": []byte("This is test content"), - "test-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), - "test-symlink-dir/file1.txt": []byte("This is file 1"), - "test-symlink-dir/file2.txt": []byte("This is file 2"), - "test-symlink-dir/file3.txt": []byte("This is file 3"), - "test-symlink-dir-with-symlink-file/test-file.txt": []byte("This is test content"), - "test-symlink-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) -} - -// TestResource_ArchiveFile_SymlinkFile_Relative_ExcludeSymlinkDirectories verifies that a symlink to a file using a relative -// path generates an archive which includes the file. -func TestResource_ArchiveFile_SymlinkFile_Relative_ExcludeSymlinkDirectories(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - resource "archive_file" "foo" { - type = "zip" - source_file = "%s" - output_path = "%s" - output_file_mode = "0666" - exclude_symlink_directories = true - } - `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-file/test-symlink.txt"), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-symlink.txt": []byte(`This is test content`), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) -} - -// TestResource_ArchiveFile_SymlinkFile_Absolute_ExcludeSymlinkDirectories verifies that a symlink to a file using an absolute -// path generates an archive which includes the file. -func TestResource_ArchiveFile_SymlinkFile_Absolute_ExcludeSymlinkDirectories(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - symlinkFileAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-file/test-symlink.txt") - if err != nil { - t.Fatal(err) - } - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - resource "archive_file" "foo" { - type = "zip" - source_file = "%s" - output_path = "%s" - output_file_mode = "0666" - exclude_symlink_directories = true - } - `, filepath.ToSlash(symlinkFileAbs), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-symlink.txt": []byte(`This is test content`), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) -} - -// TestResource_ArchiveFile_SymlinkDirectory_Relative_ExcludeSymlinkDirectories verifies that an empty archive -// is generated when trying to archive a directory which only contains a symlink to a directory. -func TestResource_ArchiveFile_SymlinkDirectory_Relative_ExcludeSymlinkDirectories(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - resource "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - output_file_mode = "0666" - exclude_symlink_directories = true - } - `, filepath.ToSlash("test-fixtures/test-symlink-dir"), filepath.ToSlash(f)), - ExpectError: regexp.MustCompile(`.*error creating archive: error archiving directory: archive has not been\ncreated as it would be empty`), - }, - }, - }) -} - -// TestResource_ArchiveFile_SymlinkDirectory_Absolute_ExcludeSymlinkDirectories verifies that an empty archive -// is generated when trying to archive a directory which only contains a symlink to a directory. -func TestResource_ArchiveFile_SymlinkDirectory_Absolute_ExcludeSymlinkDirectories(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - symlinkDirWithRegularFilesAbs, err := filepath.Abs("test-fixtures/test-symlink-dir") - if err != nil { - t.Fatal(err) - } - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - resource "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - output_file_mode = "0666" - exclude_symlink_directories = true - } - `, filepath.ToSlash(symlinkDirWithRegularFilesAbs), filepath.ToSlash(f)), - ExpectError: regexp.MustCompile(`.*error creating archive: error archiving directory: archive has not been\ncreated as it would be empty`), - }, - }, - }) -} - -// TestResource_ArchiveFile_DirectoryWithSymlinkFile_Relative_ExcludeSymlinkDirectories verifies that a relative path to a -// directory containing a symlink file generates an archive which includes the files in the directory. -func TestResource_ArchiveFile_DirectoryWithSymlinkFile_Relative_ExcludeSymlinkDirectories(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - resource "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - output_file_mode = "0666" - exclude_symlink_directories = true - } - `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-file"), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-file.txt": []byte(`This is test content`), - "test-symlink.txt": []byte(`This is test content`), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) -} - -// TestResource_ArchiveFile_DirectoryWithSymlinkFile_Absolute_ExcludeSymlinkDirectories verifies that an absolute path to a -// directory containing a symlink file generates an archive which includes the files in the directory. -func TestResource_ArchiveFile_DirectoryWithSymlinkFile_Absolute_ExcludeSymlinkDirectories(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - symlinkDirWithSymlinkFilesAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-file") - if err != nil { - t.Fatal(err) - } - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - resource "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - output_file_mode = "0666" - exclude_symlink_directories = true - } - `, filepath.ToSlash(symlinkDirWithSymlinkFilesAbs), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-file.txt": []byte(`This is test content`), - "test-symlink.txt": []byte(`This is test content`), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) -} - -// TestResource_ArchiveFile_SymlinkDirectoryWithSymlinkFile_Relative_ExcludeSymlinkDirectories verifies that a relative path -// to a symlink file in a symlink directory generates an archive which includes the files in the directory. -func TestResource_ArchiveFile_SymlinkDirectoryWithSymlinkFile_Relative_ExcludeSymlinkDirectories(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - resource "archive_file" "foo" { - type = "zip" - source_file = "%s" - output_path = "%s" - output_file_mode = "0666" - exclude_symlink_directories = true - } - `, filepath.ToSlash("test-fixtures/test-symlink-dir-with-symlink-file/test-symlink.txt"), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-symlink.txt": []byte(`This is test content`), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) -} - -// TestResource_ArchiveFile_SymlinkDirectoryWithSymlinkFile_Absolute_ExcludeSymlinkDirectories verifies that an absolute path -// to a symlink file in a symlink directory generates an archive which includes the files in the directory. -func TestResource_ArchiveFile_SymlinkDirectoryWithSymlinkFile_Absolute_ExcludeSymlinkDirectories(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - symlinkFileInSymlinkDirAbs, err := filepath.Abs("test-fixtures/test-symlink-dir-with-symlink-file/test-symlink.txt") - if err != nil { - t.Fatal(err) - } - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - resource "archive_file" "foo" { - type = "zip" - source_file = "%s" - output_path = "%s" - output_file_mode = "0666" - exclude_symlink_directories = true - } - `, filepath.ToSlash(symlinkFileInSymlinkDirAbs), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-symlink.txt": []byte(`This is test content`), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) -} - -// TestResource_ArchiveFile_DirectoryWithSymlinkDirectory_Relative_ExcludeSymlinkDirectories verifies that an empty archive -// is generated when trying to archive a directory which only contains a symlink to a directory. -func TestResource_ArchiveFile_DirectoryWithSymlinkDirectory_Relative_ExcludeSymlinkDirectories(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - resource "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - exclude_symlink_directories = true - } - `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-dir"), filepath.ToSlash(f)), - ExpectError: regexp.MustCompile(`.*error creating archive: error archiving directory: archive has not been\ncreated as it would be empty`), - }, - }, - }) -} - -// TestResource_ArchiveFile_IncludeDirectoryWithSymlinkDirectory_Absolute_ExcludeSymlinkDirectories verifies that an empty archive -// is generated when trying to archive a directory which only contains a symlink to a directory. -func TestResource_ArchiveFile_IncludeDirectoryWithSymlinkDirectory_Absolute_ExcludeSymlinkDirectories(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - symlinkDirInRegularDirAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-dir") - if err != nil { - t.Fatal(err) - } - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - resource "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - exclude_symlink_directories = true - } - `, filepath.ToSlash(symlinkDirInRegularDirAbs), filepath.ToSlash(f)), - ExpectError: regexp.MustCompile(`.*error creating archive: error archiving directory: archive has not been\ncreated as it would be empty`), - }, - }, - }) -} - -// TestResource_ArchiveFile_Multiple_Relative_ExcludeSymlinkDirectories verifies that -// symlinked directories are excluded. -func TestResource_ArchiveFile_Multiple_Relative_ExcludeSymlinkDirectories(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - resource "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - output_file_mode = "0666" - exclude_symlink_directories = true - } - `, filepath.ToSlash("test-fixtures"), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-dir/test-dir1/file1.txt": []byte("This is file 1"), - "test-dir/test-dir1/file2.txt": []byte("This is file 2"), - "test-dir/test-dir1/file3.txt": []byte("This is file 3"), - "test-dir/test-dir2/file1.txt": []byte("This is file 1"), - "test-dir/test-dir2/file2.txt": []byte("This is file 2"), - "test-dir/test-dir2/file3.txt": []byte("This is file 3"), - "test-dir/test-file.txt": []byte("This is test content"), - "test-dir-with-symlink-file/test-file.txt": []byte("This is test content"), - "test-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) -} - -// TestResource_ArchiveFile_Multiple_Relative_ExcludeSymlinkDirectories verifies that -// symlinked directories are excluded. -func TestResource_ArchiveFile_Multiple_Absolute_ExcludeSymlinkDirectories(t *testing.T) { - td := t.TempDir() - - f := filepath.Join(td, "zip_file_acc_test.zip") - - multipleDirsAndFilesAbs, err := filepath.Abs("test-fixtures") - if err != nil { - t.Fatal(err) - } - - var fileSize string - - r.ParallelTest(t, r.TestCase{ - ProtoV5ProviderFactories: protoV5ProviderFactories(), - Steps: []r.TestStep{ - { - Config: fmt.Sprintf(` - resource "archive_file" "foo" { - type = "zip" - source_dir = "%s" - output_path = "%s" - output_file_mode = "0666" - exclude_symlink_directories = true - } - `, filepath.ToSlash(multipleDirsAndFilesAbs), filepath.ToSlash(f)), - Check: r.ComposeTestCheckFunc( - testAccArchiveFileSize(f, &fileSize), - r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), - r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { - ensureContents(t, value, map[string][]byte{ - "test-dir/test-dir1/file1.txt": []byte("This is file 1"), - "test-dir/test-dir1/file2.txt": []byte("This is file 2"), - "test-dir/test-dir1/file3.txt": []byte("This is file 3"), - "test-dir/test-dir2/file1.txt": []byte("This is file 1"), - "test-dir/test-dir2/file2.txt": []byte("This is file 2"), - "test-dir/test-dir2/file3.txt": []byte("This is file 3"), - "test-dir/test-file.txt": []byte("This is test content"), - "test-dir-with-symlink-file/test-file.txt": []byte("This is test content"), - "test-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), - }) - ensureFileMode(t, value, "0666") - return nil - }), - ), - }, - }, - }) -} - -func alterFileContents(content, path string) { - f, err := os.Create(path) - if err != nil { - panic(fmt.Sprintf("error creating file: %s", err)) - } - - defer f.Close() - - _, err = f.Write([]byte(content)) - if err != nil { - panic(fmt.Sprintf("error writing file: %s", err)) - } -} - -func testAccArchiveFileResourceContentConfig(outputPath string) string { - return fmt.Sprintf(` -resource "archive_file" "foo" { - type = "zip" - source_content = "This is some content" - source_content_filename = "content.txt" - output_path = "%s" -} -`, filepath.ToSlash(outputPath)) -} - -func testAccArchiveFileResourceFileConfig(outputPath string) string { - return fmt.Sprintf(` -resource "archive_file" "foo" { - type = "zip" - source_file = "test-fixtures/test-dir/test-file.txt" - output_path = "%s" - output_file_mode = "0666" -} -`, filepath.ToSlash(outputPath)) -} - -func testAccArchiveFileResourceFileSourceFileConfig(sourceFile, outputPath string) string { - return fmt.Sprintf(` -resource "archive_file" "foo" { - type = "zip" - source_file = "%s" - output_path = "%s" - output_file_mode = "0666" -} -`, - filepath.ToSlash(sourceFile), - filepath.ToSlash(outputPath)) -} - -func testAccArchiveFileResourceDirConfig(outputPath string) string { - return fmt.Sprintf(` -resource "archive_file" "foo" { - type = "zip" - source_dir = "test-fixtures/test-dir/test-dir1" - output_path = "%s" - output_file_mode = "0666" -} -`, filepath.ToSlash(outputPath)) -} - -func testAccArchiveFileResourceDirExcludesConfig(outputPath string) string { +func testResourceSourceConfigMissing(format string) string { return fmt.Sprintf(` resource "archive_file" "foo" { - type = "zip" - source_dir = "test-fixtures/test-dir" - excludes = ["test-fixtures/test-dir/file2.txt"] - output_path = "%s" -} -`, filepath.ToSlash(outputPath)) -} - -func testAccArchiveFileResourceDirExcludesGlobConfig(outputPath string) string { - return fmt.Sprintf(` -resource "archive_file" "foo" { - type = "zip" - source_dir = "test-fixtures/test-dir" - excludes = ["test-fixtures/test-dir/file2.txt", "**/file[2-3].txt"] - output_path = "%s" -} -`, filepath.ToSlash(outputPath)) -} - -func testAccArchiveFileResourceMultiSourceConfig(outputPath string) string { - return fmt.Sprintf(` -resource "archive_file" "foo" { - type = "zip" - source { - filename = "content_1.txt" - content = "This is the content for content_1.txt" - } - source { - filename = "content_2.txt" - content = "This is the content for content_2.txt" - } - output_path = "%s" -} -`, filepath.ToSlash(outputPath)) -} - -func testResourceSourceConfigMissing() string { - return ` -resource "archive_file" "foo" { - type = "zip" + type = "%s" output_path = "path" } -` +`, format) } -func testResourceSourceConfigConflicting() string { - return ` +func testResourceSourceConfigConflicting(format string) string { + return fmt.Sprintf(` resource "archive_file" "foo" { - type = "zip" + type = "%s" source { filename = "content_1.txt" content = "This is the content for content_1.txt" @@ -1540,5 +404,5 @@ resource "archive_file" "foo" { source_dir = "test-fixtures/test-dir" output_path = "path" } -` +`, format) } diff --git a/internal/provider/resource_archive_file_tgz_test.go b/internal/provider/resource_archive_file_tgz_test.go new file mode 100644 index 00000000..7b1f0e13 --- /dev/null +++ b/internal/provider/resource_archive_file_tgz_test.go @@ -0,0 +1,1149 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package archive + +import ( + "fmt" + "path/filepath" + "regexp" + "testing" + + r "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestAccTarGzArchiveFile_Resource_Basic(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + var fileSize string + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: testAccArchiveFileResourceContentConfig("tar.gz", f), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttr( + "archive_file.foo", "output_md5", "a09ee39e708c38ccd9ba44cc39e7cacc", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_sha", "6c84af188d367644731196007301c9dc93914b0e", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_sha256", "ae18ec27af576dd62f29cec7ae0df130e7487c1a3cddefdec9f27d5ed3a4ca95", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_base64sha256", "rhjsJ69XbdYvKc7Hrg3xMOdIfBo83e/eyfJ9XtOkypU=", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_sha512", "ce93a8ba072bad42656a41def0c9ed160f9109c1a7087fb0dcf0b9fce9effc25477f9cdbf9cbc5aa593f3ded0e0db11d2c8cf67dc8d2693ff4069aa01071e68d", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_base64sha512", "zpOougcrrUJlakHe8MntFg+RCcGnCH+w3PC5/Onv/CVHf5zb+cvFqlk/Pe0ODbEdLIz2fcjSaT/0BpqgEHHmjQ==", + ), + ), + }, + { + Config: testAccArchiveFileResourceFileConfig("tar.gz", f), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttr( + "archive_file.foo", "output_md5", "39948f8ddedc8914ac2e42dd18dd3c06", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_sha", "d2f26a69cbb920715f797f81c1477c41d8fc9195", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_sha256", "6f1b1a5d17e42fae154f0bdf9301a0ad43394d7fe8485b64dfdb533a0cf07784", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_base64sha256", "bxsaXRfkL64VTwvfkwGgrUM5TX/oSFtk39tTOgzwd4Q=", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_sha512", "e0dc636c3d11095a5b5e97c598185ee3d8a0ed7d1accb69cc28419aeeaeda22b2e774a260f71892a2e85efae1a3aee36669b61dafaed9ac0886d2ca8c5add6e9", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_base64sha512", "4NxjbD0RCVpbXpfFmBhe49ig7X0azLacwoQZrurtoisud0omD3GJKi6F764aOu42Zpth2vrtmsCIbSyoxa3W6Q==", + ), + ), + }, + { + Config: testAccArchiveFileResourceDirConfig("tar.gz", f), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttr( + "archive_file.foo", "output_md5", "6678fae1fe2077c767bac136861e3bdc", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_sha", "3af6ef3c57aaa5ab3681cd25f916d6651b806cb6", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_sha256", "1b10e0f355025819486fb688aa04217939ea976cd271089bc0092e2994dbaaba", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_base64sha256", "GxDg81UCWBlIb7aIqgQheTnql2zScQibwAkuKZTbqro=", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_sha512", "adb56fca1e40420d4f994d031a08ca0d1ee51783f3c5d1631b6ed2b460ff2577f9154cb5f1c06edd0b0162899f7cfa7cc3d1f02ec9c9ae76f7ea64a31ba8cb81", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_base64sha512", "rbVvyh5AQg1PmU0DGgjKDR7lF4PzxdFjG27StGD/JXf5FUy18cBu3QsBYomffPp8w9HwLsnJrnb36mSjG6jLgQ==", + ), + ), + }, + { + Config: testAccArchiveFileResourceDirExcludesConfig("tar.gz", f), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + ), + }, + { + Config: testAccArchiveFileResourceDirExcludesGlobConfig("tar.gz", f), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + ), + }, + { + Config: testAccArchiveFileResourceMultiSourceConfig("tar.gz", f), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + ), + }, + }, + }) +} + +// TestResource_TarGzFileConfig_ModifiedContents tests that archive_file resource replaces the resource on every read. +// The contents of the source file are altered, but no aspect of the Terraform configuration is changed. +// The change in the output hashes demonstrates that the resource Read function is replacing the resource. +func TestResource_TarGzFileConfig_ModifiedContents(t *testing.T) { + td := t.TempDir() + + sourceFilePath := filepath.Join(td, "sourceFile") + outputFilePath := filepath.Join(td, "tgz_file_acc_test_upgrade_file_config.tar.gz") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + Steps: []r.TestStep{ + { + PreConfig: func() { + alterFileContents("content", sourceFilePath) + }, + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Config: testAccArchiveFileResourceFileSourceFileConfig("tar.gz", sourceFilePath, outputFilePath), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(outputFilePath, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttr( + "archive_file.foo", "output_base64sha256", "7iA9Si8nqVmS7vKVzRfUxvNXNucEnbjt8qrKJIinx2A=", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_md5", "9a562888c7cfc3f1b20cb68f0fb99e4e", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_sha", "159e394a629b7b603ff363158c289b0f3ccf852b", + ), + ), + }, + { + PreConfig: func() { + alterFileContents("modified content", sourceFilePath) + }, + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Config: testAccArchiveFileResourceFileSourceFileConfig("tar.gz", sourceFilePath, outputFilePath), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(outputFilePath, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttr( + "archive_file.foo", "output_base64sha256", "2ckWwetFiFJ9ODvHgKR+QpL0A2YtMW3aFMOIoSVWc2o=", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_md5", "f42e3989922bdf3a98c6ec5836dcb775", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_sha", "b7dbd9413862c94ccb47f1a61d334a2633733705", + ), + ), + }, + }, + }) +} + +// TestResource_TarGzArchiveFile_SymlinkFile_Relative verifies that a symlink to a file using a relative path generates an +// archive which includes the file. +func TestResource_TarGzArchiveFile_SymlinkFile_Relative(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "tar.gz" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-file/test-symlink.txt"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_TarGzArchiveFile_SymlinkFile_Absolute verifies that a symlink to a file using an absolute path generates an +// archive which includes the file. +func TestResource_TarGzArchiveFile_SymlinkFile_Absolute(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + symlinkFileAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-file/test-symlink.txt") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "tar.gz" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash(symlinkFileAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_TarGzArchiveFile_SymlinkDirectory_Relative verifies that a symlink to a directory using a relative path +// generates an archive which includes the files in the directory. +func TestResource_TarGzArchiveFile_SymlinkDirectory_Relative(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash("test-fixtures/test-symlink-dir"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "file1.txt": []byte(`This is file 1`), + "file2.txt": []byte(`This is file 2`), + "file3.txt": []byte(`This is file 3`), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_TarGzArchiveFile_SymlinkDirectory_Absolute verifies that a symlink to a directory using an absolute path +// generates an archive which includes the files in the directory. +func TestResource_TarGzArchiveFile_SymlinkDirectory_Absolute(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + symlinkDirWithRegularFilesAbs, err := filepath.Abs("test-fixtures/test-symlink-dir") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash(symlinkDirWithRegularFilesAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "file1.txt": []byte(`This is file 1`), + "file2.txt": []byte(`This is file 2`), + "file3.txt": []byte(`This is file 3`), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_TarGzArchiveFile_DirectoryWithSymlinkFile_Relative verifies that a relative path to a directory containing +// a symlink file generates an archive which includes the files in the directory. +func TestResource_TarGzArchiveFile_DirectoryWithSymlinkFile_Relative(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-file"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-file.txt": []byte(`This is test content`), + "test-symlink.txt": []byte(`This is test content`), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_TarGzArchiveFile_DirectoryWithSymlinkFile_Absolute verifies that an absolute path to a directory containing +// a symlink file generates an archive which includes the files in the directory. +func TestResource_TarGzArchiveFile_DirectoryWithSymlinkFile_Absolute(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + symlinkDirWithSymlinkFilesAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-file") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash(symlinkDirWithSymlinkFilesAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-file.txt": []byte(`This is test content`), + "test-symlink.txt": []byte(`This is test content`), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_TarGzArchiveFile_SymlinkDirectoryWithSymlinkFile_Relative verifies that a relative path to a symlink +// file in a symlink directory generates an archive which includes the files in the directory. +func TestResource_TarGzArchiveFile_SymlinkDirectoryWithSymlinkFile_Relative(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "tar.gz" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash("test-fixtures/test-symlink-dir-with-symlink-file/test-symlink.txt"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_TarGzArchiveFile_SymlinkDirectoryWithSymlinkFile_Absolute verifies that an absolute path to a symlink +// file in a symlink directory generates an archive which includes the files in the directory. +func TestResource_TarGzArchiveFile_SymlinkDirectoryWithSymlinkFile_Absolute(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + symlinkFileInSymlinkDirAbs, err := filepath.Abs("test-fixtures/test-symlink-dir-with-symlink-file/test-symlink.txt") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "tar.gz" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash(symlinkFileInSymlinkDirAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_TarGzArchiveFile_DirectoryWithSymlinkDirectory_Relative verifies that a relative path to a +// directory containing a symlink to a directory generates an archive which includes the directory. +func TestResource_TarGzArchiveFile_DirectoryWithSymlinkDirectory_Relative(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-dir"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-symlink-dir/file1.txt": []byte("This is file 1"), + "test-symlink-dir/file2.txt": []byte("This is file 2"), + "test-symlink-dir/file3.txt": []byte("This is file 3"), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_TarGzArchiveFile_IncludeDirectoryWithSymlinkDirectory_Absolute verifies that an absolute path to a +// directory containing a symlink to a directory generates an archive which includes the directory. +func TestResource_TarGzArchiveFile_IncludeDirectoryWithSymlinkDirectory_Absolute(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + symlinkDirInRegularDirAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-dir") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash(symlinkDirInRegularDirAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-symlink-dir/file1.txt": []byte("This is file 1"), + "test-symlink-dir/file2.txt": []byte("This is file 2"), + "test-symlink-dir/file3.txt": []byte("This is file 3"), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_TarGzArchiveFile_Multiple_Relative verifies that a relative path to a directory containing multiple +// directories including symlink directories generates an archive which includes the directories and files. +func TestResource_TarGzArchiveFile_Multiple_Relative(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash("test-fixtures"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-dir/test-dir1/file1.txt": []byte("This is file 1"), + "test-dir/test-dir1/file2.txt": []byte("This is file 2"), + "test-dir/test-dir1/file3.txt": []byte("This is file 3"), + "test-dir/test-dir2/file1.txt": []byte("This is file 1"), + "test-dir/test-dir2/file2.txt": []byte("This is file 2"), + "test-dir/test-dir2/file3.txt": []byte("This is file 3"), + "test-dir/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-dir/test-symlink-dir/file1.txt": []byte("This is file 1"), + "test-dir-with-symlink-dir/test-symlink-dir/file2.txt": []byte("This is file 2"), + "test-dir-with-symlink-dir/test-symlink-dir/file3.txt": []byte("This is file 3"), + "test-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), + "test-symlink-dir/file1.txt": []byte("This is file 1"), + "test-symlink-dir/file2.txt": []byte("This is file 2"), + "test-symlink-dir/file3.txt": []byte("This is file 3"), + "test-symlink-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + "test-symlink-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_TarGzArchiveFile_Multiple_Absolute verifies that an absolute path to a directory containing multiple +// directories including symlink directories generates an archive which includes the directories and files. +func TestResource_TarGzArchiveFile_Multiple_Absolute(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + multipleDirsAndFilesAbs, err := filepath.Abs("test-fixtures") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash(multipleDirsAndFilesAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-dir/test-dir1/file1.txt": []byte("This is file 1"), + "test-dir/test-dir1/file2.txt": []byte("This is file 2"), + "test-dir/test-dir1/file3.txt": []byte("This is file 3"), + "test-dir/test-dir2/file1.txt": []byte("This is file 1"), + "test-dir/test-dir2/file2.txt": []byte("This is file 2"), + "test-dir/test-dir2/file3.txt": []byte("This is file 3"), + "test-dir/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-dir/test-symlink-dir/file1.txt": []byte("This is file 1"), + "test-dir-with-symlink-dir/test-symlink-dir/file2.txt": []byte("This is file 2"), + "test-dir-with-symlink-dir/test-symlink-dir/file3.txt": []byte("This is file 3"), + "test-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), + "test-symlink-dir/file1.txt": []byte("This is file 1"), + "test-symlink-dir/file2.txt": []byte("This is file 2"), + "test-symlink-dir/file3.txt": []byte("This is file 3"), + "test-symlink-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + "test-symlink-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_TarGzArchiveFile_SymlinkFile_Relative_ExcludeSymlinkDirectories verifies that a symlink to a file using a relative +// path generates an archive which includes the file. +func TestResource_TarGzArchiveFile_SymlinkFile_Relative_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "tar.gz" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-file/test-symlink.txt"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_TarGzArchiveFile_SymlinkFile_Absolute_ExcludeSymlinkDirectories verifies that a symlink to a file using an absolute +// path generates an archive which includes the file. +func TestResource_TarGzArchiveFile_SymlinkFile_Absolute_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + symlinkFileAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-file/test-symlink.txt") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "tar.gz" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash(symlinkFileAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_TarGzArchiveFile_SymlinkDirectory_Relative_ExcludeSymlinkDirectories verifies that an empty archive +// is generated when trying to archive a directory which only contains a symlink to a directory. +func TestResource_TarGzArchiveFile_SymlinkDirectory_Relative_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash("test-fixtures/test-symlink-dir"), filepath.ToSlash(f)), + ExpectError: regexp.MustCompile(`.*error creating archive: error archiving directory: archive has not been\ncreated as it would be empty`), + }, + }, + }) +} + +// TestResource_TarGzArchiveFile_SymlinkDirectory_Absolute_ExcludeSymlinkDirectories verifies that an empty archive +// is generated when trying to archive a directory which only contains a symlink to a directory. +func TestResource_TarGzArchiveFile_SymlinkDirectory_Absolute_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + symlinkDirWithRegularFilesAbs, err := filepath.Abs("test-fixtures/test-symlink-dir") + if err != nil { + t.Fatal(err) + } + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash(symlinkDirWithRegularFilesAbs), filepath.ToSlash(f)), + ExpectError: regexp.MustCompile(`.*error creating archive: error archiving directory: archive has not been\ncreated as it would be empty`), + }, + }, + }) +} + +// TestResource_TarGzArchiveFile_DirectoryWithSymlinkFile_Relative_ExcludeSymlinkDirectories verifies that a relative path to a +// directory containing a symlink file generates an archive which includes the files in the directory. +func TestResource_TarGzArchiveFile_DirectoryWithSymlinkFile_Relative_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-file"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-file.txt": []byte(`This is test content`), + "test-symlink.txt": []byte(`This is test content`), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_TarGzArchiveFile_DirectoryWithSymlinkFile_Absolute_ExcludeSymlinkDirectories verifies that an absolute path to a +// directory containing a symlink file generates an archive which includes the files in the directory. +func TestResource_TarGzArchiveFile_DirectoryWithSymlinkFile_Absolute_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + symlinkDirWithSymlinkFilesAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-file") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash(symlinkDirWithSymlinkFilesAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-file.txt": []byte(`This is test content`), + "test-symlink.txt": []byte(`This is test content`), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_TarGzArchiveFile_SymlinkDirectoryWithSymlinkFile_Relative_ExcludeSymlinkDirectories verifies that a relative path +// to a symlink file in a symlink directory generates an archive which includes the files in the directory. +func TestResource_TarGzArchiveFile_SymlinkDirectoryWithSymlinkFile_Relative_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "tar.gz" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash("test-fixtures/test-symlink-dir-with-symlink-file/test-symlink.txt"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_TarGzArchiveFile_SymlinkDirectoryWithSymlinkFile_Absolute_ExcludeSymlinkDirectories verifies that an absolute path +// to a symlink file in a symlink directory generates an archive which includes the files in the directory. +func TestResource_TarGzArchiveFile_SymlinkDirectoryWithSymlinkFile_Absolute_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + symlinkFileInSymlinkDirAbs, err := filepath.Abs("test-fixtures/test-symlink-dir-with-symlink-file/test-symlink.txt") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "tar.gz" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash(symlinkFileInSymlinkDirAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_TarGzArchiveFile_DirectoryWithSymlinkDirectory_Relative_ExcludeSymlinkDirectories verifies that an empty archive +// is generated when trying to archive a directory which only contains a symlink to a directory. +func TestResource_TarGzArchiveFile_DirectoryWithSymlinkDirectory_Relative_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + exclude_symlink_directories = true + } + `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-dir"), filepath.ToSlash(f)), + ExpectError: regexp.MustCompile(`.*error creating archive: error archiving directory: archive has not been\ncreated as it would be empty`), + }, + }, + }) +} + +// TestResource_TarGzArchiveFile_IncludeDirectoryWithSymlinkDirectory_Absolute_ExcludeSymlinkDirectories verifies that an empty archive +// is generated when trying to archive a directory which only contains a symlink to a directory. +func TestResource_TarGzArchiveFile_IncludeDirectoryWithSymlinkDirectory_Absolute_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + symlinkDirInRegularDirAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-dir") + if err != nil { + t.Fatal(err) + } + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + exclude_symlink_directories = true + } + `, filepath.ToSlash(symlinkDirInRegularDirAbs), filepath.ToSlash(f)), + ExpectError: regexp.MustCompile(`.*error creating archive: error archiving directory: archive has not been\ncreated as it would be empty`), + }, + }, + }) +} + +// TestResource_TarGzArchiveFile_Multiple_Relative_ExcludeSymlinkDirectories verifies that +// symlinked directories are excluded. +func TestResource_TarGzArchiveFile_Multiple_Relative_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash("test-fixtures"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-dir/test-dir1/file1.txt": []byte("This is file 1"), + "test-dir/test-dir1/file2.txt": []byte("This is file 2"), + "test-dir/test-dir1/file3.txt": []byte("This is file 3"), + "test-dir/test-dir2/file1.txt": []byte("This is file 1"), + "test-dir/test-dir2/file2.txt": []byte("This is file 2"), + "test-dir/test-dir2/file3.txt": []byte("This is file 3"), + "test-dir/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_TarGzArchiveFile_Multiple_Relative_ExcludeSymlinkDirectories verifies that +// symlinked directories are excluded. +func TestResource_TarGzArchiveFile_Multiple_Absolute_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "tgz_file_acc_test.tar.gz") + + multipleDirsAndFilesAbs, err := filepath.Abs("test-fixtures") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "tar.gz" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash(multipleDirsAndFilesAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureTarContents(t, value, map[string][]byte{ + "test-dir/test-dir1/file1.txt": []byte("This is file 1"), + "test-dir/test-dir1/file2.txt": []byte("This is file 2"), + "test-dir/test-dir1/file3.txt": []byte("This is file 3"), + "test-dir/test-dir2/file1.txt": []byte("This is file 1"), + "test-dir/test-dir2/file2.txt": []byte("This is file 2"), + "test-dir/test-dir2/file3.txt": []byte("This is file 3"), + "test-dir/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), + }) + ensureTarFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} diff --git a/internal/provider/resource_archive_file_zip_test.go b/internal/provider/resource_archive_file_zip_test.go new file mode 100644 index 00000000..5cbea36d --- /dev/null +++ b/internal/provider/resource_archive_file_zip_test.go @@ -0,0 +1,1149 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package archive + +import ( + "fmt" + "path/filepath" + "regexp" + "testing" + + r "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestAccZipArchiveFile_Resource_Basic(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + var fileSize string + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: testAccArchiveFileResourceContentConfig("zip", f), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttr( + "archive_file.foo", "output_md5", "ea35f0444ea9a3d5641d8760bc2815cc", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_sha", "019c79c4dc14dbe1edb3e467b2de6a6aad148717", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_sha256", "3fb55c931a048943b8d7558dde7c2e4bfc8e04be33b1b55691053d1352391fa7", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_base64sha256", "P7VckxoEiUO411WN3nwuS/yOBL4zsbVWkQU9E1I5H6c=", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_sha512", "57e2d073dce214609bd61113b90b0b2b7c75034047224d56e35f363c8f2662e3acd561eebf94826a67453411181eca7e1cbf15db1f2fdd496cf13df46b7848c3", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_base64sha512", "V+LQc9ziFGCb1hETuQsLK3x1A0BHIk1W4182PI8mYuOs1WHuv5SCamdFNBEYHsp+HL8V2x8v3Uls8T30a3hIww==", + ), + ), + }, + { + Config: testAccArchiveFileResourceFileConfig("zip", f), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttr( + "archive_file.foo", "output_md5", "59fbc9e62af3cbc2f588f97498240dae", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_sha", "ce4ee1450ab93ac86e11446649e44cea907b6568", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_sha256", "5131387f97167da47aa741df3ab2c82f182f17c514c222538d34708d04e0756b", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_base64sha256", "UTE4f5cWfaR6p0HfOrLILxgvF8UUwiJTjTRwjQTgdWs=", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_sha512", "eb33eb0f8cd8efe1a5a0b99acbd22ed22dbebb80817f8de6e8fed15c21c52240838d9bb46fb0938846c74f694425551ba60829a6396f91fcfe49d21a1e3bb409", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_base64sha512", "6zPrD4zY7+GloLmay9Iu0i2+u4CBf43m6P7RXCHFIkCDjZu0b7CTiEbHT2lEJVUbpggppjlvkfz+SdIaHju0CQ==", + ), + ), + }, + { + Config: testAccArchiveFileResourceDirConfig("zip", f), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttr( + "archive_file.foo", "output_md5", "b73f64a383716070aa4a29563b8b14d4", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_sha", "76d20a402eefd1cfbdc47886abd4e0909616c191", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_sha256", "c9d07cc2dabc9caf6f43bed51fa613c281e6ca58cae3a8d6fae2094b00b3369a", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_base64sha256", "ydB8wtq8nK9vQ77VH6YTwoHmyljK46jW+uIJSwCzNpo=", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_sha512", "b96ac6b9554a04473a733be36f190422bf7162b4afdb211a0f551713eadf4092459426750646c70383ce6c8b89171b88582a608e5841bfaaafa17004a2a2ca0a", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_base64sha512", "uWrGuVVKBEc6czvjbxkEIr9xYrSv2yEaD1UXE+rfQJJFlCZ1BkbHA4PObIuJFxuIWCpgjlhBv6qvoXAEoqLKCg==", + ), + ), + }, + { + Config: testAccArchiveFileResourceDirExcludesConfig("zip", f), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + ), + }, + { + Config: testAccArchiveFileResourceDirExcludesGlobConfig("zip", f), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + ), + }, + { + Config: testAccArchiveFileResourceMultiSourceConfig("zip", f), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + ), + }, + }, + }) +} + +// TestResource_FileConfig_ModifiedContents tests that archive_file resource replaces the resource on every read. +// The contents of the source file are altered, but no aspect of the Terraform configuration is changed. +// The change in the output hashes demonstrates that the resource Read function is replacing the resource. +func TestResource_FileConfig_ModifiedContents(t *testing.T) { + td := t.TempDir() + + sourceFilePath := filepath.Join(td, "sourceFile") + outputFilePath := filepath.Join(td, "zip_file_acc_test_upgrade_file_config.zip") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + Steps: []r.TestStep{ + { + PreConfig: func() { + alterFileContents("content", sourceFilePath) + }, + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Config: testAccArchiveFileResourceFileSourceFileConfig("zip", sourceFilePath, outputFilePath), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(outputFilePath, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttr( + "archive_file.foo", "output_base64sha256", "8inOmQJB12dXqCyRTdaRO63yP22Rmuube/A1DLDii10=", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_md5", "20d9c8096f99174d128e5042279fe576", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_sha", "119d3169ec43fe95bbd38a3824f4e477f4e8d4e7", + ), + ), + }, + { + PreConfig: func() { + alterFileContents("modified content", sourceFilePath) + }, + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Config: testAccArchiveFileResourceFileSourceFileConfig("zip", sourceFilePath, outputFilePath), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(outputFilePath, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttr( + "archive_file.foo", "output_base64sha256", "OnzXDJ3jda5RPuINpxKHQsZ+jSNOupxShSmW3iUWw7Q=", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_md5", "ce31b13da062764f2975d1ef08ee56fe", + ), + r.TestCheckResourceAttr( + "archive_file.foo", "output_sha", "12c51ec24fc5dc10570abbc0b56ac5a3b4141b83", + ), + ), + }, + }, + }) +} + +// TestResource_ZipArchiveFile_SymlinkFile_Relative verifies that a symlink to a file using a relative path generates an +// archive which includes the file. +func TestResource_ZipArchiveFile_SymlinkFile_Relative(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "zip" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-file/test-symlink.txt"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_ZipArchiveFile_SymlinkFile_Absolute verifies that a symlink to a file using an absolute path generates an +// archive which includes the file. +func TestResource_ZipArchiveFile_SymlinkFile_Absolute(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + symlinkFileAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-file/test-symlink.txt") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "zip" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash(symlinkFileAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_ZipArchiveFile_SymlinkDirectory_Relative verifies that a symlink to a directory using a relative path +// generates an archive which includes the files in the directory. +func TestResource_ZipArchiveFile_SymlinkDirectory_Relative(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash("test-fixtures/test-symlink-dir"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "file1.txt": []byte(`This is file 1`), + "file2.txt": []byte(`This is file 2`), + "file3.txt": []byte(`This is file 3`), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_ZipArchiveFile_SymlinkDirectory_Absolute verifies that a symlink to a directory using an absolute path +// generates an archive which includes the files in the directory. +func TestResource_ZipArchiveFile_SymlinkDirectory_Absolute(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + symlinkDirWithRegularFilesAbs, err := filepath.Abs("test-fixtures/test-symlink-dir") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash(symlinkDirWithRegularFilesAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "file1.txt": []byte(`This is file 1`), + "file2.txt": []byte(`This is file 2`), + "file3.txt": []byte(`This is file 3`), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_ZipArchiveFile_DirectoryWithSymlinkFile_Relative verifies that a relative path to a directory containing +// a symlink file generates an archive which includes the files in the directory. +func TestResource_ZipArchiveFile_DirectoryWithSymlinkFile_Relative(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-file"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-file.txt": []byte(`This is test content`), + "test-symlink.txt": []byte(`This is test content`), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_ZipArchiveFile_DirectoryWithSymlinkFile_Absolute verifies that an absolute path to a directory containing +// a symlink file generates an archive which includes the files in the directory. +func TestResource_ZipArchiveFile_DirectoryWithSymlinkFile_Absolute(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + symlinkDirWithSymlinkFilesAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-file") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash(symlinkDirWithSymlinkFilesAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-file.txt": []byte(`This is test content`), + "test-symlink.txt": []byte(`This is test content`), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_ZipArchiveFile_SymlinkDirectoryWithSymlinkFile_Relative verifies that a relative path to a symlink +// file in a symlink directory generates an archive which includes the files in the directory. +func TestResource_ZipArchiveFile_SymlinkDirectoryWithSymlinkFile_Relative(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "zip" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash("test-fixtures/test-symlink-dir-with-symlink-file/test-symlink.txt"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_ZipArchiveFile_SymlinkDirectoryWithSymlinkFile_Absolute verifies that an absolute path to a symlink +// file in a symlink directory generates an archive which includes the files in the directory. +func TestResource_ZipArchiveFile_SymlinkDirectoryWithSymlinkFile_Absolute(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + symlinkFileInSymlinkDirAbs, err := filepath.Abs("test-fixtures/test-symlink-dir-with-symlink-file/test-symlink.txt") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "zip" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash(symlinkFileInSymlinkDirAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_ZipArchiveFile_DirectoryWithSymlinkDirectory_Relative verifies that a relative path to a +// directory containing a symlink to a directory generates an archive which includes the directory. +func TestResource_ZipArchiveFile_DirectoryWithSymlinkDirectory_Relative(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-dir"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-symlink-dir/file1.txt": []byte("This is file 1"), + "test-symlink-dir/file2.txt": []byte("This is file 2"), + "test-symlink-dir/file3.txt": []byte("This is file 3"), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_ZipArchiveFile_IncludeDirectoryWithSymlinkDirectory_Absolute verifies that an absolute path to a +// directory containing a symlink to a directory generates an archive which includes the directory. +func TestResource_ZipArchiveFile_IncludeDirectoryWithSymlinkDirectory_Absolute(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + symlinkDirInRegularDirAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-dir") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash(symlinkDirInRegularDirAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-symlink-dir/file1.txt": []byte("This is file 1"), + "test-symlink-dir/file2.txt": []byte("This is file 2"), + "test-symlink-dir/file3.txt": []byte("This is file 3"), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_ZipArchiveFile_Multiple_Relative verifies that a relative path to a directory containing multiple +// directories including symlink directories generates an archive which includes the directories and files. +func TestResource_ZipArchiveFile_Multiple_Relative(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash("test-fixtures"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-dir/test-dir1/file1.txt": []byte("This is file 1"), + "test-dir/test-dir1/file2.txt": []byte("This is file 2"), + "test-dir/test-dir1/file3.txt": []byte("This is file 3"), + "test-dir/test-dir2/file1.txt": []byte("This is file 1"), + "test-dir/test-dir2/file2.txt": []byte("This is file 2"), + "test-dir/test-dir2/file3.txt": []byte("This is file 3"), + "test-dir/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-dir/test-symlink-dir/file1.txt": []byte("This is file 1"), + "test-dir-with-symlink-dir/test-symlink-dir/file2.txt": []byte("This is file 2"), + "test-dir-with-symlink-dir/test-symlink-dir/file3.txt": []byte("This is file 3"), + "test-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), + "test-symlink-dir/file1.txt": []byte("This is file 1"), + "test-symlink-dir/file2.txt": []byte("This is file 2"), + "test-symlink-dir/file3.txt": []byte("This is file 3"), + "test-symlink-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + "test-symlink-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_ZipArchiveFile_Multiple_Absolute verifies that an absolute path to a directory containing multiple +// directories including symlink directories generates an archive which includes the directories and files. +func TestResource_ZipArchiveFile_Multiple_Absolute(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + multipleDirsAndFilesAbs, err := filepath.Abs("test-fixtures") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + } + `, filepath.ToSlash(multipleDirsAndFilesAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-dir/test-dir1/file1.txt": []byte("This is file 1"), + "test-dir/test-dir1/file2.txt": []byte("This is file 2"), + "test-dir/test-dir1/file3.txt": []byte("This is file 3"), + "test-dir/test-dir2/file1.txt": []byte("This is file 1"), + "test-dir/test-dir2/file2.txt": []byte("This is file 2"), + "test-dir/test-dir2/file3.txt": []byte("This is file 3"), + "test-dir/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-dir/test-symlink-dir/file1.txt": []byte("This is file 1"), + "test-dir-with-symlink-dir/test-symlink-dir/file2.txt": []byte("This is file 2"), + "test-dir-with-symlink-dir/test-symlink-dir/file3.txt": []byte("This is file 3"), + "test-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), + "test-symlink-dir/file1.txt": []byte("This is file 1"), + "test-symlink-dir/file2.txt": []byte("This is file 2"), + "test-symlink-dir/file3.txt": []byte("This is file 3"), + "test-symlink-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + "test-symlink-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_ZipArchiveFile_SymlinkFile_Relative_ExcludeSymlinkDirectories verifies that a symlink to a file using a relative +// path generates an archive which includes the file. +func TestResource_ZipArchiveFile_SymlinkFile_Relative_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "zip" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-file/test-symlink.txt"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_ZipArchiveFile_SymlinkFile_Absolute_ExcludeSymlinkDirectories verifies that a symlink to a file using an absolute +// path generates an archive which includes the file. +func TestResource_ZipArchiveFile_SymlinkFile_Absolute_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + symlinkFileAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-file/test-symlink.txt") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "zip" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash(symlinkFileAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_ZipArchiveFile_SymlinkDirectory_Relative_ExcludeSymlinkDirectories verifies that an empty archive +// is generated when trying to archive a directory which only contains a symlink to a directory. +func TestResource_ZipArchiveFile_SymlinkDirectory_Relative_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash("test-fixtures/test-symlink-dir"), filepath.ToSlash(f)), + ExpectError: regexp.MustCompile(`.*error creating archive: error archiving directory: archive has not been\ncreated as it would be empty`), + }, + }, + }) +} + +// TestResource_ZipArchiveFile_SymlinkDirectory_Absolute_ExcludeSymlinkDirectories verifies that an empty archive +// is generated when trying to archive a directory which only contains a symlink to a directory. +func TestResource_ZipArchiveFile_SymlinkDirectory_Absolute_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + symlinkDirWithRegularFilesAbs, err := filepath.Abs("test-fixtures/test-symlink-dir") + if err != nil { + t.Fatal(err) + } + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash(symlinkDirWithRegularFilesAbs), filepath.ToSlash(f)), + ExpectError: regexp.MustCompile(`.*error creating archive: error archiving directory: archive has not been\ncreated as it would be empty`), + }, + }, + }) +} + +// TestResource_ZipArchiveFile_DirectoryWithSymlinkFile_Relative_ExcludeSymlinkDirectories verifies that a relative path to a +// directory containing a symlink file generates an archive which includes the files in the directory. +func TestResource_ZipArchiveFile_DirectoryWithSymlinkFile_Relative_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-file"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-file.txt": []byte(`This is test content`), + "test-symlink.txt": []byte(`This is test content`), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_ZipArchiveFile_DirectoryWithSymlinkFile_Absolute_ExcludeSymlinkDirectories verifies that an absolute path to a +// directory containing a symlink file generates an archive which includes the files in the directory. +func TestResource_ZipArchiveFile_DirectoryWithSymlinkFile_Absolute_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + symlinkDirWithSymlinkFilesAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-file") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash(symlinkDirWithSymlinkFilesAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-file.txt": []byte(`This is test content`), + "test-symlink.txt": []byte(`This is test content`), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_ZipArchiveFile_SymlinkDirectoryWithSymlinkFile_Relative_ExcludeSymlinkDirectories verifies that a relative path +// to a symlink file in a symlink directory generates an archive which includes the files in the directory. +func TestResource_ZipArchiveFile_SymlinkDirectoryWithSymlinkFile_Relative_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "zip" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash("test-fixtures/test-symlink-dir-with-symlink-file/test-symlink.txt"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_ZipArchiveFile_SymlinkDirectoryWithSymlinkFile_Absolute_ExcludeSymlinkDirectories verifies that an absolute path +// to a symlink file in a symlink directory generates an archive which includes the files in the directory. +func TestResource_ZipArchiveFile_SymlinkDirectoryWithSymlinkFile_Absolute_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + symlinkFileInSymlinkDirAbs, err := filepath.Abs("test-fixtures/test-symlink-dir-with-symlink-file/test-symlink.txt") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "zip" + source_file = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash(symlinkFileInSymlinkDirAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-symlink.txt": []byte(`This is test content`), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_ZipArchiveFile_DirectoryWithSymlinkDirectory_Relative_ExcludeSymlinkDirectories verifies that an empty archive +// is generated when trying to archive a directory which only contains a symlink to a directory. +func TestResource_ZipArchiveFile_DirectoryWithSymlinkDirectory_Relative_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + exclude_symlink_directories = true + } + `, filepath.ToSlash("test-fixtures/test-dir-with-symlink-dir"), filepath.ToSlash(f)), + ExpectError: regexp.MustCompile(`.*error creating archive: error archiving directory: archive has not been\ncreated as it would be empty`), + }, + }, + }) +} + +// TestResource_ZipArchiveFile_IncludeDirectoryWithSymlinkDirectory_Absolute_ExcludeSymlinkDirectories verifies that an empty archive +// is generated when trying to archive a directory which only contains a symlink to a directory. +func TestResource_ZipArchiveFile_IncludeDirectoryWithSymlinkDirectory_Absolute_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + symlinkDirInRegularDirAbs, err := filepath.Abs("test-fixtures/test-dir-with-symlink-dir") + if err != nil { + t.Fatal(err) + } + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + exclude_symlink_directories = true + } + `, filepath.ToSlash(symlinkDirInRegularDirAbs), filepath.ToSlash(f)), + ExpectError: regexp.MustCompile(`.*error creating archive: error archiving directory: archive has not been\ncreated as it would be empty`), + }, + }, + }) +} + +// TestResource_ZipArchiveFile_Multiple_Relative_ExcludeSymlinkDirectories verifies that +// symlinked directories are excluded. +func TestResource_ZipArchiveFile_Multiple_Relative_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash("test-fixtures"), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-dir/test-dir1/file1.txt": []byte("This is file 1"), + "test-dir/test-dir1/file2.txt": []byte("This is file 2"), + "test-dir/test-dir1/file3.txt": []byte("This is file 3"), + "test-dir/test-dir2/file1.txt": []byte("This is file 1"), + "test-dir/test-dir2/file2.txt": []byte("This is file 2"), + "test-dir/test-dir2/file3.txt": []byte("This is file 3"), + "test-dir/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} + +// TestResource_ZipArchiveFile_Multiple_Relative_ExcludeSymlinkDirectories verifies that +// symlinked directories are excluded. +func TestResource_ZipArchiveFile_Multiple_Absolute_ExcludeSymlinkDirectories(t *testing.T) { + td := t.TempDir() + + f := filepath.Join(td, "zip_file_acc_test.zip") + + multipleDirsAndFilesAbs, err := filepath.Abs("test-fixtures") + if err != nil { + t.Fatal(err) + } + + var fileSize string + + r.ParallelTest(t, r.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []r.TestStep{ + { + Config: fmt.Sprintf(` + resource "archive_file" "foo" { + type = "zip" + source_dir = "%s" + output_path = "%s" + output_file_mode = "0666" + exclude_symlink_directories = true + } + `, filepath.ToSlash(multipleDirsAndFilesAbs), filepath.ToSlash(f)), + Check: r.ComposeTestCheckFunc( + testAccArchiveFileSize(f, &fileSize), + r.TestCheckResourceAttrPtr("archive_file.foo", "output_size", &fileSize), + r.TestCheckResourceAttrWith("archive_file.foo", "output_path", func(value string) error { + ensureContents(t, value, map[string][]byte{ + "test-dir/test-dir1/file1.txt": []byte("This is file 1"), + "test-dir/test-dir1/file2.txt": []byte("This is file 2"), + "test-dir/test-dir1/file3.txt": []byte("This is file 3"), + "test-dir/test-dir2/file1.txt": []byte("This is file 1"), + "test-dir/test-dir2/file2.txt": []byte("This is file 2"), + "test-dir/test-dir2/file3.txt": []byte("This is file 3"), + "test-dir/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), + }) + ensureFileMode(t, value, "0666") + return nil + }), + ), + }, + }, + }) +} diff --git a/internal/provider/tar_archiver.go b/internal/provider/tar_archiver.go new file mode 100644 index 00000000..14977d18 --- /dev/null +++ b/internal/provider/tar_archiver.go @@ -0,0 +1,316 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package archive + +import ( + "archive/tar" + "compress/gzip" + "errors" + "fmt" + "io" + "os" + "path/filepath" + "sort" + "strconv" + "time" +) + +type TarCompressionType int + +const ( + TarCompressionGz TarCompressionType = iota +) + +type TarArchiver struct { + compression TarCompressionType + filepath string + outputFileMode string // Default value "" means unset + fileWriter *os.File + tarWriter *tar.Writer + compressionWriter io.WriteCloser +} + +func NewTarGzArchiver(filepath string) Archiver { + return NewTarArchiver(filepath, TarCompressionGz) +} + +func NewTarArchiver(filepath string, compression TarCompressionType) Archiver { + return &TarArchiver{ + filepath: filepath, + compression: compression, + } +} + +func (a *TarArchiver) ArchiveContent(content []byte, infilename string) error { + if err := a.open(); err != nil { + return err + } + defer a.close() + + return a.addContent(content, &tar.Header{ + Name: infilename, + Size: int64(len(content)), + ModTime: time.Time{}, + }) +} + +func (a *TarArchiver) ArchiveFile(infilename string) error { + fi, err := assertValidFile(infilename) + if err != nil { + return err + } + + if err := a.open(); err != nil { + return err + } + defer a.close() + + header := &tar.Header{ + Name: filepath.ToSlash(fi.Name()), + Size: fi.Size(), + Mode: int64(fi.Mode()), + ModTime: time.Time{}, + } + + if err := a.addFile(infilename, header); err != nil { + return err + } + + return err +} + +func (a *TarArchiver) ArchiveDir(indirname string, opts ArchiveDirOpts) error { + err := assertValidDir(indirname) + if err != nil { + return err + } + + // ensure exclusions are OS compatible paths + for i := range opts.Excludes { + opts.Excludes[i] = filepath.FromSlash(opts.Excludes[i]) + } + + // Determine whether an empty archive would be generated. + isArchiveEmpty := true + + err = filepath.Walk(indirname, a.createWalkFunc("", indirname, opts, &isArchiveEmpty, true)) + if err != nil { + return err + } + + // Return an error if an empty archive would be generated. + if isArchiveEmpty { + return fmt.Errorf("archive has not been created as it would be empty") + } + + if err := a.open(); err != nil { + return err + } + defer a.close() + + return filepath.Walk(indirname, a.createWalkFunc("", indirname, opts, &isArchiveEmpty, false)) +} + +func (a *TarArchiver) createWalkFunc(basePath, indirname string, opts ArchiveDirOpts, isArchiveEmpty *bool, dryRun bool) func(path string, info os.FileInfo, err error) error { + return func(path string, info os.FileInfo, err error) error { + if err != nil { + return fmt.Errorf("error encountered during file walk: %s", err) + } + + relname, err := filepath.Rel(indirname, path) + if err != nil { + return fmt.Errorf("error relativizing file for archival: %s", err) + } + + archivePath := filepath.Join(basePath, relname) + + isMatch, err := checkMatch(archivePath, opts.Excludes) + if err != nil { + return fmt.Errorf("error checking excludes matches: %w", err) + } + + if info.IsDir() { + if isMatch { + return filepath.SkipDir + } + return nil + } + + if isMatch { + return nil + } + + if err != nil { + return err + } + + if info.Mode()&os.ModeSymlink == os.ModeSymlink { + realPath, err := filepath.EvalSymlinks(path) + if err != nil { + return err + } + + realInfo, err := os.Stat(realPath) + if err != nil { + return err + } + + if realInfo.IsDir() { + if !opts.ExcludeSymlinkDirectories { + return filepath.Walk(realPath, a.createWalkFunc(archivePath, realPath, opts, isArchiveEmpty, dryRun)) + } else { + return filepath.SkipDir + } + } + + info = realInfo + } + + *isArchiveEmpty = false + + if dryRun { + return nil + } + + header := &tar.Header{ + Name: filepath.ToSlash(archivePath), + Size: info.Size(), + Mode: int64(info.Mode()), + ModTime: time.Time{}, + } + + return a.addFile(path, header) + } +} + +func (a *TarArchiver) ArchiveMultiple(content map[string][]byte) error { + if err := a.open(); err != nil { + return err + } + defer a.close() + + // Ensure files are processed in the same order so hashes don't change + keys := make([]string, len(content)) + i := 0 + for k := range content { + keys[i] = k + i++ + } + sort.Strings(keys) + + for _, filename := range keys { + header := &tar.Header{ + Name: filepath.ToSlash(filename), + Size: int64(len(content[filename])), + ModTime: time.Time{}, + } + + if err := a.addContent(content[filename], header); err != nil { + return err + } + } + return nil +} + +func (a *TarArchiver) SetOutputFileMode(outputFileMode string) { + a.outputFileMode = outputFileMode +} + +func (a *TarArchiver) open() error { + var err error + + a.fileWriter, err = os.Create(filepath.ToSlash(a.filepath)) + if err != nil { + return err + } + + switch a.compression { + case TarCompressionGz: + a.compressionWriter = gzip.NewWriter(a.fileWriter) + } + + a.tarWriter = tar.NewWriter(a.compressionWriter) + return nil +} + +func (a *TarArchiver) close() { + if a.tarWriter != nil { + err := a.tarWriter.Close() + if err != nil { + fmt.Printf("error closing tarwriter : %s\n\n", err) + } + a.tarWriter = nil + } + if a.compressionWriter != nil { + err := a.compressionWriter.Close() + if err != nil { + fmt.Printf("error closing compressionWriter : %s\n\n", err) + } + a.compressionWriter = nil + } + if a.fileWriter != nil { + err := a.fileWriter.Close() + if err != nil { + fmt.Printf("error closing fileWriter: %s\n\n", err) + } + a.fileWriter = nil + } +} + +func (a *TarArchiver) addFile(filePath string, header *tar.Header) error { + if header == nil { + return fmt.Errorf("tar.Header is nil") + } + + file, err := os.Open(filePath) + if err != nil { + return fmt.Errorf("could not open file '%s', got error '%w'", filePath, err) + } + defer file.Close() + + if a.outputFileMode != "" { + fileMode, err := strconv.ParseInt(a.outputFileMode, 0, 32) + if err != nil { + return fmt.Errorf("error parsing output_file_mode value: %s", a.outputFileMode) + } + header.Mode = fileMode + } + + err = a.tarWriter.WriteHeader(header) + if err != nil { + return fmt.Errorf("could not write header for file '%s', got error '%w'", filePath, err) + } + + _, err = io.Copy(a.tarWriter, file) + if err != nil { + return fmt.Errorf("error reading file for archival: %s", err) + } + + return nil +} + +func (a *TarArchiver) addContent(content []byte, header *tar.Header) error { + if header == nil { + return errors.New("tar.Header is nil") + } + + if a.outputFileMode != "" { + filemode, err := strconv.ParseInt(a.outputFileMode, 0, 32) + if err != nil { + return fmt.Errorf("error parsing output_file_mode value: %s", a.outputFileMode) + } + header.Mode = filemode + } + + if err := a.tarWriter.WriteHeader(header); err != nil { + return fmt.Errorf("could not write header, got error '%w'", err) + } + + _, err := a.tarWriter.Write(content) + if err != nil { + return fmt.Errorf("could not copy data to the tarball, got error '%w'", err) + } + + return nil +} diff --git a/internal/provider/tar_archiver_test.go b/internal/provider/tar_archiver_test.go new file mode 100644 index 00000000..bc19dbcb --- /dev/null +++ b/internal/provider/tar_archiver_test.go @@ -0,0 +1,506 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package archive + +import ( + "archive/tar" + "bytes" + "compress/gzip" + "io" + "os" + "path/filepath" + "strconv" + "testing" + "time" + + "golang.org/x/exp/maps" + "golang.org/x/exp/slices" +) + +func TestTarArchiver_Content(t *testing.T) { + tarFilePath := filepath.Join(t.TempDir(), "archive-content.tar.gz") + + archiver := NewTarGzArchiver(tarFilePath) + if err := archiver.ArchiveContent([]byte("This is some content"), "content.txt"); err != nil { + t.Fatalf("unexpected error: %s", err) + } + + ensureTarContents(t, tarFilePath, map[string][]byte{ + "content.txt": []byte("This is some content"), + }) +} + +func TestTarArchiver_File(t *testing.T) { + tarFilePath := filepath.Join(t.TempDir(), "archive-file.tar.gz") + + archiver := NewTarGzArchiver(tarFilePath) + if err := archiver.ArchiveFile("./test-fixtures/test-dir/test-file.txt"); err != nil { + t.Fatalf("unexpected error: %s", err) + } + + ensureTarContents(t, tarFilePath, map[string][]byte{ + "test-file.txt": []byte("This is test content"), + }) +} + +func TestTarArchiver_FileMode(t *testing.T) { + file, err := os.CreateTemp("", "archive-file-mode-test.tar.gz") + if err != nil { + t.Fatal(err) + } + + var ( + tarFilePath = file.Name() + toTarPath = filepath.FromSlash("./test-fixtures/test-dir/test-file.txt") + ) + + stringArray := [5]string{"0444", "0644", "0666", "0744", "0777"} + for _, element := range stringArray { + archiver := NewTarGzArchiver(tarFilePath) + archiver.SetOutputFileMode(element) + if err := archiver.ArchiveFile(toTarPath); err != nil { + t.Fatalf("unexpected error: %s", err) + } + + ensureTarFileMode(t, tarFilePath, element) + } +} + +func TestTarArchiver_FileModified(t *testing.T) { + var ( + tarFilePath = filepath.Join(t.TempDir(), "archive-file-modified.tar.gz") + toTarPath = filepath.FromSlash("./test-fixtures/test-dir/test-file.txt") + ) + + var tarFunc = func() { + archiver := NewTarGzArchiver(tarFilePath) + if err := archiver.ArchiveFile(toTarPath); err != nil { + t.Fatalf("unexpected error: %s", err) + } + } + + tarFunc() + + expectedContents, err := os.ReadFile(tarFilePath) + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + // touch file modified, in the future just in case of weird race issues + newTime := time.Now().Add(1 * time.Hour) + if err := os.Chtimes(toTarPath, newTime, newTime); err != nil { + t.Fatalf("unexpected error: %s", err) + } + + tarFunc() + + actualContents, err := os.ReadFile(tarFilePath) + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + if !bytes.Equal(expectedContents, actualContents) { + t.Fatalf("tar contents do not match, potentially a modified time issue") + } +} + +func TestTarArchiver_Dir(t *testing.T) { + tarFilePath := filepath.Join(t.TempDir(), "archive-dir.tar.gz") + + archiver := NewTarGzArchiver(tarFilePath) + if err := archiver.ArchiveDir("./test-fixtures/test-dir/test-dir1", ArchiveDirOpts{}); err != nil { + t.Fatalf("unexpected error: %s", err) + } + + ensureTarContents(t, tarFilePath, map[string][]byte{ + "file1.txt": []byte("This is file 1"), + "file2.txt": []byte("This is file 2"), + "file3.txt": []byte("This is file 3"), + }) +} + +func TestTarArchiver_Dir_Exclude(t *testing.T) { + tarFilePath := filepath.Join(t.TempDir(), "archive-dir-exclude.tar.gz") + + archiver := NewTarGzArchiver(tarFilePath) + if err := archiver.ArchiveDir("./test-fixtures/test-dir/test-dir1", ArchiveDirOpts{ + Excludes: []string{"file2.txt"}, + }); err != nil { + t.Fatalf("unexpected error: %s", err) + } + + ensureTarContents(t, tarFilePath, map[string][]byte{ + "file1.txt": []byte("This is file 1"), + "file3.txt": []byte("This is file 3"), + }) +} + +func TestTarArchiver_Dir_Exclude_With_Directory(t *testing.T) { + tarFilePath := filepath.Join(t.TempDir(), "archive-dir-exclude-dir.tar.gz") + + archiver := NewTarGzArchiver(tarFilePath) + if err := archiver.ArchiveDir("./test-fixtures/test-dir", ArchiveDirOpts{ + Excludes: []string{"test-dir1", "test-dir2/file2.txt"}, + }); err != nil { + t.Fatalf("unexpected error: %s", err) + } + + ensureTarContents(t, tarFilePath, map[string][]byte{ + "test-dir2/file1.txt": []byte("This is file 1"), + "test-dir2/file3.txt": []byte("This is file 3"), + "test-file.txt": []byte("This is test content"), + }) +} + +func TestTarArchiver_Multiple(t *testing.T) { + tarFilePath := filepath.Join(t.TempDir(), "archive-content.tar.gz") + + content := map[string][]byte{ + "file1.txt": []byte("This is file 1"), + "file2.txt": []byte("This is file 2"), + "file3.txt": []byte("This is file 3"), + } + + archiver := NewTarGzArchiver(tarFilePath) + if err := archiver.ArchiveMultiple(content); err != nil { + t.Fatalf("unexpected error: %s", err) + } + + ensureTarContents(t, tarFilePath, content) +} + +func TestTarArchiver_Multiple_NoChange(t *testing.T) { + tarFilePath := filepath.Join(t.TempDir(), "archive-content.tar.gz") + + content := map[string][]byte{ + "file1.txt": []byte("This is file 1"), + "file2.txt": []byte("This is file 2"), + "file3.txt": []byte("This is file 3"), + } + + archiver := NewTarGzArchiver(tarFilePath) + if err := archiver.ArchiveMultiple(content); err != nil { + t.Fatalf("unexpected error: %s", err) + } + + expectedContents, err := os.ReadFile(tarFilePath) + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + time.Sleep(1 * time.Second) + + archiver = NewTarGzArchiver(tarFilePath) + if err := archiver.ArchiveMultiple(content); err != nil { + t.Fatalf("unexpected error: %s", err) + } + + actualContents, err := os.ReadFile(tarFilePath) + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + if !bytes.Equal(expectedContents, actualContents) { + t.Fatalf("tar contents do not match, potentially a modified time issue") + } +} + +func TestTarArchiver_Dir_With_Symlink_File(t *testing.T) { + tarFilePath := filepath.Join(t.TempDir(), "archive-dir-with-symlink-file.tar.gz") + + archiver := NewTarGzArchiver(tarFilePath) + if err := archiver.ArchiveDir("./test-fixtures/test-dir-with-symlink-file", ArchiveDirOpts{}); err != nil { + t.Fatalf("unexpected error: %s", err) + } + + ensureTarContents(t, tarFilePath, map[string][]byte{ + "test-file.txt": []byte("This is test content"), + "test-symlink.txt": []byte("This is test content"), + }) +} + +func TestTarArchiver_Dir_DoNotExcludeSymlinkDirectories(t *testing.T) { + tarFilePath := filepath.Join(t.TempDir(), "archive-dir-with-symlink-dir.tar.gz") + + archiver := NewTarGzArchiver(tarFilePath) + if err := archiver.ArchiveDir("./test-fixtures", ArchiveDirOpts{}); err != nil { + t.Fatalf("unexpected error: %s", err) + } + + ensureTarContents(t, tarFilePath, map[string][]byte{ + "test-dir/test-dir1/file1.txt": []byte("This is file 1"), + "test-dir/test-dir1/file2.txt": []byte("This is file 2"), + "test-dir/test-dir1/file3.txt": []byte("This is file 3"), + "test-dir/test-dir2/file1.txt": []byte("This is file 1"), + "test-dir/test-dir2/file2.txt": []byte("This is file 2"), + "test-dir/test-dir2/file3.txt": []byte("This is file 3"), + "test-dir/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-dir/test-symlink-dir/file1.txt": []byte("This is file 1"), + "test-dir-with-symlink-dir/test-symlink-dir/file2.txt": []byte("This is file 2"), + "test-dir-with-symlink-dir/test-symlink-dir/file3.txt": []byte("This is file 3"), + "test-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), + "test-symlink-dir/file1.txt": []byte("This is file 1"), + "test-symlink-dir/file2.txt": []byte("This is file 2"), + "test-symlink-dir/file3.txt": []byte("This is file 3"), + "test-symlink-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + "test-symlink-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), + }) +} + +func TestTarArchiver_Dir_ExcludeSymlinkDirectories(t *testing.T) { + tarFilePath := filepath.Join(t.TempDir(), "archive-dir-with-symlink-dir.tar.gz") + + archiver := NewTarGzArchiver(tarFilePath) + err := archiver.ArchiveDir("./test-fixtures", ArchiveDirOpts{ + ExcludeSymlinkDirectories: true, + }) + + if err != nil { + t.Errorf("expected no error: %s", err) + } + + ensureTarContents(t, tarFilePath, map[string][]byte{ + "test-dir/test-dir1/file1.txt": []byte("This is file 1"), + "test-dir/test-dir1/file2.txt": []byte("This is file 2"), + "test-dir/test-dir1/file3.txt": []byte("This is file 3"), + "test-dir/test-dir2/file1.txt": []byte("This is file 1"), + "test-dir/test-dir2/file2.txt": []byte("This is file 2"), + "test-dir/test-dir2/file3.txt": []byte("This is file 3"), + "test-dir/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), + }) +} + +func TestTarArchiver_Dir_Exclude_DoNotExcludeSymlinkDirectories(t *testing.T) { + tarFilePath := filepath.Join(t.TempDir(), "archive-dir-with-symlink-dir.tar.gz") + + archiver := NewTarGzArchiver(tarFilePath) + if err := archiver.ArchiveDir("./test-fixtures", ArchiveDirOpts{ + Excludes: []string{ + "test-symlink-dir/file1.txt", + "test-symlink-dir-with-symlink-file/test-symlink.txt", + }, + }); err != nil { + t.Fatalf("unexpected error: %s", err) + } + + ensureTarContents(t, tarFilePath, map[string][]byte{ + "test-dir/test-dir1/file1.txt": []byte("This is file 1"), + "test-dir/test-dir1/file2.txt": []byte("This is file 2"), + "test-dir/test-dir1/file3.txt": []byte("This is file 3"), + "test-dir/test-dir2/file1.txt": []byte("This is file 1"), + "test-dir/test-dir2/file2.txt": []byte("This is file 2"), + "test-dir/test-dir2/file3.txt": []byte("This is file 3"), + "test-dir/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-dir/test-symlink-dir/file1.txt": []byte("This is file 1"), + "test-dir-with-symlink-dir/test-symlink-dir/file2.txt": []byte("This is file 2"), + "test-dir-with-symlink-dir/test-symlink-dir/file3.txt": []byte("This is file 3"), + "test-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), + "test-symlink-dir/file2.txt": []byte("This is file 2"), + "test-symlink-dir/file3.txt": []byte("This is file 3"), + "test-symlink-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + }) +} + +func TestTarArchiver_Dir_Exclude_Glob_DoNotExcludeSymlinkDirectories(t *testing.T) { + tarFilePath := filepath.Join(t.TempDir(), "archive-dir-with-symlink-dir.tar") + + archiver := NewTarGzArchiver(tarFilePath) + if err := archiver.ArchiveDir("./test-fixtures", ArchiveDirOpts{ + Excludes: []string{ + "**/file1.txt", + "**/file2.*", + "test-dir-with-symlink-dir/test-symlink-dir", + "test-symlink-dir-with-symlink-file/test-symlink.txt", + }, + }); err != nil { + t.Fatalf("unexpected error: %s", err) + } + + ensureTarContents(t, tarFilePath, map[string][]byte{ + "test-dir/test-dir1/file3.txt": []byte("This is file 3"), + "test-dir/test-dir2/file3.txt": []byte("This is file 3"), + "test-dir/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), + "test-symlink-dir/file3.txt": []byte("This is file 3"), + "test-symlink-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + }) +} + +func TestTarArchiver_Dir_Exclude_ExcludeSymlinkDirectories(t *testing.T) { + tarFilePath := filepath.Join(t.TempDir(), "archive-dir-with-symlink-dir.tar.gz") + + archiver := NewTarGzArchiver(tarFilePath) + err := archiver.ArchiveDir("./test-fixtures", ArchiveDirOpts{ + Excludes: []string{ + "test-dir/test-dir1/file1.txt", + "test-symlink-dir-with-symlink-file/test-symlink.txt", + }, + ExcludeSymlinkDirectories: true, + }) + + if err != nil { + t.Errorf("expected no error: %s", err) + } + + ensureTarContents(t, tarFilePath, map[string][]byte{ + "test-dir/test-dir1/file2.txt": []byte("This is file 2"), + "test-dir/test-dir1/file3.txt": []byte("This is file 3"), + "test-dir/test-dir2/file1.txt": []byte("This is file 1"), + "test-dir/test-dir2/file2.txt": []byte("This is file 2"), + "test-dir/test-dir2/file3.txt": []byte("This is file 3"), + "test-dir/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-file.txt": []byte("This is test content"), + "test-dir-with-symlink-file/test-symlink.txt": []byte("This is test content"), + }) +} + +func TestTarArchiver_Dir_Exclude_Glob_ExcludeSymlinkDirectories(t *testing.T) { + tarFilePath := filepath.Join(t.TempDir(), "archive-dir-with-symlink-dir.zip") + + archiver := NewTarGzArchiver(tarFilePath) + err := archiver.ArchiveDir("./test-fixtures", ArchiveDirOpts{ + Excludes: []string{ + "test-dir/test-dir1/file1.txt", + "**/file[2-3].txt", + "test-dir-with-symlink-file", + }, + ExcludeSymlinkDirectories: true, + }) + + if err != nil { + t.Errorf("expected no error: %s", err) + } + + ensureTarContents(t, tarFilePath, map[string][]byte{ + "test-dir/test-dir2/file1.txt": []byte("This is file 1"), + "test-dir/test-file.txt": []byte("This is test content"), + }) +} + +func ensureTarContents(t *testing.T, tarFilePath string, wants map[string][]byte) { + t.Helper() + + f, err := os.Open(tarFilePath) + if err != nil { + t.Fatalf("could not open tar.gz file: %s", err) + } + defer f.Close() + + gzf, err := gzip.NewReader(f) + if err != nil { + t.Fatalf("could not open tar.gz file: %s", err) + } + defer gzf.Close() + + tarReader := tar.NewReader(gzf) + + tarFileNames := make([]string, 0, len(wants)) + + for { + header, err := tarReader.Next() + + if err == io.EOF { + break + } + + if err != nil { + t.Fatal(err) + } + + name := header.Name + tarFileNames = append(tarFileNames, name) + + switch header.Typeflag { + case tar.TypeDir: + continue + case tar.TypeReg: + buf := bytes.Buffer{} + _, err = io.Copy(&buf, tarReader) + if err != nil { + t.Fatalf("could not read file %s in tar: %s", name, err) + } + + wantFile, ok := wants[name] + if !ok { + t.Fatalf("missing file %s in tar", name) + } + + wantContent := string(wantFile) + gotContent := buf.String() + if gotContent != wantContent { + t.Errorf("mismatched content\ngot\n%s\nwant\n%s", gotContent, wantContent) + } + default: + t.Fatalf("Unable to figure out type: %c in file: %s\n", + header.Typeflag, + name, + ) + } + } + + wantFileNames := maps.Keys(wants) + slices.Sort(wantFileNames) + slices.Sort(tarFileNames) + + if len(wants) != len(tarFileNames) { + t.Fatalf("unexpect file count in tar\ngot\n%s\nwant\n%s", tarFileNames, wantFileNames) + } +} + +func ensureTarFileMode(t *testing.T, tarfilepath string, outputFileMode string) { + t.Helper() + + f, err := os.Open(tarfilepath) + if err != nil { + t.Fatalf("could not open tar.gz file: %s", err) + } + defer f.Close() + + gzf, err := gzip.NewReader(f) + if err != nil { + t.Fatalf("could not open tar.gz file: %s", err) + } + + tarReader := tar.NewReader(gzf) + + filemode, err := strconv.ParseUint(outputFileMode, 0, 32) + if err != nil { + t.Fatalf("error parsing outputFileMode value: %s", outputFileMode) + } + + var osfilemode = os.FileMode(filemode) + + for { + header, err := tarReader.Next() + + if err == io.EOF { + break + } + + if err != nil { + t.Fatal(err) + } + + name := header.Name + + switch header.Typeflag { + case tar.TypeDir: + continue + case tar.TypeReg: + if header.FileInfo().Mode() != osfilemode { + t.Fatalf("Expected filemode \"%s\" but was \"%s\"", osfilemode, header.FileInfo().Mode()) + } + default: + t.Fatalf("Unable to figure out type: %c in file: %s\n", + header.Typeflag, + name, + ) + } + } +} diff --git a/internal/provider/zip_archiver.go b/internal/provider/zip_archiver.go index 303fa465..014cec10 100644 --- a/internal/provider/zip_archiver.go +++ b/internal/provider/zip_archiver.go @@ -104,7 +104,7 @@ func checkMatch(fileName string, excludes []string) (value bool, err error) { } func (a *ZipArchiver) ArchiveDir(indirname string, opts ArchiveDirOpts) error { - _, err := assertValidDir(indirname) + err := assertValidDir(indirname) if err != nil { return err }