From cd15bcb057e52efcb52704402082d86c300a2cf1 Mon Sep 17 00:00:00 2001 From: Bartosz Blizniak Date: Fri, 24 Nov 2023 13:02:00 +0000 Subject: [PATCH] Feedback improvements to main and test file --- cloudsmith/data_source_package.go | 110 +++++++++++++++++++++---- cloudsmith/data_source_package_test.go | 72 +++++++++++++++- 2 files changed, 162 insertions(+), 20 deletions(-) diff --git a/cloudsmith/data_source_package.go b/cloudsmith/data_source_package.go index 91d997d..e3c76ab 100644 --- a/cloudsmith/data_source_package.go +++ b/cloudsmith/data_source_package.go @@ -9,13 +9,23 @@ import ( "fmt" "io" "net/http" + "net/url" "os" "path" + "strconv" + "time" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) +type Checksums struct { + MD5 string + SHA1 string + SHA256 string + SHA512 string +} + func dataSourcePackageRead(d *schema.ResourceData, m interface{}) error { pc := m.(*providerConfig) namespace := requiredString(d, "namespace") @@ -50,7 +60,7 @@ func dataSourcePackageRead(d *schema.ResourceData, m interface{}) error { d.SetId(fmt.Sprintf("%s_%s_%s", namespace, repository, pkg.GetSlugPerm())) if download { - outputPath, err := downloadPackage(pkg.GetCdnUrl(), downloadDir, pc) + outputPath, err := downloadPackage(pkg.GetCdnUrl(), downloadDir, pc, false) if err != nil { return err } @@ -58,15 +68,63 @@ func dataSourcePackageRead(d *schema.ResourceData, m interface{}) error { d.Set("output_directory", downloadDir) // Calculate checksums for the downloaded file - md5Checksum, sha1Checksum, sha256Checksum, sha512Checksum, err := calculateChecksums(outputPath) + localChecksums, err := calculateChecksums(outputPath) if err != nil { return err } - d.Set("checksum_md5", md5Checksum) - d.Set("checksum_sha1", sha1Checksum) - d.Set("checksum_sha256", sha256Checksum) - d.Set("checksum_sha512", sha512Checksum) + localMD5 := localChecksums.MD5 + localSHA1 := localChecksums.SHA1 + localSHA256 := localChecksums.SHA256 + localSHA512 := localChecksums.SHA512 + + // Check against API checksums + if localMD5 != pkg.GetChecksumMd5() || localSHA1 != pkg.GetChecksumSha1() || localSHA256 != pkg.GetChecksumSha256() || localSHA512 != pkg.GetChecksumSha512() { + // Checksum doesn't match, try to download again with isCached set to true + outputPath, err := downloadPackage(pkg.GetCdnUrl(), downloadDir, pc, true) + if err != nil { + return err + } + + // Calculate checksums for the downloaded file again + localChecksums, err := calculateChecksums(outputPath) + if err != nil { + return err + } + + localMD5 = localChecksums.MD5 + localSHA1 = localChecksums.SHA1 + localSHA256 = localChecksums.SHA256 + localSHA512 = localChecksums.SHA512 + + // Check again after the retry + if localMD5 != pkg.GetChecksumMd5() || localSHA1 != pkg.GetChecksumSha1() || localSHA256 != pkg.GetChecksumSha256() || localSHA512 != pkg.GetChecksumSha512() { + // Checksum still doesn't match, set the flag, and provide a warning + d.Set("download_checksum_mismatch", true) + + // Set the content for each checksum to "Checksum mismatch: Local File: , Remote File: " + mismatchMessageMD5 := fmt.Sprintf("Checksum mismatch: Local File: %s, Remote File: %s", localMD5, pkg.GetChecksumMd5()) + d.Set("checksum_md5", mismatchMessageMD5) + fmt.Println("Warning:", mismatchMessageMD5) + + mismatchMessageSHA1 := fmt.Sprintf("Checksum mismatch: Local File: %s, Remote File: %s", localSHA1, pkg.GetChecksumSha1()) + d.Set("checksum_sha1", mismatchMessageSHA1) + fmt.Println("Warning:", mismatchMessageSHA1) + + mismatchMessageSHA256 := fmt.Sprintf("Checksum mismatch: Local File: %s, Remote File: %s", localSHA256, pkg.GetChecksumSha256()) + d.Set("checksum_sha256", mismatchMessageSHA256) + fmt.Println("Warning:", mismatchMessageSHA256) + + mismatchMessageSHA512 := fmt.Sprintf("Checksum mismatch: Local File: %s, Remote File: %s", localSHA512, pkg.GetChecksumSha512()) + d.Set("checksum_sha512", mismatchMessageSHA512) + fmt.Println("Warning:", mismatchMessageSHA512) + } + } + + d.Set("checksum_md5", localMD5) + d.Set("checksum_sha1", localSHA1) + d.Set("checksum_sha256", localSHA256) + d.Set("checksum_sha512", localSHA512) } else { d.Set("output_path", pkg.GetCdnUrl()) d.Set("output_directory", "") @@ -75,8 +133,8 @@ func dataSourcePackageRead(d *schema.ResourceData, m interface{}) error { return nil } -func downloadPackage(url string, downloadDir string, pc *providerConfig) (string, error) { - req, err := http.NewRequest(http.MethodGet, url, nil) +func downloadPackage(urlStr string, downloadDir string, pc *providerConfig, isCached bool) (string, error) { + req, err := http.NewRequest(http.MethodGet, urlStr, nil) if err != nil { return "", err } @@ -84,6 +142,20 @@ func downloadPackage(url string, downloadDir string, pc *providerConfig) (string req.Header.Add("Authorization", fmt.Sprintf("Token %s", pc.GetAPIKey())) client := pc.APIClient.GetConfig().HTTPClient + if isCached { + timestamp := time.Now().Unix() + parsedURL, err := url.Parse(urlStr) + if err != nil { + return "", err + } + + queryValues := parsedURL.Query() + queryValues.Set("time", strconv.FormatInt(timestamp, 10)) + parsedURL.RawQuery = queryValues.Encode() + + req.URL = parsedURL + } + resp, err := client.Do(req) if err != nil { return "", err @@ -91,11 +163,11 @@ func downloadPackage(url string, downloadDir string, pc *providerConfig) (string defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return "", fmt.Errorf("failed to download file: %s, status code: %d", url, resp.StatusCode) + return "", fmt.Errorf("failed to download file: %s, status code: %d", urlStr, resp.StatusCode) } // Extract filename from CDN URL - filename := path.Base(url) + filename := path.Base(urlStr) outputPath := path.Join(downloadDir, filename) outputFile, err := os.Create(outputPath) @@ -112,10 +184,12 @@ func downloadPackage(url string, downloadDir string, pc *providerConfig) (string return outputPath, nil } -func calculateChecksums(filePath string) (string, string, string, string, error) { +func calculateChecksums(filePath string) (Checksums, error) { + var checksums Checksums + file, err := os.Open(filePath) if err != nil { - return "", "", "", "", err + return checksums, err } defer file.Close() @@ -125,15 +199,15 @@ func calculateChecksums(filePath string) (string, string, string, string, error) sha512hash := sha512.New() if _, err := io.Copy(io.MultiWriter(md5hash, sha1hash, sha256hash, sha512hash), file); err != nil { - return "", "", "", "", err + return checksums, err } - md5Checksum := hex.EncodeToString(md5hash.Sum(nil)) - sha1Checksum := hex.EncodeToString(sha1hash.Sum(nil)) - sha256Checksum := hex.EncodeToString(sha256hash.Sum(nil)) - sha512Checksum := hex.EncodeToString(sha512hash.Sum(nil)) + checksums.MD5 = hex.EncodeToString(md5hash.Sum(nil)) + checksums.SHA1 = hex.EncodeToString(sha1hash.Sum(nil)) + checksums.SHA256 = hex.EncodeToString(sha256hash.Sum(nil)) + checksums.SHA512 = hex.EncodeToString(sha512hash.Sum(nil)) - return md5Checksum, sha1Checksum, sha256Checksum, sha512Checksum, nil + return checksums, nil } func dataSourcePackage() *schema.Resource { diff --git a/cloudsmith/data_source_package_test.go b/cloudsmith/data_source_package_test.go index 5125bfd..149bea6 100644 --- a/cloudsmith/data_source_package_test.go +++ b/cloudsmith/data_source_package_test.go @@ -36,7 +36,7 @@ func TestAccPackage_data(t *testing.T) { resource.TestCheckResourceAttr("cloudsmith_repository.test", "name", dsPackageTestRepository), // Custom TestCheckFunc to upload the package and wait for sync after repository creation func(s *terraform.State) error { - return uploadPackage(testAccProvider.Meta().(*providerConfig)) + return uploadPackage(testAccProvider.Meta().(*providerConfig), false) }, ), }, @@ -58,6 +58,33 @@ func TestAccPackage_data(t *testing.T) { if _, err := os.Stat(filePath); os.IsNotExist(err) { return fmt.Errorf("file does not exist at path: %s", filePath) } + expectedContent := "Hello world" + if err := checkFileContent(filePath, expectedContent); err != nil { + return fmt.Errorf("file content check failed: %w", err) + } + return nil + }, + ), + }, + { + Config: testAccPackageDataReadPackageDownloadRepublish(dsPackageTestNamespace, dsPackageTestRepository), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.cloudsmith_package.test", "namespace", dsPackageTestNamespace), + resource.TestCheckResourceAttr("data.cloudsmith_package.test", "repository", dsPackageTestRepository), + func(s *terraform.State) error { + return uploadPackage(testAccProvider.Meta().(*providerConfig), true) + }, + func(s *terraform.State) error { + filePath := filepath.Join("/Users/bblizniak/Desktop/terrafor_test/2", "hello.txt") + if _, err := os.Stat(filePath); os.IsNotExist(err) { + return fmt.Errorf("file does not exist at path: %s", filePath) + } + + expectedContent := "Hello world updated content" + if err := checkFileContent(filePath, expectedContent); err != nil { + return fmt.Errorf("file content check failed: %w", err) + } + return nil }, ), @@ -65,9 +92,25 @@ func TestAccPackage_data(t *testing.T) { }, }) } +func checkFileContent(filePath string, expectedContent string) error { + content, err := os.ReadFile(filePath) + if err != nil { + return fmt.Errorf("failed to read file: %w", err) + } -func uploadPackage(pc *providerConfig) error { + if string(content) != expectedContent { + return fmt.Errorf("file content does not match expected. Got: %s, Expected: %s", content, expectedContent) + } + + return nil +} + +func uploadPackage(pc *providerConfig, republish bool) error { fileContent := []byte("Hello world") + if republish { + updatedContent := []byte(" updated content") + fileContent = append(fileContent, updatedContent...) + } initPayload := cloudsmith.PackageFileUploadRequest{ Filename: "hello.txt", @@ -154,6 +197,7 @@ func testAccPackageDataSetup(namespace, repository string) string { resource "cloudsmith_repository" "test" { name = "%s" namespace = "%s" + replace_packages_by_default = true } `, repository, namespace) } @@ -163,6 +207,7 @@ func testAccPackageDataReadPackage(namespace, repository string) string { resource "cloudsmith_repository" "test" { name = "%s" namespace = "%s" + replace_packages_by_default = true } data "cloudsmith_package_list" "test" { @@ -183,6 +228,29 @@ func testAccPackageDataReadPackageDownload(namespace, repository string) string resource "cloudsmith_repository" "test" { name = "%s" namespace = "%s" + replace_packages_by_default = true + } + + data "cloudsmith_package_list" "test" { + repository = "%s" + namespace = "%s" + } + + data "cloudsmith_package" "test" { + repository = "%s" + namespace = "%s" + identifier = data.cloudsmith_package_list.test.packages[0].slug_perm + download = true + } + `, repository, namespace, repository, namespace, repository, namespace) +} + +func testAccPackageDataReadPackageDownloadRepublish(namespace, repository string) string { + return fmt.Sprintf(` + resource "cloudsmith_repository" "test" { + name = "%s" + namespace = "%s" + replace_packages_by_default = true } data "cloudsmith_package_list" "test" {