Skip to content

Commit

Permalink
Move cmd.globalState to new cmd/state package
Browse files Browse the repository at this point in the history
This allows us to use it in tests outside of the cmd package.

See #2459
  • Loading branch information
Ivan Mirić committed Dec 16, 2022
1 parent 3db11f2 commit f223cd5
Show file tree
Hide file tree
Showing 32 changed files with 629 additions and 644 deletions.
10 changes: 6 additions & 4 deletions cmd/archive.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package cmd
import (
"github.com/spf13/cobra"
"github.com/spf13/pflag"

"go.k6.io/k6/cmd/state"
)

// cmdArchive handles the `k6 archive` sub-command
type cmdArchive struct {
gs *globalState
gs *state.GlobalState

archiveOut string
excludeEnvVars bool
Expand All @@ -31,13 +33,13 @@ func (c *cmdArchive) run(cmd *cobra.Command, args []string) error {

// Archive.
arc := testRunState.Runner.MakeArchive()
f, err := c.gs.fs.Create(c.archiveOut)
f, err := c.gs.FS.Create(c.archiveOut)
if err != nil {
return err
}

if c.excludeEnvVars {
c.gs.logger.Debug("environment variables will be excluded from the archive")
c.gs.Logger.Debug("environment variables will be excluded from the archive")

arc.Env = nil
}
Expand Down Expand Up @@ -66,7 +68,7 @@ func (c *cmdArchive) flagSet() *pflag.FlagSet {
return flags
}

func getCmdArchive(gs *globalState) *cobra.Command {
func getCmdArchive(gs *state.GlobalState) *cobra.Command {
c := &cmdArchive{
gs: gs,
archiveOut: "archive.tar",
Expand Down
37 changes: 19 additions & 18 deletions cmd/archive_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

"github.com/spf13/afero"
"github.com/stretchr/testify/require"
"go.k6.io/k6/cmd/state"
"go.k6.io/k6/errext/exitcodes"
)

Expand Down Expand Up @@ -78,17 +79,17 @@ func TestArchiveThresholds(t *testing.T) {
testScript, err := ioutil.ReadFile(testCase.testFilename)
require.NoError(t, err)

testState := newGlobalTestState(t)
require.NoError(t, afero.WriteFile(testState.fs, filepath.Join(testState.cwd, testCase.testFilename), testScript, 0o644))
testState.args = []string{"k6", "archive", testCase.testFilename}
ts := state.NewGlobalTestState(t)
require.NoError(t, afero.WriteFile(ts.FS, filepath.Join(ts.Cwd, testCase.testFilename), testScript, 0o644))
ts.CmdArgs = []string{"k6", "archive", testCase.testFilename}
if testCase.noThresholds {
testState.args = append(testState.args, "--no-thresholds")
ts.CmdArgs = append(ts.CmdArgs, "--no-thresholds")
}

if testCase.wantErr {
testState.expectedExitCode = int(exitcodes.InvalidConfig)
ts.ExpectedExitCode = int(exitcodes.InvalidConfig)
}
newRootCommand(testState.globalState).execute()
newRootCommand(ts.GlobalState).execute()
})
}
}
Expand All @@ -99,16 +100,16 @@ func TestArchiveContainsEnv(t *testing.T) {
// given some script that will be archived
fileName := "script.js"
testScript := []byte(`export default function () {}`)
testState := newGlobalTestState(t)
require.NoError(t, afero.WriteFile(testState.fs, filepath.Join(testState.cwd, fileName), testScript, 0o644))
ts := state.NewGlobalTestState(t)
require.NoError(t, afero.WriteFile(ts.FS, filepath.Join(ts.Cwd, fileName), testScript, 0o644))

// when we do archiving and passing the `--env` flags
testState.args = []string{"k6", "--env", "ENV1=lorem", "--env", "ENV2=ipsum", "archive", fileName}
ts.CmdArgs = []string{"k6", "--env", "ENV1=lorem", "--env", "ENV2=ipsum", "archive", fileName}

newRootCommand(testState.globalState).execute()
require.NoError(t, untar(t, testState.fs, "archive.tar", "tmp/"))
newRootCommand(ts.GlobalState).execute()
require.NoError(t, untar(t, ts.FS, "archive.tar", "tmp/"))

data, err := afero.ReadFile(testState.fs, "tmp/metadata.json")
data, err := afero.ReadFile(ts.FS, "tmp/metadata.json")
require.NoError(t, err)

metadata := struct {
Expand All @@ -132,16 +133,16 @@ func TestArchiveNotContainsEnv(t *testing.T) {
// given some script that will be archived
fileName := "script.js"
testScript := []byte(`export default function () {}`)
testState := newGlobalTestState(t)
require.NoError(t, afero.WriteFile(testState.fs, filepath.Join(testState.cwd, fileName), testScript, 0o644))
ts := state.NewGlobalTestState(t)
require.NoError(t, afero.WriteFile(ts.FS, filepath.Join(ts.Cwd, fileName), testScript, 0o644))

// when we do archiving and passing the `--env` flags altogether with `--exclude-env-vars` flag
testState.args = []string{"k6", "--env", "ENV1=lorem", "--env", "ENV2=ipsum", "archive", "--exclude-env-vars", fileName}
ts.CmdArgs = []string{"k6", "--env", "ENV1=lorem", "--env", "ENV2=ipsum", "archive", "--exclude-env-vars", fileName}

newRootCommand(testState.globalState).execute()
require.NoError(t, untar(t, testState.fs, "archive.tar", "tmp/"))
newRootCommand(ts.GlobalState).execute()
require.NoError(t, untar(t, ts.FS, "archive.tar", "tmp/"))

data, err := afero.ReadFile(testState.fs, "tmp/metadata.json")
data, err := afero.ReadFile(ts.FS, "tmp/metadata.json")
require.NoError(t, err)

metadata := struct {
Expand Down
33 changes: 17 additions & 16 deletions cmd/cloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/spf13/pflag"

"go.k6.io/k6/cloudapi"
"go.k6.io/k6/cmd/state"
"go.k6.io/k6/errext"
"go.k6.io/k6/errext/exitcodes"
"go.k6.io/k6/lib"
Expand All @@ -25,7 +26,7 @@ import (

// cmdCloud handles the `k6 cloud` sub-command
type cmdCloud struct {
gs *globalState
gs *state.GlobalState

showCloudLogs bool
exitOnRunning bool
Expand All @@ -37,7 +38,7 @@ func (c *cmdCloud) preRun(cmd *cobra.Command, args []string) error {
// We deliberately parse the env variables, to validate for wrong
// values, even if we don't subsequently use them (if the respective
// CLI flag was specified, since it has a higher priority).
if showCloudLogsEnv, ok := c.gs.envVars["K6_SHOW_CLOUD_LOGS"]; ok {
if showCloudLogsEnv, ok := c.gs.Env["K6_SHOW_CLOUD_LOGS"]; ok {
showCloudLogsValue, err := strconv.ParseBool(showCloudLogsEnv)
if err != nil {
return fmt.Errorf("parsing K6_SHOW_CLOUD_LOGS returned an error: %w", err)
Expand All @@ -47,7 +48,7 @@ func (c *cmdCloud) preRun(cmd *cobra.Command, args []string) error {
}
}

if exitOnRunningEnv, ok := c.gs.envVars["K6_EXIT_ON_RUNNING"]; ok {
if exitOnRunningEnv, ok := c.gs.Env["K6_EXIT_ON_RUNNING"]; ok {
exitOnRunningValue, err := strconv.ParseBool(exitOnRunningEnv)
if err != nil {
return fmt.Errorf("parsing K6_EXIT_ON_RUNNING returned an error: %w", err)
Expand Down Expand Up @@ -112,7 +113,7 @@ func (c *cmdCloud) run(cmd *cobra.Command, args []string) error {

// Cloud config
cloudConfig, err := cloudapi.GetConsolidatedConfig(
test.derivedConfig.Collectors["cloud"], c.gs.envVars, "", arc.Options.External)
test.derivedConfig.Collectors["cloud"], c.gs.Env, "", arc.Options.External)
if err != nil {
return err
}
Expand Down Expand Up @@ -146,10 +147,10 @@ func (c *cmdCloud) run(cmd *cobra.Command, args []string) error {
name = filepath.Base(test.sourceRootPath)
}

globalCtx, globalCancel := context.WithCancel(c.gs.ctx)
globalCtx, globalCancel := context.WithCancel(c.gs.Ctx)
defer globalCancel()

logger := c.gs.logger
logger := c.gs.Logger

// Start cloud test run
progressBar.Modify(pb.WithConstProgress(0, "Validating script options"))
Expand Down Expand Up @@ -196,13 +197,13 @@ func (c *cmdCloud) run(cmd *cobra.Command, args []string) error {
executionPlan := test.derivedConfig.Scenarios.GetFullExecutionRequirements(et)

execDesc := getExecutionDescription(
c.gs.console.ApplyTheme, "cloud", test.sourceRootPath, testURL, test.derivedConfig,
c.gs.Console.ApplyTheme, "cloud", test.sourceRootPath, testURL, test.derivedConfig,
et, executionPlan, nil,
)
if c.gs.flags.quiet {
c.gs.logger.Debug(execDesc)
if c.gs.Flags.Quiet {
c.gs.Logger.Debug(execDesc)
} else {
c.gs.console.Print(execDesc)
c.gs.Console.Print(execDesc)
}

progressBar.Modify(
Expand All @@ -213,12 +214,12 @@ func (c *cmdCloud) run(cmd *cobra.Command, args []string) error {

progressCtx, progressCancel := context.WithCancel(globalCtx)
defer progressCancel()
if !c.gs.flags.quiet {
if !c.gs.Flags.Quiet {
progressBarWG := &sync.WaitGroup{}
progressBarWG.Add(1)
defer progressBarWG.Wait()
go func() {
c.gs.console.ShowProgress(progressCtx, []*pb.ProgressBar{progressBar})
c.gs.Console.ShowProgress(progressCtx, []*pb.ProgressBar{progressBar})
progressBarWG.Done()
}()
}
Expand Down Expand Up @@ -293,9 +294,9 @@ func (c *cmdCloud) run(cmd *cobra.Command, args []string) error {
return errext.WithExitCodeIfNone(errors.New("Test progress error"), exitcodes.CloudFailedToGetProgress)
}

if !c.gs.flags.quiet {
c.gs.console.Printf(" test status: %s\n",
c.gs.console.ApplyTheme(testProgress.RunStatusText))
if !c.gs.Flags.Quiet {
c.gs.Console.Printf(" test status: %s\n",
c.gs.Console.ApplyTheme(testProgress.RunStatusText))
} else {
logger.WithField("run_status", testProgress.RunStatusText).Debug("Test finished")
}
Expand Down Expand Up @@ -324,7 +325,7 @@ func (c *cmdCloud) flagSet() *pflag.FlagSet {
return flags
}

func getCmdCloud(gs *globalState) *cobra.Command {
func getCmdCloud(gs *state.GlobalState) *cobra.Command {
c := &cmdCloud{
gs: gs,
showCloudLogs: true,
Expand Down
9 changes: 5 additions & 4 deletions cmd/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/spf13/pflag"
"gopkg.in/guregu/null.v3"

"go.k6.io/k6/cmd/state"
"go.k6.io/k6/errext/exitcodes"
"go.k6.io/k6/lib"
"go.k6.io/k6/lib/types"
Expand Down Expand Up @@ -70,10 +71,10 @@ func exactArgsWithMsg(n int, msg string) cobra.PositionalArgs {
}

// Trap Interrupts, SIGINTs and SIGTERMs and call the given.
func handleTestAbortSignals(gs *globalState, gracefulStopHandler, onHardStop func(os.Signal)) (stop func()) {
func handleTestAbortSignals(gs *state.GlobalState, gracefulStopHandler, onHardStop func(os.Signal)) (stop func()) {
sigC := make(chan os.Signal, 2)
done := make(chan struct{})
gs.signalNotify(sigC, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
gs.SignalNotify(sigC, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)

go func() {
select {
Expand All @@ -90,15 +91,15 @@ func handleTestAbortSignals(gs *globalState, gracefulStopHandler, onHardStop fun
}
// If we get a second signal, we immediately exit, so something like
// https://github.com/k6io/k6/issues/971 never happens again
gs.osExit(int(exitcodes.ExternalAbort))
gs.OSExit(int(exitcodes.ExternalAbort))
case <-done:
return
}
}()

return func() {
close(done)
gs.signalStop(sigC)
gs.SignalStop(sigC)
}
}

Expand Down
25 changes: 13 additions & 12 deletions cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/spf13/pflag"
"gopkg.in/guregu/null.v3"

"go.k6.io/k6/cmd/state"
"go.k6.io/k6/errext"
"go.k6.io/k6/errext/exitcodes"
"go.k6.io/k6/lib"
Expand Down Expand Up @@ -104,42 +105,42 @@ func getConfig(flags *pflag.FlagSet) (Config, error) {
// an error. The only situation in which an error won't be returned is if the
// user didn't explicitly specify a config file path and the default config file
// doesn't exist.
func readDiskConfig(globalState *globalState) (Config, error) {
func readDiskConfig(gs *state.GlobalState) (Config, error) {
// Try to see if the file exists in the supplied filesystem
if _, err := globalState.fs.Stat(globalState.flags.configFilePath); err != nil {
if os.IsNotExist(err) && globalState.flags.configFilePath == globalState.defaultFlags.configFilePath {
if _, err := gs.FS.Stat(gs.Flags.ConfigFilePath); err != nil {
if os.IsNotExist(err) && gs.Flags.ConfigFilePath == gs.DefaultFlags.ConfigFilePath {
// If the file doesn't exist, but it was the default config file (i.e. the user
// didn't specify anything), silence the error
err = nil
}
return Config{}, err
}

data, err := afero.ReadFile(globalState.fs, globalState.flags.configFilePath)
data, err := afero.ReadFile(gs.FS, gs.Flags.ConfigFilePath)
if err != nil {
return Config{}, fmt.Errorf("couldn't load the configuration from %q: %w", globalState.flags.configFilePath, err)
return Config{}, fmt.Errorf("couldn't load the configuration from %q: %w", gs.Flags.ConfigFilePath, err)
}
var conf Config
err = json.Unmarshal(data, &conf)
if err != nil {
return Config{}, fmt.Errorf("couldn't parse the configuration from %q: %w", globalState.flags.configFilePath, err)
return Config{}, fmt.Errorf("couldn't parse the configuration from %q: %w", gs.Flags.ConfigFilePath, err)
}
return conf, nil
}

// Serializes the configuration to a JSON file and writes it in the supplied
// location on the supplied filesystem
func writeDiskConfig(globalState *globalState, conf Config) error {
func writeDiskConfig(gs *state.GlobalState, conf Config) error {
data, err := json.MarshalIndent(conf, "", " ")
if err != nil {
return err
}

if err := globalState.fs.MkdirAll(filepath.Dir(globalState.flags.configFilePath), 0o755); err != nil {
if err := gs.FS.MkdirAll(filepath.Dir(gs.Flags.ConfigFilePath), 0o755); err != nil {
return err
}

return afero.WriteFile(globalState.fs, globalState.flags.configFilePath, data, 0o644)
return afero.WriteFile(gs.FS, gs.Flags.ConfigFilePath, data, 0o644)
}

// Reads configuration variables from the environment.
Expand All @@ -162,14 +163,14 @@ func readEnvConfig(envMap map[string]string) (Config, error) {
// - set some defaults if they weren't previously specified
// TODO: add better validation, more explicit default values and improve consistency between formats
// TODO: accumulate all errors and differentiate between the layers?
func getConsolidatedConfig(globalState *globalState, cliConf Config, runnerOpts lib.Options) (conf Config, err error) {
func getConsolidatedConfig(gs *state.GlobalState, cliConf Config, runnerOpts lib.Options) (conf Config, err error) {
// TODO: use errext.WithExitCodeIfNone(err, exitcodes.InvalidConfig) where it makes sense?

fileConf, err := readDiskConfig(globalState)
fileConf, err := readDiskConfig(gs)
if err != nil {
return conf, err
}
envConf, err := readEnvConfig(globalState.envVars)
envConf, err := readEnvConfig(gs.Env)
if err != nil {
return conf, err
}
Expand Down
Loading

0 comments on commit f223cd5

Please sign in to comment.