Skip to content

Commit

Permalink
Implemented Artifactory upload, download and delete handling
Browse files Browse the repository at this point in the history
- Added GRABIT_ARTIFACTORY_TOKEN support
- Implemented cache download priority
- Added fallback to source URL
- Added validation at each step
- Improved error handling and logging
- Integrated cache upload functionality

Co-authored-by: Amin Assaid <[email protected]>
Co-authored-by: Amy Druham <[email protected]>
  • Loading branch information
eeasaa01 and Amy Druham committed Dec 7, 2024
1 parent 0575bde commit c760fe1
Show file tree
Hide file tree
Showing 8 changed files with 367 additions and 24 deletions.
18 changes: 17 additions & 1 deletion cmd/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
package cmd

import (
"fmt"
"os"

"github.com/cisco-open/grabit/internal"
"github.com/spf13/cobra"
)
Expand All @@ -18,6 +21,7 @@ func addAdd(cmd *cobra.Command) {
addCmd.Flags().String("algo", internal.RecommendedAlgo, "Integrity algorithm")
addCmd.Flags().String("filename", "", "Target file name to use when downloading the resource")
addCmd.Flags().StringArray("tag", []string{}, "Resource tags")
addCmd.Flags().String("cache", "", "Artifactory cache URL")
cmd.AddCommand(addCmd)
}

