Skip to content

Commit

Permalink
Add initial draft test for DownloadProductFromURL using mocked server…
Browse files Browse the repository at this point in the history
… and data

Issue #315
  • Loading branch information
MatthewJohn committed May 29, 2024
1 parent d22a046 commit c25d831
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 6 deletions.
124 changes: 123 additions & 1 deletion lib/download_test.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
package lib

import (
"archive/zip"
"bytes"
"crypto"
"crypto/sha256"
"encoding/hex"
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"os"
"path/filepath"
"runtime"
"strings"
"sync"
"testing"

"github.com/mitchellh/go-homedir"
"golang.org/x/crypto/openpgp"
"golang.org/x/crypto/openpgp/armor"
"golang.org/x/crypto/openpgp/packet"
)

// TestDownloadFromURL_FileNameMatch : Check expected filename exist when downloaded
Expand Down Expand Up @@ -79,7 +90,7 @@ func TestDownloadFromURL_FileNameMatch(t *testing.T) {
})
}

// // TestDownloadFromURL_Valid : Test if https://releases.hashicorp.com/terraform/ is still valid
// TestDownloadFromURL_Valid : Test if https://releases.hashicorp.com/terraform/ is still valid
func TestDownloadFromURL_Valid(t *testing.T) {

hashiURL := "https://releases.hashicorp.com/terraform/"
Expand All @@ -91,3 +102,114 @@ func TestDownloadFromURL_Valid(t *testing.T) {
t.Logf("Valid URL from %v [expected]", url)
}
}

// TestDownloadProductFromURL : Test DownloadProductFromURL
func TestDownloadProductFromURL(t *testing.T) {

openpgpConfig := packet.Config{
RSABits: 1024,
DefaultHash: crypto.SHA256,
DefaultCipher: packet.CipherAES256,
DefaultCompressionAlgo: packet.CompressionZLIB,
}
gpgKeyEntity, err := openpgp.NewEntity("TestProductSign", "Signing key for test product", "example@localhost.com", &openpgpConfig)
if err != nil {
fmt.Println(err)
return
}
gpgFingerprint := hex.EncodeToString(gpgKeyEntity.PrimaryKey.Fingerprint[:])[:8]

zipFileBuffer := new(bytes.Buffer)
zipWriter := zip.NewWriter(zipFileBuffer)

mainExecutableBytes := []byte("This is the main executable")
zipFileContentWriter, err := zipWriter.Create("myprod")
if err != nil {
t.Fatal(err)
}
zipFileContentWriter.Write(mainExecutableBytes)
zipWriter.Flush()
zipWriter.Close()

var publicKeySerialiseBuffer bytes.Buffer
err = gpgKeyEntity.Serialize(&publicKeySerialiseBuffer)
if err != nil {
t.Fatal(err)
}
var publicKey bytes.Buffer
publicKeyWriter, err := armor.Encode(&publicKey, openpgp.PublicKeyType, nil)
if err != nil {
t.Fatal(err)
}
publicKeyWriter.Close()

zipFileBytes := zipFileBuffer.Bytes()

// Calculate SHA256 sum of ZIP file
sha256HashWriter := sha256.New()
sha256Hash := sha256HashWriter.Sum(zipFileBytes)

// Create checksum file
checksumFileContent := string(sha256Hash) + " " + "my_product_download_2.1.0_linux_amd64.zip"
checksumFileReader := bytes.NewBuffer([]byte(checksumFileContent))

// Create signature of checksum file
var sigFile bytes.Buffer
err = openpgp.DetachSign(&sigFile, gpgKeyEntity, checksumFileReader, &openpgpConfig)
if err != nil {
t.Fatal(err)
}

// Create mock server
mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch strings.TrimSpace(r.URL.Path) {
case "/testproduct/gpg-key.txt":
w.Header().Set("Content-Type", "text/html")
w.WriteHeader(http.StatusOK)
w.Write(publicKey.Bytes())
case "/productdownload/2.1.0/my_product_download_2.1.0_linux_amd64.zip":
w.Header().Set("Content-Type", "application/zip")
w.WriteHeader(http.StatusOK)
w.Write(zipFileBytes)
case "/productdownload/2.1.0/my_product_download_2.1.0_SHA256SUMS":
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
w.Write([]byte(checksumFileContent))
case "/productdownload/2.1.0/my_product_download_2.1.0_SHA256SUMS." + gpgFingerprint + ".sig":
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
w.Write(sigFile.Bytes())
default:
http.NotFoundHandler().ServeHTTP(w, r)
}
}))

// Create mock product
mockProduct := TerraformProduct{
ProductDetails{
ID: "myproduct",
Name: "Mock Product",
DefaultMirror: mockServer.URL + "/productdownload",
VersionPrefix: "myprod_",
ExecutableName: "myprod",
ArchivePrefix: "my_product_download_",
PublicKeyId: gpgFingerprint,
PublicKeyUrl: mockServer.URL + "/testproduct/gpg-key.txt",
},
}

// Create temp location
tempDir, err := os.MkdirTemp("", "addRecentVersion")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tempDir)

zipFilePath, err := DownloadProductFromURL(mockProduct, tempDir, mockProduct.GetArtifactUrl(mockServer.URL+"/productdownload", "2.1.0"), "2.1.0", mockProduct.GetArchivePrefix(), "linux", "amd64")
if err != nil {
t.Fatal(err)
}
if expectedZipPath := ""; zipFilePath != expectedZipPath {
t.Errorf("Returned zipFile not expected path. Expected: %q, actual: %q", expectedZipPath, zipFilePath)
}
}
8 changes: 4 additions & 4 deletions lib/list_versions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func compareLists(actual []string, expected []string) error {
return nil
}

func getMockServer() *httptest.Server {
func getMockListVersionServer() *httptest.Server {
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch strings.TrimSpace(r.URL.Path) {
case "/hashicorp/":
Expand Down Expand Up @@ -144,7 +144,7 @@ func TestGetVersionsFromBodyOpenTofu(t *testing.T) {

// TestGetTFLatest : Test getTFLatest
func TestGetTFLatest(t *testing.T) {
server := getMockServer()
server := getMockListVersionServer()
defer server.Close()

version, err := getTFLatest(fmt.Sprintf("%s/%s", server.URL, "hashicorp"))
Expand All @@ -167,7 +167,7 @@ func TestGetTFLatestImplicit(t *testing.T) {
}

func testGetTFLatestImplicit(t *testing.T, version string, preRelease bool, expectedVersion string) {
server := getMockServer()
server := getMockListVersionServer()
defer server.Close()

version, err := getTFLatestImplicit(fmt.Sprintf("%s/%s", server.URL, "hashicorp"), preRelease, version)
Expand All @@ -181,7 +181,7 @@ func testGetTFLatestImplicit(t *testing.T, version string, preRelease bool, expe

// TestGetTFURLBody : Test getTFURLBody method
func TestGetTFURLBody(t *testing.T) {
server := getMockServer()
server := getMockListVersionServer()
defer server.Close()

body, err := getTFURLBody(fmt.Sprintf("%s/%s", server.URL, "hashicorp"))
Expand Down
2 changes: 1 addition & 1 deletion lib/products.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func (p TerraformProduct) GetArchivePrefix() string {
return p.ArchivePrefix
}
func (p TerraformProduct) GetArtifactUrl(mirrorURL string, version string) string {
return fmt.Sprintf("%s%s", mirrorURL, version)
return fmt.Sprintf("%s/%s", mirrorURL, version)
}
func (p TerraformProduct) GetPublicKeyId() string {
return p.PublicKeyId
Expand Down

0 comments on commit c25d831

Please sign in to comment.