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  }