Expand All @@ -26,6 +30,18 @@ func runAdd(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
// Get cache URL
cacheURL, err := cmd.Flags().GetString("cache")
if err != nil {
return err
}
// Check token if cache is requested
if cacheURL != "" {
token := os.Getenv("GRABIT_ARTIFACTORY_TOKEN")
if token == "" {
return fmt.Errorf("GRABIT_ARTIFACTORY_TOKEN environment variable is not set")
}
}
lock, err := internal.NewLock(lockFile, true)
if err != nil {
return err
Expand All @@ -42,7 +58,7 @@ func runAdd(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
err = lock.AddResource(args, algo, tags, filename)
err = lock.AddResource(args, algo, tags, filename, cacheURL)
if err != nil {
return err
}
Expand Down
27 changes: 26 additions & 1 deletion cmd/add_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import (
)

func TestRunAdd(t *testing.T) {
// Set the GRABIT_ARTIFACTORY_TOKEN environment variable.
t.Setenv("GRABIT_ARTIFACTORY_TOKEN", "test-token")

// Setup HTTP handler for the resource
handler := func(w http.ResponseWriter, r *http.Request) {
_, err := w.Write([]byte(`abcdef`))
if err != nil {
Expand All @@ -18,8 +22,29 @@ func TestRunAdd(t *testing.T) {
}
port, server := test.HttpHandler(handler)
defer server.Close()

// Setup dummy cache server
cacheHandler := func(w http.ResponseWriter, r *http.Request) {
if r.Method == "PUT" {
w.WriteHeader(http.StatusCreated)
}
}
cachePort, cacheServer := test.HttpHandler(cacheHandler)
defer cacheServer.Close()

// Create empty lockfile
lockFile := test.TmpFile(t, "")

cmd := NewRootCmd()
cmd.SetArgs([]string{"-f", test.TmpFile(t, ""), "add", fmt.Sprintf("http://localhost:%d/test.html", port)})
// Add cache URL to the command
cacheURL := fmt.Sprintf("http://localhost:%d", cachePort)
cmd.SetArgs([]string{
"-f", lockFile,
"add",
fmt.Sprintf("http://localhost:%d/test.html", port),
"--cache", cacheURL,
})

err := cmd.Execute()
assert.Nil(t, err)
}
1 change: 1 addition & 0 deletions cmd/delete_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ func TestRunDelete(t *testing.T) {
Tags = ['tag1', 'tag2']
`)
cmd := NewRootCmd()
cmd.Flags().String("cache", "", "Artifactory URL for caching")
cmd.SetArgs([]string{"-f", testfilepath, "delete", "http://localhost:123456/test.html"})
err := cmd.Execute()
assert.Nil(t, err)
Expand Down
139 changes: 139 additions & 0 deletions internal/artifactory_cache_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package internal

import (
"crypto/sha256"
"encoding/base64"
"fmt"
"net/http"
"testing"

"github.com/cisco-open/grabit/test"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

// TestAddWithArtifactoryCache verifies adding a resource with caching enabled.
func TestAddWithArtifactoryCache(t *testing.T) {
// Sub-test to verify behavior when the token is not set.
t.Run("TokenNotSet", func(t *testing.T) {
// Clear the GRABIT_ARTIFACTORY_TOKEN environment variable.
t.Setenv("GRABIT_ARTIFACTORY_TOKEN", "")

// Setup a simple HTTP handler that always returns "test content".
handler := func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`test content`))
}
// Start the HTTP server and get the port it runs on.
port, server := test.HttpHandler(handler)
defer server.Close() // Ensure the server is stopped after the test.

// Create a temporary lock file for testing.
path := test.TmpFile(t, "")
lock, err := NewLock(path, true)
require.NoError(t, err) // Fail the test if the lock cannot be created.

// Set up URLs for the source file and cache.
sourceURL := fmt.Sprintf("http://localhost:%d/test.txt", port)
cacheURL := fmt.Sprintf("http://localhost:%d", port)

// Attempt to add a resource to the lock file.
err = lock.AddResource([]string{sourceURL}, "sha256", []string{}, "", cacheURL)
// Verify that the error message indicates the token is not set.
assert.Contains(t, err.Error(), "GRABIT_ARTIFACTORY_TOKEN environment variable is not set")
})
}

// TestDownloadWithArtifactoryCache verifies downloading resources with caching enabled.
func TestDownloadWithArtifactoryCache(t *testing.T) {
// Sub-test to verify behavior when NO_CACHE_UPLOAD is set.
t.Run("NO_CACHE_UPLOAD", func(t *testing.T) {
// Set the NO_CACHE_UPLOAD environment variable.
t.Setenv("NO_CACHE_UPLOAD", "1")

// Prepare the content and calculate its hash.
testContent := []byte("test content")
hash := sha256.Sum256(testContent)
expectedHash := "sha256-" + base64.StdEncoding.EncodeToString(hash[:])

// Track if an upload is attempted.
uploadAttempted := false
// Setup an HTTP handler to serve the content and log upload attempts.
handler := func(w http.ResponseWriter, r *http.Request) {
if r.Method == "PUT" { // Check for upload attempts.
uploadAttempted = true
t.Error("Should not attempt upload when NO_CACHE_UPLOAD is set")
}
w.Write(testContent)
}
// Start the HTTP server and get the port it runs on.
port, server := test.HttpHandler(handler)
defer server.Close() // Ensure the server is stopped after the test.

// Create a lock file with the resource and cache information.
lockContent := fmt.Sprintf(`[[Resource]]
Urls = ['http://localhost:%d/test.txt']
Integrity = '%s'
CacheUri = 'http://localhost:%d/cache'`, port, expectedHash, port)

lockPath := test.TmpFile(t, lockContent)
lock, err := NewLock(lockPath, false)
require.NoError(t, err) // Fail the test if the lock cannot be created.

// Download the resource into a temporary directory.
tmpDir := test.TmpDir(t)
err = lock.Download(tmpDir, []string{}, []string{}, "", false)
assert.NoError(t, err) // Verify the download succeeded.

// Ensure no upload was attempted.
assert.False(t, uploadAttempted)
})
}

// TestDeleteWithArtifactoryCache verifies deleting a resource with caching enabled.
func TestDeleteWithArtifactoryCache(t *testing.T) {
// Sub-test to verify successful deletion of a resource.
t.Run("SuccessfulDelete", func(t *testing.T) {
// Set the GRABIT_ARTIFACTORY_TOKEN environment variable.
t.Setenv("GRABIT_ARTIFACTORY_TOKEN", "test-token")

// Setup an HTTP handler to handle DELETE requests.
handler := func(w http.ResponseWriter, r *http.Request) {
if r.Method == "DELETE" { // Respond with OK for DELETE requests.
w.WriteHeader(http.StatusOK)
}
}
// Start the HTTP server and get the port it runs on.
port, server := test.HttpHandler(handler)
defer server.Close() // Ensure the server is stopped after the test.

// Set up URLs for the source file and cache.
sourceURL := fmt.Sprintf("http://localhost:%d/test.txt", port)
cacheURL := fmt.Sprintf("http://localhost:%d", port)

// Create a lock file with the resource and cache information.
lockContent := fmt.Sprintf(`[[Resource]]
Urls = ['%s']
Integrity = 'sha256-test'
CacheUri = '%s'`, sourceURL, cacheURL)

lockPath := test.TmpFile(t, lockContent)
lock, err := NewLock(lockPath, false)
require.NoError(t, err) // Fail the test if the lock cannot be created.

// Save the lock file before modifying it.
err = lock.Save()
require.NoError(t, err) // Fail the test if saving fails.

// Delete the resource from the lock file.
lock.DeleteResource(sourceURL)

// Save the lock file again after deletion.
err = lock.Save()
require.NoError(t, err) // Fail the test if saving fails.

// Reload the lock file and verify the resource is gone.
newLock, err := NewLock(lockPath, false)
require.NoError(t, err)
assert.Equal(t, 0, len(newLock.conf.Resource)) // Ensure no resources remain.
})
}
Loading

0 comments on commit c760fe1

Please sign in to comment.