github.com/saucelabs/saucectl@v0.175.1/internal/saucecloud/replay.go (about) 1 package saucecloud 2 3 import ( 4 "context" 5 "errors" 6 7 "github.com/rs/zerolog/log" 8 "github.com/saucelabs/saucectl/internal/framework" 9 "github.com/saucelabs/saucectl/internal/job" 10 "github.com/saucelabs/saucectl/internal/msg" 11 "github.com/saucelabs/saucectl/internal/puppeteer/replay" 12 ) 13 14 // ReplayRunner represents the Sauce Labs cloud implementation for puppeteer-replay. 15 type ReplayRunner struct { 16 CloudRunner 17 Project replay.Project 18 } 19 20 // RunProject runs the tests defined in cypress.Project. 21 func (r *ReplayRunner) RunProject() (int, error) { 22 exitCode := 1 23 24 m, err := r.MetadataSearchStrategy.Find(context.Background(), r.MetadataService, replay.Kind, "latest") 25 if err != nil { 26 r.logFrameworkError(err) 27 return exitCode, err 28 } 29 if r.Project.RunnerVersion == "" { 30 r.Project.RunnerVersion = m.CloudRunnerVersion 31 } 32 33 for _, s := range r.Project.Suites { 34 if s.Platform != "" && !framework.HasPlatform(m, s.Platform) { 35 msg.LogUnsupportedPlatform(s.Platform, framework.PlatformNames(m.Platforms)) 36 return 1, errors.New("unsupported platform") 37 } 38 } 39 40 if err := r.validateTunnel( 41 r.Project.Sauce.Tunnel.Name, 42 r.Project.Sauce.Tunnel.Owner, 43 r.Project.DryRun, 44 r.Project.Sauce.Tunnel.Timeout, 45 ); err != nil { 46 return 1, err 47 } 48 49 var files []string 50 var suiteNames []string 51 for _, suite := range r.Project.Suites { 52 suiteNames = append(suiteNames, suite.Name) 53 files = append(files, suite.Recording) 54 } 55 56 fileURIs, err := r.remoteArchiveFiles(r.Project, files, "", r.Project.DryRun) 57 if err != nil { 58 return exitCode, err 59 } 60 61 if r.Project.DryRun { 62 printDryRunSuiteNames(suiteNames) 63 return 0, nil 64 } 65 66 passed := r.runSuites(fileURIs) 67 if passed { 68 exitCode = 0 69 } 70 71 return exitCode, nil 72 } 73 74 func (r *ReplayRunner) runSuites(fileURI string) bool { 75 sigChan := r.registerSkipSuitesOnSignal() 76 defer unregisterSignalCapture(sigChan) 77 78 jobOpts, results, err := r.createWorkerPool(r.Project.Sauce.Concurrency, r.Project.Sauce.Retries) 79 if err != nil { 80 return false 81 } 82 defer close(results) 83 84 suites := r.Project.Suites 85 if r.Project.Sauce.LaunchOrder != "" { 86 history, err := r.getHistory(r.Project.Sauce.LaunchOrder) 87 if err != nil { 88 log.Warn().Err(err).Msg(msg.RetrieveJobHistoryError) 89 } else { 90 suites = replay.SortByHistory(suites, history) 91 } 92 } 93 // Submit suites to work on. 94 go func() { 95 for _, s := range suites { 96 jobOpts <- job.StartOptions{ 97 ConfigFilePath: r.Project.ConfigFilePath, 98 DisplayName: s.Name, 99 Timeout: s.Timeout, 100 App: fileURI, 101 Suite: s.Name, 102 Framework: "puppeteer-replay", 103 FrameworkVersion: "latest", 104 RunnerVersion: r.Project.RunnerVersion, 105 BrowserName: s.BrowserName, 106 BrowserVersion: s.BrowserVersion, 107 PlatformName: s.Platform, 108 Name: s.Name, 109 Build: r.Project.Sauce.Metadata.Build, 110 Tags: r.Project.Sauce.Metadata.Tags, 111 Tunnel: job.TunnelOptions{ 112 ID: r.Project.Sauce.Tunnel.Name, 113 Parent: r.Project.Sauce.Tunnel.Owner, 114 }, 115 Experiments: r.Project.Sauce.Experiments, 116 Attempt: 0, 117 Retries: r.Project.Sauce.Retries, 118 Visibility: r.Project.Sauce.Visibility, 119 PassThreshold: s.PassThreshold, 120 } 121 } 122 }() 123 124 return r.collectResults(r.Project.Artifacts.Download, results, len(r.Project.Suites)) 125 }