diff --git a/internal/cmd/artifacts/cmd.go b/internal/cmd/artifacts/cmd.go
index 910aa6b75..ec4b6acad 100644
--- a/internal/cmd/artifacts/cmd.go
+++ b/internal/cmd/artifacts/cmd.go
@@ -5,7 +5,6 @@ import (
"time"
"github.com/saucelabs/saucectl/internal/artifacts"
- "github.com/saucelabs/saucectl/internal/config"
"github.com/saucelabs/saucectl/internal/credentials"
"github.com/saucelabs/saucectl/internal/http"
"github.com/saucelabs/saucectl/internal/region"
@@ -45,7 +44,7 @@ func Command(preRun func(cmd *cobra.Command, args []string)) *cobra.Command {
creds := credentials.Get()
url := reg.APIBaseURL()
restoClient := http.NewResto(url, creds.Username, creds.AccessKey, restoTimeout)
- rdcClient := http.NewRDCService(url, creds.Username, creds.AccessKey, rdcTimeout, config.ArtifactDownload{})
+ rdcClient := http.NewRDCService(url, creds.Username, creds.AccessKey, rdcTimeout)
testcompClient := http.NewTestComposer(url, creds, testComposerTimeout)
artifactSvc = saucecloud.NewArtifactService(&restoClient, &rdcClient, &testcompClient)
diff --git a/internal/cmd/ini/initializer.go b/internal/cmd/ini/initializer.go
index 8646e305e..6ddc2ee2d 100644
--- a/internal/cmd/ini/initializer.go
+++ b/internal/cmd/ini/initializer.go
@@ -59,7 +59,7 @@ type initializer struct {
func newInitializer(stdio terminal.Stdio, creds iam.Credentials, cfg *initConfig) *initializer {
r := region.FromString(cfg.region)
tc := http.NewTestComposer(r.APIBaseURL(), creds, testComposerTimeout)
- rc := http.NewRDCService(r.APIBaseURL(), creds.Username, creds.AccessKey, rdcTimeout, config.ArtifactDownload{})
+ rc := http.NewRDCService(r.APIBaseURL(), creds.Username, creds.AccessKey, rdcTimeout)
rs := http.NewResto(r.APIBaseURL(), creds.Username, creds.AccessKey, restoTimeout)
us := http.NewUserService(r.APIBaseURL(), creds, 5*time.Second)
diff --git a/internal/cmd/run/cucumber.go b/internal/cmd/run/cucumber.go
index 033d69e32..9e060ad01 100644
--- a/internal/cmd/run/cucumber.go
+++ b/internal/cmd/run/cucumber.go
@@ -13,6 +13,7 @@ import (
"github.com/saucelabs/saucectl/internal/http"
"github.com/saucelabs/saucectl/internal/region"
"github.com/saucelabs/saucectl/internal/saucecloud"
+ "github.com/saucelabs/saucectl/internal/saucecloud/downloader"
"github.com/saucelabs/saucectl/internal/saucecloud/retry"
"github.com/saucelabs/saucectl/internal/segment"
"github.com/saucelabs/saucectl/internal/usage"
@@ -116,14 +117,15 @@ func runCucumber(cmd *cobra.Command, isCLIDriven bool) (int, error) {
creds := regio.Credentials()
restoClient := http.NewResto(regio.APIBaseURL(), creds.Username, creds.AccessKey, 0)
- restoClient.ArtifactConfig = p.Artifacts.Download
testcompClient := http.NewTestComposer(regio.APIBaseURL(), creds, testComposerTimeout)
webdriverClient := http.NewWebdriver(regio.WebDriverBaseURL(), creds, webdriverTimeout)
appsClient := *http.NewAppStore(regio.APIBaseURL(), creds.Username, creds.AccessKey, gFlags.appStoreTimeout)
- rdcClient := http.NewRDCService(regio.APIBaseURL(), creds.Username, creds.AccessKey, rdcTimeout, config.ArtifactDownload{})
+ rdcClient := http.NewRDCService(regio.APIBaseURL(), creds.Username, creds.AccessKey, rdcTimeout)
insightsClient := http.NewInsightsService(regio.APIBaseURL(), creds, insightsTimeout)
iamClient := http.NewUserService(regio.APIBaseURL(), creds, iamTimeout)
+ vdcDownloader := downloader.NewArtifactDownloader(&restoClient, p.Artifacts.Download)
+
log.Info().Msg("Running Playwright-Cucumberjs in Sauce Labs")
r := saucecloud.CucumberRunner{
Project: p,
@@ -137,7 +139,7 @@ func runCucumber(cmd *cobra.Command, isCLIDriven bool) (int, error) {
VDCWriter: &testcompClient,
VDCStopper: &restoClient,
RDCStopper: &rdcClient,
- VDCDownloader: &restoClient,
+ VDCDownloader: &vdcDownloader,
},
TunnelService: &restoClient,
MetadataService: &testcompClient,
diff --git a/internal/cmd/run/cypress.go b/internal/cmd/run/cypress.go
index 9b5063f9e..48ee6dddf 100644
--- a/internal/cmd/run/cypress.go
+++ b/internal/cmd/run/cypress.go
@@ -21,6 +21,7 @@ import (
"github.com/saucelabs/saucectl/internal/msg"
"github.com/saucelabs/saucectl/internal/region"
"github.com/saucelabs/saucectl/internal/saucecloud"
+ "github.com/saucelabs/saucectl/internal/saucecloud/downloader"
"github.com/saucelabs/saucectl/internal/saucecloud/retry"
"github.com/saucelabs/saucectl/internal/segment"
"github.com/saucelabs/saucectl/internal/usage"
@@ -151,14 +152,15 @@ func runCypress(cmd *cobra.Command, cflags cypressFlags, isCLIDriven bool) (int,
creds := regio.Credentials()
restoClient := http.NewResto(regio.APIBaseURL(), creds.Username, creds.AccessKey, 0)
- restoClient.ArtifactConfig = p.GetArtifactsCfg().Download
testcompClient := http.NewTestComposer(regio.APIBaseURL(), creds, testComposerTimeout)
webdriverClient := http.NewWebdriver(regio.WebDriverBaseURL(), creds, webdriverTimeout)
appsClient := *http.NewAppStore(regio.APIBaseURL(), creds.Username, creds.AccessKey, gFlags.appStoreTimeout)
- rdcClient := http.NewRDCService(regio.APIBaseURL(), creds.Username, creds.AccessKey, rdcTimeout, config.ArtifactDownload{})
+ rdcClient := http.NewRDCService(regio.APIBaseURL(), creds.Username, creds.AccessKey, rdcTimeout)
insightsClient := http.NewInsightsService(regio.APIBaseURL(), creds, insightsTimeout)
iamClient := http.NewUserService(regio.APIBaseURL(), creds, iamTimeout)
+ vdcDownloader := downloader.NewArtifactDownloader(&restoClient, p.GetArtifactsCfg().Download)
+
log.Info().Msg("Running Cypress in Sauce Labs")
r := saucecloud.CypressRunner{
Project: p,
@@ -172,7 +174,7 @@ func runCypress(cmd *cobra.Command, cflags cypressFlags, isCLIDriven bool) (int,
VDCWriter: &testcompClient,
VDCStopper: &restoClient,
RDCStopper: &rdcClient,
- VDCDownloader: &restoClient,
+ VDCDownloader: &vdcDownloader,
},
MetadataService: &testcompClient,
TunnelService: &restoClient,
diff --git a/internal/cmd/run/espresso.go b/internal/cmd/run/espresso.go
index 2e04b21c2..a32327540 100644
--- a/internal/cmd/run/espresso.go
+++ b/internal/cmd/run/espresso.go
@@ -19,6 +19,7 @@ import (
"github.com/saucelabs/saucectl/internal/framework"
"github.com/saucelabs/saucectl/internal/region"
"github.com/saucelabs/saucectl/internal/saucecloud"
+ "github.com/saucelabs/saucectl/internal/saucecloud/downloader"
"github.com/saucelabs/saucectl/internal/saucecloud/retry"
"github.com/saucelabs/saucectl/internal/segment"
"github.com/saucelabs/saucectl/internal/usage"
@@ -137,14 +138,16 @@ func runEspressoInCloud(p espresso.Project, regio region.Region) (int, error) {
creds := regio.Credentials()
restoClient := http.NewResto(regio.APIBaseURL(), creds.Username, creds.AccessKey, 0)
- restoClient.ArtifactConfig = p.Artifacts.Download
testcompClient := http.NewTestComposer(regio.APIBaseURL(), creds, testComposerTimeout)
webdriverClient := http.NewWebdriver(regio.WebDriverBaseURL(), creds, webdriverTimeout)
appsClient := *http.NewAppStore(regio.APIBaseURL(), creds.Username, creds.AccessKey, gFlags.appStoreTimeout)
- rdcClient := http.NewRDCService(regio.APIBaseURL(), creds.Username, creds.AccessKey, rdcTimeout, p.Artifacts.Download)
+ rdcClient := http.NewRDCService(regio.APIBaseURL(), creds.Username, creds.AccessKey, rdcTimeout)
insightsClient := http.NewInsightsService(regio.APIBaseURL(), creds, insightsTimeout)
iamClient := http.NewUserService(regio.APIBaseURL(), creds, iamTimeout)
+ vdcDownloader := downloader.NewArtifactDownloader(&restoClient, p.Artifacts.Download)
+ rdcDownloader := downloader.NewArtifactDownloader(&rdcClient, p.Artifacts.Download)
+
r := saucecloud.EspressoRunner{
Project: p,
CloudRunner: saucecloud.CloudRunner{
@@ -157,8 +160,8 @@ func runEspressoInCloud(p espresso.Project, regio region.Region) (int, error) {
VDCWriter: &testcompClient,
VDCStopper: &restoClient,
RDCStopper: &rdcClient,
- VDCDownloader: &restoClient,
- RDCDownloader: &rdcClient,
+ VDCDownloader: &vdcDownloader,
+ RDCDownloader: &rdcDownloader,
},
TunnelService: &restoClient,
MetadataService: &testcompClient,
diff --git a/internal/cmd/run/playwright.go b/internal/cmd/run/playwright.go
index 17f752a91..11ea90a4f 100644
--- a/internal/cmd/run/playwright.go
+++ b/internal/cmd/run/playwright.go
@@ -22,6 +22,7 @@ import (
"github.com/saucelabs/saucectl/internal/playwright"
"github.com/saucelabs/saucectl/internal/region"
"github.com/saucelabs/saucectl/internal/saucecloud"
+ "github.com/saucelabs/saucectl/internal/saucecloud/downloader"
"github.com/saucelabs/saucectl/internal/saucecloud/retry"
"github.com/saucelabs/saucectl/internal/segment"
"github.com/saucelabs/saucectl/internal/usage"
@@ -162,14 +163,15 @@ func runPlaywright(cmd *cobra.Command, pf playwrightFlags, isCLIDriven bool) (in
creds := regio.Credentials()
restoClient := http.NewResto(regio.APIBaseURL(), creds.Username, creds.AccessKey, 0)
- restoClient.ArtifactConfig = p.Artifacts.Download
testcompClient := http.NewTestComposer(regio.APIBaseURL(), creds, testComposerTimeout)
webdriverClient := http.NewWebdriver(regio.WebDriverBaseURL(), creds, webdriverTimeout)
appsClient := *http.NewAppStore(regio.APIBaseURL(), creds.Username, creds.AccessKey, gFlags.appStoreTimeout)
- rdcClient := http.NewRDCService(regio.APIBaseURL(), creds.Username, creds.AccessKey, rdcTimeout, config.ArtifactDownload{})
+ rdcClient := http.NewRDCService(regio.APIBaseURL(), creds.Username, creds.AccessKey, rdcTimeout)
insightsClient := http.NewInsightsService(regio.APIBaseURL(), creds, insightsTimeout)
iamClient := http.NewUserService(regio.APIBaseURL(), creds, iamTimeout)
+ vdcDownloader := downloader.NewArtifactDownloader(&restoClient, p.Artifacts.Download)
+
log.Info().Msg("Running Playwright in Sauce Labs")
r := saucecloud.PlaywrightRunner{
Project: p,
@@ -183,7 +185,7 @@ func runPlaywright(cmd *cobra.Command, pf playwrightFlags, isCLIDriven bool) (in
VDCWriter: &testcompClient,
VDCStopper: &restoClient,
RDCStopper: &rdcClient,
- VDCDownloader: &restoClient,
+ VDCDownloader: &vdcDownloader,
},
TunnelService: &restoClient,
MetadataService: &testcompClient,
diff --git a/internal/cmd/run/replay.go b/internal/cmd/run/replay.go
index f51231678..590d65443 100644
--- a/internal/cmd/run/replay.go
+++ b/internal/cmd/run/replay.go
@@ -21,6 +21,7 @@ import (
"github.com/saucelabs/saucectl/internal/puppeteer/replay"
"github.com/saucelabs/saucectl/internal/region"
"github.com/saucelabs/saucectl/internal/saucecloud"
+ "github.com/saucelabs/saucectl/internal/saucecloud/downloader"
"github.com/saucelabs/saucectl/internal/saucecloud/retry"
"github.com/saucelabs/saucectl/internal/segment"
"github.com/saucelabs/saucectl/internal/usage"
@@ -125,14 +126,15 @@ func runPuppeteerReplayInSauce(p replay.Project, regio region.Region) (int, erro
creds := regio.Credentials()
restoClient := http.NewResto(regio.APIBaseURL(), creds.Username, creds.AccessKey, 0)
- restoClient.ArtifactConfig = p.Artifacts.Download
testcompClient := http.NewTestComposer(regio.APIBaseURL(), creds, testComposerTimeout)
webdriverClient := http.NewWebdriver(regio.WebDriverBaseURL(), creds, webdriverTimeout)
appsClient := *http.NewAppStore(regio.APIBaseURL(), creds.Username, creds.AccessKey, gFlags.appStoreTimeout)
- rdcClient := http.NewRDCService(regio.APIBaseURL(), creds.Username, creds.AccessKey, rdcTimeout, config.ArtifactDownload{})
+ rdcClient := http.NewRDCService(regio.APIBaseURL(), creds.Username, creds.AccessKey, rdcTimeout)
insightsClient := http.NewInsightsService(regio.APIBaseURL(), creds, insightsTimeout)
iamClient := http.NewUserService(regio.APIBaseURL(), creds, iamTimeout)
+ vdcDownloader := downloader.NewArtifactDownloader(&restoClient, p.Artifacts.Download)
+
r := saucecloud.ReplayRunner{
Project: p,
CloudRunner: saucecloud.CloudRunner{
@@ -145,7 +147,7 @@ func runPuppeteerReplayInSauce(p replay.Project, regio region.Region) (int, erro
VDCWriter: &testcompClient,
VDCStopper: &restoClient,
RDCStopper: &rdcClient,
- VDCDownloader: &restoClient,
+ VDCDownloader: &vdcDownloader,
},
TunnelService: &restoClient,
MetadataService: &testcompClient,
diff --git a/internal/cmd/run/testcafe.go b/internal/cmd/run/testcafe.go
index 87d4fd01b..361bfa80c 100644
--- a/internal/cmd/run/testcafe.go
+++ b/internal/cmd/run/testcafe.go
@@ -21,6 +21,7 @@ import (
"github.com/saucelabs/saucectl/internal/msg"
"github.com/saucelabs/saucectl/internal/region"
"github.com/saucelabs/saucectl/internal/saucecloud"
+ "github.com/saucelabs/saucectl/internal/saucecloud/downloader"
"github.com/saucelabs/saucectl/internal/saucecloud/retry"
"github.com/saucelabs/saucectl/internal/segment"
"github.com/saucelabs/saucectl/internal/testcafe"
@@ -185,14 +186,15 @@ func runTestcafe(cmd *cobra.Command, tcFlags testcafeFlags, isCLIDriven bool) (i
creds := regio.Credentials()
restoClient := http.NewResto(regio.APIBaseURL(), creds.Username, creds.AccessKey, 0)
- restoClient.ArtifactConfig = p.Artifacts.Download
testcompClient := http.NewTestComposer(regio.APIBaseURL(), creds, testComposerTimeout)
webdriverClient := http.NewWebdriver(regio.WebDriverBaseURL(), creds, webdriverTimeout)
appsClient := *http.NewAppStore(regio.APIBaseURL(), creds.Username, creds.AccessKey, gFlags.appStoreTimeout)
- rdcClient := http.NewRDCService(regio.APIBaseURL(), creds.Username, creds.AccessKey, rdcTimeout, config.ArtifactDownload{})
+ rdcClient := http.NewRDCService(regio.APIBaseURL(), creds.Username, creds.AccessKey, rdcTimeout)
insightsClient := http.NewInsightsService(regio.APIBaseURL(), creds, insightsTimeout)
iamClient := http.NewUserService(regio.APIBaseURL(), creds, iamTimeout)
+ vdcDownloader := downloader.NewArtifactDownloader(&restoClient, p.Artifacts.Download)
+
log.Info().Msg("Running Testcafe in Sauce Labs")
r := saucecloud.TestcafeRunner{
Project: p,
@@ -206,7 +208,7 @@ func runTestcafe(cmd *cobra.Command, tcFlags testcafeFlags, isCLIDriven bool) (i
VDCWriter: &testcompClient,
VDCStopper: &restoClient,
RDCStopper: &rdcClient,
- VDCDownloader: &restoClient,
+ VDCDownloader: &vdcDownloader,
},
TunnelService: &restoClient,
MetadataService: &testcompClient,
diff --git a/internal/cmd/run/xcuitest.go b/internal/cmd/run/xcuitest.go
index 279d4b7e2..d59d8d2ed 100644
--- a/internal/cmd/run/xcuitest.go
+++ b/internal/cmd/run/xcuitest.go
@@ -18,6 +18,7 @@ import (
"github.com/saucelabs/saucectl/internal/framework"
"github.com/saucelabs/saucectl/internal/region"
"github.com/saucelabs/saucectl/internal/saucecloud"
+ "github.com/saucelabs/saucectl/internal/saucecloud/downloader"
"github.com/saucelabs/saucectl/internal/saucecloud/retry"
"github.com/saucelabs/saucectl/internal/segment"
"github.com/saucelabs/saucectl/internal/usage"
@@ -138,14 +139,15 @@ func runXcuitestInCloud(p xcuitest.Project, regio region.Region) (int, error) {
creds := regio.Credentials()
restoClient := http.NewResto(regio.APIBaseURL(), creds.Username, creds.AccessKey, 0)
- restoClient.ArtifactConfig = p.Artifacts.Download
testcompClient := http.NewTestComposer(regio.APIBaseURL(), creds, testComposerTimeout)
webdriverClient := http.NewWebdriver(regio.WebDriverBaseURL(), creds, webdriverTimeout)
appsClient := *http.NewAppStore(regio.APIBaseURL(), creds.Username, creds.AccessKey, gFlags.appStoreTimeout)
- rdcClient := http.NewRDCService(regio.APIBaseURL(), creds.Username, creds.AccessKey, rdcTimeout, p.Artifacts.Download)
+ rdcClient := http.NewRDCService(regio.APIBaseURL(), creds.Username, creds.AccessKey, rdcTimeout)
insightsClient := http.NewInsightsService(regio.APIBaseURL(), creds, insightsTimeout)
iamClient := http.NewUserService(regio.APIBaseURL(), creds, iamTimeout)
+ vdcDownloader := downloader.NewArtifactDownloader(&restoClient, p.Artifacts.Download)
+ rdcDownloader := downloader.NewArtifactDownloader(&rdcClient, p.Artifacts.Download)
r := saucecloud.XcuitestRunner{
Project: p,
CloudRunner: saucecloud.CloudRunner{
@@ -158,8 +160,8 @@ func runXcuitestInCloud(p xcuitest.Project, regio region.Region) (int, error) {
VDCWriter: &testcompClient,
VDCStopper: &restoClient,
RDCStopper: &rdcClient,
- VDCDownloader: &restoClient,
- RDCDownloader: &rdcClient,
+ VDCDownloader: &vdcDownloader,
+ RDCDownloader: &rdcDownloader,
},
TunnelService: &restoClient,
MetadataService: &testcompClient,
diff --git a/internal/http/rdcservice.go b/internal/http/rdcservice.go
index 4fc9e8c73..03f7eb08c 100644
--- a/internal/http/rdcservice.go
+++ b/internal/http/rdcservice.go
@@ -8,31 +8,25 @@ import (
"fmt"
"io"
"net/http"
- "os"
- "path/filepath"
"strings"
"time"
"github.com/saucelabs/saucectl/internal/slice"
"github.com/hashicorp/go-retryablehttp"
- "github.com/rs/zerolog/log"
- "github.com/saucelabs/saucectl/internal/config"
"github.com/saucelabs/saucectl/internal/devices"
"github.com/saucelabs/saucectl/internal/espresso"
- "github.com/saucelabs/saucectl/internal/fpath"
"github.com/saucelabs/saucectl/internal/job"
"github.com/saucelabs/saucectl/internal/xcuitest"
)
// RDCService http client.
type RDCService struct {
- Client *retryablehttp.Client
- URL string
- Username string
- AccessKey string
- ArtifactConfig config.ArtifactDownload
+ Client *retryablehttp.Client
+ URL string
+ Username string
+ AccessKey string
}
type rdcJob struct {
@@ -87,13 +81,12 @@ type DeviceQuery struct {
}
// NewRDCService creates a new client.
-func NewRDCService(url, username, accessKey string, timeout time.Duration, artifactConfig config.ArtifactDownload) RDCService {
+func NewRDCService(url, username, accessKey string, timeout time.Duration) RDCService {
return RDCService{
- Client: NewRetryableClient(timeout),
- URL: url,
- Username: username,
- AccessKey: accessKey,
- ArtifactConfig: artifactConfig,
+ Client: NewRetryableClient(timeout),
+ URL: url,
+ Username: username,
+ AccessKey: accessKey,
}
}
@@ -386,43 +379,6 @@ func (c *RDCService) GetJobAssetFileContent(ctx context.Context, jobID, fileName
return io.ReadAll(resp.Body)
}
-// DownloadArtifact downloads artifacts and returns a list of downloaded files.
-func (c *RDCService) DownloadArtifact(jobID, suiteName string, realDevice bool) []string {
- targetDir, err := config.GetSuiteArtifactFolder(suiteName, c.ArtifactConfig)
- if err != nil {
- log.Error().Msgf("Unable to create artifacts folder (%v)", err)
- return []string{}
- }
-
- files, err := c.GetJobAssetFileNames(context.Background(), jobID, realDevice)
- if err != nil {
- log.Error().Msgf("Unable to fetch artifacts list (%v)", err)
- return []string{}
- }
-
- filepaths := fpath.MatchFiles(files, c.ArtifactConfig.Match)
- var artifacts []string
- for _, f := range filepaths {
- targetFile, err := c.downloadArtifact(targetDir, jobID, f, realDevice)
- if err != nil {
- log.Err(err).Msg("Unable to download artifacts")
- return artifacts
- }
- artifacts = append(artifacts, targetFile)
- }
-
- return artifacts
-}
-
-func (c *RDCService) downloadArtifact(targetDir, jobID, fileName string, realDevice bool) (string, error) {
- content, err := c.GetJobAssetFileContent(context.Background(), jobID, fileName, realDevice)
- if err != nil {
- return "", err
- }
- targetFile := filepath.Join(targetDir, fileName)
- return targetFile, os.WriteFile(targetFile, content, 0644)
-}
-
// GetDevices returns the list of available devices using a specific operating system.
func (c *RDCService) GetDevices(ctx context.Context, OS string) ([]devices.Device, error) {
req, err := NewRetryableRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("%s/v1/rdc/devices/filtered", c.URL), nil)
diff --git a/internal/http/rdcservice_test.go b/internal/http/rdcservice_test.go
index 18003331c..4db2ba35e 100644
--- a/internal/http/rdcservice_test.go
+++ b/internal/http/rdcservice_test.go
@@ -7,15 +7,12 @@ import (
"fmt"
"net/http"
"net/http/httptest"
- "os"
- "path/filepath"
"reflect"
"sort"
"testing"
"time"
"github.com/hashicorp/go-retryablehttp"
- "github.com/saucelabs/saucectl/internal/config"
"github.com/saucelabs/saucectl/internal/devices"
"github.com/saucelabs/saucectl/internal/job"
"github.com/stretchr/testify/assert"
@@ -45,7 +42,7 @@ func TestRDCService_ReadJob(t *testing.T) {
}))
defer ts.Close()
timeout := 3 * time.Second
- client := NewRDCService(ts.URL, "test-user", "test-key", timeout, config.ArtifactDownload{})
+ client := NewRDCService(ts.URL, "test-user", "test-key", timeout)
testCases := []struct {
name string
@@ -142,7 +139,7 @@ func TestRDCService_PollJob(t *testing.T) {
}{
{
name: "get job details with ID 1 and status 'complete'",
- client: NewRDCService(ts.URL, "test", "123", timeout, config.ArtifactDownload{}),
+ client: NewRDCService(ts.URL, "test", "123", timeout),
jobID: "1",
expectedResp: job.Job{
ID: "1",
@@ -155,7 +152,7 @@ func TestRDCService_PollJob(t *testing.T) {
},
{
name: "get job details with ID 2 and status 'error'",
- client: NewRDCService(ts.URL, "test", "123", timeout, config.ArtifactDownload{}),
+ client: NewRDCService(ts.URL, "test", "123", timeout),
jobID: "2",
expectedResp: job.Job{
ID: "2",
@@ -168,28 +165,28 @@ func TestRDCService_PollJob(t *testing.T) {
},
{
name: "job not found error from external API",
- client: NewRDCService(ts.URL, "test", "123", timeout, config.ArtifactDownload{}),
+ client: NewRDCService(ts.URL, "test", "123", timeout),
jobID: "3",
expectedResp: job.Job{},
expectedErr: ErrJobNotFound,
},
{
name: "http status is not 200, but 401 from external API",
- client: NewRDCService(ts.URL, "test", "123", timeout, config.ArtifactDownload{}),
+ client: NewRDCService(ts.URL, "test", "123", timeout),
jobID: "4",
expectedResp: job.Job{},
expectedErr: errors.New("unexpected statusCode: 401"),
},
{
name: "unexpected status code from external API",
- client: NewRDCService(ts.URL, "test", "123", timeout, config.ArtifactDownload{}),
+ client: NewRDCService(ts.URL, "test", "123", timeout),
jobID: "333",
expectedResp: job.Job{},
expectedErr: errors.New("internal server error"),
},
{
name: "get job details with ID 5. retry 2 times and succeed",
- client: NewRDCService(ts.URL, "test", "123", timeout, config.ArtifactDownload{}),
+ client: NewRDCService(ts.URL, "test", "123", timeout),
jobID: "5",
expectedResp: job.Job{
ID: "5",
@@ -241,7 +238,7 @@ func TestRDCService_GetJobAssetFileNames(t *testing.T) {
}
}))
defer ts.Close()
- client := NewRDCService(ts.URL, "test-user", "test-password", 1*time.Second, config.ArtifactDownload{})
+ client := NewRDCService(ts.URL, "test-user", "test-password", 1*time.Second)
testCases := []struct {
name string
@@ -314,7 +311,7 @@ func TestRDCService_GetJobAssetFileContent(t *testing.T) {
}
}))
defer ts.Close()
- client := NewRDCService(ts.URL, "test-user", "test-password", 1*time.Second, config.ArtifactDownload{})
+ client := NewRDCService(ts.URL, "test-user", "test-password", 1*time.Second)
testCases := []struct {
name string
@@ -353,50 +350,6 @@ func TestRDCService_GetJobAssetFileContent(t *testing.T) {
}
}
-func TestRDCService_DownloadArtifact(t *testing.T) {
- fileContent := "junit.xml"
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- var err error
- switch r.URL.Path {
- case "/v1/rdc/jobs/test-123":
- _, err = w.Write([]byte(`{"automation_backend":"espresso"}`))
- case "/v1/rdc/jobs/test-123/junit.xml":
- _, err = w.Write([]byte(fileContent))
- default:
- w.WriteHeader(http.StatusNotFound)
- }
-
- if err != nil {
- t.Errorf("failed to respond: %v", err)
- }
- }))
- defer ts.Close()
-
- tempDir, err := os.MkdirTemp("", "saucectl-download-artifact")
- if err != nil {
- t.Errorf("Failed to create temp dir: %v", err)
- }
- defer func() {
- _ = os.RemoveAll(tempDir)
- }()
-
- rc := NewRDCService(ts.URL, "dummy-user", "dummy-key", 10*time.Second, config.ArtifactDownload{
- Directory: tempDir,
- Match: []string{"junit.xml"},
- })
- rc.DownloadArtifact("test-123", "suite name", true)
-
- fileName := filepath.Join(tempDir, "suite_name", "junit.xml")
- d, err := os.ReadFile(fileName)
- if err != nil {
- t.Errorf("file '%s' not found: %v", fileName, err)
- }
-
- if string(d) != fileContent {
- t.Errorf("file content mismatch: got '%v', expects: '%v'", d, fileContent)
- }
-}
-
func TestRDCService_GetDevices(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var err error
diff --git a/internal/http/resto.go b/internal/http/resto.go
index 9e54a9841..0d217a2c2 100644
--- a/internal/http/resto.go
+++ b/internal/http/resto.go
@@ -7,19 +7,13 @@ import (
"fmt"
"io"
"net/http"
- "os"
- "path/filepath"
"reflect"
"sort"
"strings"
"time"
"github.com/hashicorp/go-retryablehttp"
- "github.com/rs/zerolog/log"
- "github.com/ryanuber/go-glob"
-
"github.com/saucelabs/saucectl/internal/build"
- "github.com/saucelabs/saucectl/internal/config"
"github.com/saucelabs/saucectl/internal/job"
tunnels "github.com/saucelabs/saucectl/internal/tunnel"
"github.com/saucelabs/saucectl/internal/vmd"
@@ -54,11 +48,10 @@ type restoJob struct {
// Resto http client.
type Resto struct {
- Client *retryablehttp.Client
- URL string
- Username string
- AccessKey string
- ArtifactConfig config.ArtifactDownload
+ Client *retryablehttp.Client
+ URL string
+ Username string
+ AccessKey string
}
type tunnel struct {
@@ -348,43 +341,6 @@ func (c *Resto) StopJob(ctx context.Context, jobID string, realDevice bool) (job
return c.parseJob(resp.Body)
}
-// DownloadArtifact downloads artifacts and returns a list of what was downloaded.
-func (c *Resto) DownloadArtifact(jobID, suiteName string, realDevice bool) []string {
- targetDir, err := config.GetSuiteArtifactFolder(suiteName, c.ArtifactConfig)
- if err != nil {
- log.Error().Msgf("Unable to create artifacts folder (%v)", err)
- return []string{}
- }
- files, err := c.GetJobAssetFileNames(context.Background(), jobID, realDevice)
- if err != nil {
- log.Error().Msgf("Unable to fetch artifacts list (%v)", err)
- return []string{}
- }
- var artifacts []string
- for _, f := range files {
- for _, pattern := range c.ArtifactConfig.Match {
- if glob.Glob(pattern, f) {
- if err := c.downloadArtifact(targetDir, jobID, f); err != nil {
- log.Error().Err(err).Msgf("Failed to download file: %s", f)
- } else {
- artifacts = append(artifacts, filepath.Join(targetDir, f))
- }
- break
- }
- }
- }
- return artifacts
-}
-
-func (c *Resto) downloadArtifact(targetDir, jobID, fileName string) error {
- content, err := c.GetJobAssetFileContent(context.Background(), jobID, fileName, false)
- if err != nil {
- return err
- }
- targetFile := filepath.Join(targetDir, fileName)
- return os.WriteFile(targetFile, content, 0644)
-}
-
// GetVirtualDevices returns the list of available virtual devices.
func (c *Resto) GetVirtualDevices(ctx context.Context, kind string) ([]vmd.VirtualDevice, error) {
req, err := NewRetryableRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("%s/rest/v1.1/info/platforms/all", c.URL), nil)
diff --git a/internal/saucecloud/downloader/downloader.go b/internal/saucecloud/downloader/downloader.go
new file mode 100644
index 000000000..95706ce49
--- /dev/null
+++ b/internal/saucecloud/downloader/downloader.go
@@ -0,0 +1,59 @@
+package downloader
+
+import (
+ "context"
+ "os"
+ "path/filepath"
+
+ "github.com/rs/zerolog/log"
+ "github.com/saucelabs/saucectl/internal/config"
+ "github.com/saucelabs/saucectl/internal/fpath"
+ "github.com/saucelabs/saucectl/internal/job"
+)
+
+type ArtifactDownloader struct {
+ reader job.Reader
+ config config.ArtifactDownload
+}
+
+func NewArtifactDownloader(reader job.Reader, artifactConfig config.ArtifactDownload) ArtifactDownloader {
+ return ArtifactDownloader{
+ reader: reader,
+ config: artifactConfig,
+ }
+}
+
+func (d *ArtifactDownloader) DownloadArtifact(jobID string, suiteName string, realDevice bool) []string {
+ targetDir, err := config.GetSuiteArtifactFolder(suiteName, d.config)
+ if err != nil {
+ log.Error().Msgf("Unable to create artifacts folder (%v)", err)
+ return []string{}
+ }
+ files, err := d.reader.GetJobAssetFileNames(context.Background(), jobID, realDevice)
+ if err != nil {
+ log.Error().Msgf("Unable to fetch artifacts list (%v)", err)
+ return []string{}
+ }
+
+ filepaths := fpath.MatchFiles(files, d.config.Match)
+ var artifacts []string
+ for _, f := range filepaths {
+ targetFile, err := d.downloadArtifact(targetDir, jobID, f, realDevice)
+ if err != nil {
+ log.Err(err).Msg("Unable to download artifacts")
+ return artifacts
+ }
+ artifacts = append(artifacts, targetFile)
+ }
+
+ return artifacts
+}
+
+func (d *ArtifactDownloader) downloadArtifact(targetDir, jobID, fileName string, realDevice bool) (string, error) {
+ content, err := d.reader.GetJobAssetFileContent(context.Background(), jobID, fileName, realDevice)
+ if err != nil {
+ return "", err
+ }
+ targetFile := filepath.Join(targetDir, fileName)
+ return targetFile, os.WriteFile(targetFile, content, 0644)
+}
diff --git a/internal/saucecloud/downloader/downloader_test.go b/internal/saucecloud/downloader/downloader_test.go
new file mode 100644
index 000000000..490c7260e
--- /dev/null
+++ b/internal/saucecloud/downloader/downloader_test.go
@@ -0,0 +1,60 @@
+package downloader
+
+import (
+ "net/http"
+ "net/http/httptest"
+ "os"
+ "path/filepath"
+ "testing"
+ "time"
+
+ "github.com/saucelabs/saucectl/internal/config"
+ httpServices "github.com/saucelabs/saucectl/internal/http"
+)
+
+func TestArtifactDownloader_DownloadArtifact(t *testing.T) {
+ fileContent := "junit.xml"
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ var err error
+ switch r.URL.Path {
+ case "/v1/rdc/jobs/test-123":
+ _, err = w.Write([]byte(`{"automation_backend":"espresso"}`))
+ case "/v1/rdc/jobs/test-123/junit.xml":
+ _, err = w.Write([]byte(fileContent))
+ default:
+ w.WriteHeader(http.StatusNotFound)
+ }
+
+ if err != nil {
+ t.Errorf("failed to respond: %v", err)
+ }
+ }))
+ defer ts.Close()
+
+ tempDir, err := os.MkdirTemp("", "saucectl-download-artifact")
+ if err != nil {
+ t.Errorf("Failed to create temp dir: %v", err)
+ }
+ defer func() {
+ _ = os.RemoveAll(tempDir)
+ }()
+
+ rc := httpServices.NewRDCService(ts.URL, "dummy-user", "dummy-key", 10*time.Second)
+ artifactCfg := config.ArtifactDownload{
+ Directory: tempDir,
+ Match: []string{"junit.xml"},
+ }
+
+ downloader := NewArtifactDownloader(&rc, artifactCfg)
+ downloader.DownloadArtifact("test-123", "suite name", true)
+
+ fileName := filepath.Join(tempDir, "suite_name", "junit.xml")
+ d, err := os.ReadFile(fileName)
+ if err != nil {
+ t.Errorf("file '%s' not found: %v", fileName, err)
+ }
+
+ if string(d) != fileContent {
+ t.Errorf("file content mismatch: got '%v', expects: '%v'", d, fileContent)
+ }
+}