github.com/clusterize-io/tusk@v0.6.3-0.20211001020217-cfe8a8cd0d4a/appcli/app_test.go (about)

     1  package appcli
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"os/exec"
     9  	"path/filepath"
    10  	"reflect"
    11  	"syscall"
    12  	"testing"
    13  
    14  	"github.com/clusterize-io/tusk/runner"
    15  	"github.com/clusterize-io/tusk/ui"
    16  	"github.com/urfave/cli"
    17  )
    18  
    19  func TestNewFlagApp(t *testing.T) {
    20  	cfgText := []byte(`options:
    21    foo:
    22      short: f
    23      default: foovalue
    24  
    25  tasks:
    26    mytask:
    27      run: echo ${foo}
    28  `)
    29  
    30  	flagApp, err := newMetaApp(cfgText)
    31  	if err != nil {
    32  		t.Fatalf(
    33  			"newFlagApp():\nconfig: `%s`\nunexpected err: %s",
    34  			string(cfgText), err,
    35  		)
    36  	}
    37  
    38  	args := []string{"tusk", "mytask", "--foo", "other"}
    39  	if err = flagApp.Run(args); err != nil {
    40  		t.Fatalf(
    41  			"flagApp.Run():\nconfig: `%s`\nunexpected err: %s",
    42  			string(cfgText), err,
    43  		)
    44  	}
    45  
    46  	command, ok := flagApp.Metadata["command"].(*cli.Command)
    47  	if !ok {
    48  		t.Fatalf(
    49  			"flagApp.Metadata:\nconfig: `%s`\nMetadata command not a *cli.Command: %#v",
    50  			string(cfgText), flagApp.Metadata["command"],
    51  		)
    52  	}
    53  
    54  	commandName := command.Name
    55  	commandExpected := "mytask"
    56  
    57  	if commandExpected != commandName {
    58  		t.Errorf(
    59  			"flagApp.Metadata[\"command\"] for args(%s):\n expected: %s\nactual: %s",
    60  			args, commandExpected, commandName,
    61  		)
    62  	}
    63  
    64  	flagsActual, ok := flagApp.Metadata["flagsPassed"].(map[string]string)
    65  	if !ok {
    66  		t.Fatalf(
    67  			"flagApp.Metadata:\nconfig: `%s`\nMetadata flagsPassed not a map: %#v",
    68  			string(cfgText), flagApp.Metadata["flagsPassed"],
    69  		)
    70  	}
    71  
    72  	flagsExpected := map[string]string{
    73  		"foo": "other",
    74  	}
    75  
    76  	if !reflect.DeepEqual(flagsExpected, flagsActual) {
    77  		t.Errorf(
    78  			"flagApp.Metadata for args(%s):\n expected: %#v\nactual: %#v",
    79  			args, flagsExpected, flagsActual,
    80  		)
    81  	}
    82  }
    83  
    84  func TestNewFlagApp_no_options(t *testing.T) {
    85  	cfgText := []byte(`tasks:
    86    mytask:
    87      run: echo foo
    88  `)
    89  
    90  	flagApp, err := newMetaApp(cfgText)
    91  	if err != nil {
    92  		t.Fatalf(
    93  			"newFlagApp():\nconfig: `%s`\nunexpected err: %s",
    94  			string(cfgText), err,
    95  		)
    96  	}
    97  
    98  	args := []string{"tusk", "mytask"}
    99  	if err = flagApp.Run(args); err != nil {
   100  		t.Fatalf(
   101  			"flagApp.Run():\nconfig: `%s`\nunexpected err: %s",
   102  			string(cfgText), err,
   103  		)
   104  	}
   105  
   106  	command, ok := flagApp.Metadata["command"].(*cli.Command)
   107  	if !ok {
   108  		t.Fatalf(
   109  			"flagApp.Metadata:\nconfig: `%s`\nMetadata command not a *cli.Command: %#v",
   110  			string(cfgText), flagApp.Metadata["command"],
   111  		)
   112  	}
   113  
   114  	commandName := command.Name
   115  	commandExpected := "mytask"
   116  
   117  	if commandExpected != commandName {
   118  		t.Errorf(
   119  			"flagApp.Metadata[\"command\"] for args(%s):\n expected: %s\nactual: %s",
   120  			args, commandExpected, commandName,
   121  		)
   122  	}
   123  
   124  	flagsActual, ok := flagApp.Metadata["flagsPassed"].(map[string]string)
   125  	if !ok {
   126  		t.Fatalf(
   127  			"flagApp.Metadata:\nconfig: `%s`\nMetadata flagsPassed not a map: %#v",
   128  			string(cfgText), flagApp.Metadata["flagsPassed"],
   129  		)
   130  	}
   131  
   132  	flagsExpected := map[string]string{}
   133  
   134  	if !reflect.DeepEqual(flagsExpected, flagsActual) {
   135  		t.Errorf(
   136  			"flagApp.Metadata for args(%s):\n expected: %#v\nactual: %#v",
   137  			args, flagsExpected, flagsActual,
   138  		)
   139  	}
   140  }
   141  
   142  func TestNewApp(t *testing.T) {
   143  	taskName := "foo"
   144  	name := "new-name"
   145  	usage := "new usage"
   146  	args := []string{"tusk", taskName}
   147  
   148  	cfgText := []byte(fmt.Sprintf(`
   149  name: %s
   150  usage: %s
   151  tasks: { %q: {} }
   152  `,
   153  		name, usage, taskName,
   154  	))
   155  	meta := &runner.Metadata{CfgText: cfgText}
   156  
   157  	app, err := NewApp(args, meta)
   158  	if err != nil {
   159  		t.Errorf("NewApp(): unexpected error: %v", err)
   160  	}
   161  
   162  	if len(app.Commands) != 1 {
   163  		t.Errorf(
   164  			"For config: `%s`\nexpected 1 command, got %#v",
   165  			string(cfgText), app.Commands,
   166  		)
   167  	}
   168  
   169  	if name != app.Name {
   170  		t.Errorf(
   171  			`NewApp().name => %q, want %q`,
   172  			app.Name, name,
   173  		)
   174  	}
   175  
   176  	if usage != app.Usage {
   177  		t.Errorf(
   178  			`NewApp().usage => %q, want %q`,
   179  			app.Usage, usage,
   180  		)
   181  	}
   182  }
   183  
   184  func TestNewApp_exit_code(t *testing.T) {
   185  	args := []string{"tusk", "foo"}
   186  	expectedCode := 99
   187  	cfgText := []byte(`
   188  tasks:
   189    foo:
   190      run: exit 99`)
   191  	meta := &runner.Metadata{
   192  		CfgText: cfgText,
   193  		Logger:  ui.Noop(),
   194  	}
   195  
   196  	app, err := NewApp(args, meta)
   197  	if err != nil {
   198  		t.Errorf("NewApp(): unexpected error: %v", err)
   199  	}
   200  
   201  	if len(app.Commands) != 1 {
   202  		t.Fatalf(
   203  			"For config: `%s`\nexpected 1 command, got %#v",
   204  			string(cfgText), app.Commands,
   205  		)
   206  	}
   207  
   208  	exitErr, ok := app.Run(args).(*exec.ExitError)
   209  	if !ok {
   210  		t.Fatalf("app.Run(%v): expected exit err, got %#v", args, err)
   211  	}
   212  
   213  	if actual := exitErr.Sys().(syscall.WaitStatus).ExitStatus(); actual != expectedCode {
   214  		t.Fatalf("app.Run(%v): expected error code 99, actual: %d", args, actual)
   215  	}
   216  }
   217  
   218  func TestNewApp_private_task(t *testing.T) {
   219  	args := []string{"tusk", "public"}
   220  	expectedCode := 99
   221  	cfgText := []byte(`
   222  tasks:
   223    private:
   224      private: true
   225      run: exit 99
   226    public:
   227      run: {task: private}`)
   228  	meta := &runner.Metadata{
   229  		CfgText: cfgText,
   230  		Logger:  ui.Noop(),
   231  	}
   232  
   233  	app, err := NewApp(args, meta)
   234  	if err != nil {
   235  		t.Errorf("NewApp(): unexpected error: %v", err)
   236  	}
   237  
   238  	if len(app.Commands) != 1 {
   239  		t.Fatalf(
   240  			"For config: `%s`\nexpected 1 command, got %#v",
   241  			string(cfgText), app.Commands,
   242  		)
   243  	}
   244  
   245  	// Ensure private task still runs as subtask
   246  	exitErr, ok := app.Run(args).(*exec.ExitError)
   247  	if !ok {
   248  		t.Fatalf("app.Run(%v): expected exit err, got %#v", args, err)
   249  	}
   250  
   251  	if actual := exitErr.Sys().(syscall.WaitStatus).ExitStatus(); actual != expectedCode {
   252  		t.Fatalf("app.Run(%v): expected error code 99, actual: %d", args, actual)
   253  	}
   254  }
   255  
   256  func TestNewApp_fails_bad_config(t *testing.T) {
   257  	args := []string{"tusk"}
   258  	cfgText := []byte(`invalid`)
   259  	meta := &runner.Metadata{CfgText: cfgText}
   260  	_, err := NewApp(args, meta)
   261  	if err == nil {
   262  		t.Fatal("expected error for invalid config text")
   263  	}
   264  }
   265  
   266  func TestNewApp_fails_bad_flag(t *testing.T) {
   267  	args := []string{"tusk", "--invalid"}
   268  	cfgText := []byte{}
   269  	meta := &runner.Metadata{CfgText: cfgText}
   270  	_, err := NewApp(args, meta)
   271  	if err == nil {
   272  		t.Fatal("expected error for invalid flag")
   273  	}
   274  }
   275  
   276  func TestGetConfigMetadata_defaults(t *testing.T) {
   277  	args := []string{"tusk"}
   278  
   279  	metadata, err := GetConfigMetadata(args)
   280  	if err != nil {
   281  		t.Fatalf(
   282  			"GetConfigMetadata(%s): unexpected err: %s",
   283  			args, err,
   284  		)
   285  	}
   286  
   287  	// The project's tuskfile should be found in the project root.
   288  	wd, err := os.Getwd()
   289  	if err != nil {
   290  		t.Fatalf("os.Getwd(): unexpected err: %s", err)
   291  	}
   292  
   293  	directory := filepath.Dir(wd)
   294  	if directory != metadata.Directory {
   295  		t.Errorf(
   296  			"GetConfigMetadata(%s): expected Directory: %s, actual: %s",
   297  			args, directory, metadata.Directory,
   298  		)
   299  	}
   300  
   301  	if metadata.PrintVersion {
   302  		t.Errorf(
   303  			"GetConfigMetadata(%s): expected RunVersion: false, actual: true",
   304  			args,
   305  		)
   306  	}
   307  
   308  	if metadata.Logger.Verbosity != ui.VerbosityLevelNormal {
   309  		t.Errorf(
   310  			"GetConfigMetadata(%s): expected: %s, actual: %s",
   311  			args,
   312  			ui.VerbosityLevelNormal,
   313  			metadata.Logger.Verbosity,
   314  		)
   315  	}
   316  }
   317  
   318  func TestGetConfigMetadata_file(t *testing.T) {
   319  	cfgPath := "testdata/example.yml"
   320  	args := []string{"tusk", "--file", cfgPath}
   321  
   322  	metadata, err := GetConfigMetadata(args)
   323  	if err != nil {
   324  		t.Fatalf(
   325  			"GetConfigMetadata(%s): unexpected err: %s",
   326  			args, err,
   327  		)
   328  	}
   329  
   330  	directory := "testdata"
   331  
   332  	if directory != metadata.Directory {
   333  		t.Errorf(
   334  			"GetConfigMetadata(%s): expected Directory: %s, actual: %s",
   335  			args, directory, metadata.Directory,
   336  		)
   337  	}
   338  
   339  	cfgText, err := ioutil.ReadFile(cfgPath)
   340  	if err != nil {
   341  		t.Fatalf(
   342  			"ioutil.ReadFile(%s): unexpected err: %s",
   343  			cfgPath, err,
   344  		)
   345  	}
   346  
   347  	expected := string(cfgText)
   348  	actual := string(metadata.CfgText)
   349  
   350  	if expected != actual {
   351  		t.Errorf(
   352  			"GetConfigMetadata(%s):\nexpected config text: %s\nactual: %s",
   353  			args, expected, actual,
   354  		)
   355  	}
   356  }
   357  
   358  func TestGetConfigMetadata_fileNoExist(t *testing.T) {
   359  	args := []string{"tusk", "--file", "fakefile.yml"}
   360  
   361  	_, err := GetConfigMetadata(args)
   362  	if !errors.Is(err, os.ErrNotExist) {
   363  		t.Errorf(
   364  			"GetConfigMetadata(%s): unexpected err: os.IsNotExist, actual: %s",
   365  			args, err,
   366  		)
   367  	}
   368  }
   369  
   370  func TestGetConfigMetadata_version(t *testing.T) {
   371  	args := []string{"tusk", "--version"}
   372  
   373  	metadata, err := GetConfigMetadata(args)
   374  	if err != nil {
   375  		t.Fatalf(
   376  			"GetConfigMetadata(%s):\nunexpected err: %s",
   377  			args, err,
   378  		)
   379  	}
   380  
   381  	if !metadata.PrintVersion {
   382  		t.Errorf(
   383  			"GetConfigMetadata(%s): expected RunVersion: true, actual: false",
   384  			args,
   385  		)
   386  	}
   387  }
   388  
   389  var verbosityFlagTests = []struct {
   390  	args     []string
   391  	expected ui.VerbosityLevel
   392  }{
   393  	{
   394  		[]string{"tusk"},
   395  		ui.VerbosityLevelNormal,
   396  	},
   397  	{
   398  		[]string{"tusk", "--silent"},
   399  		ui.VerbosityLevelSilent,
   400  	},
   401  	{
   402  		[]string{"tusk", "--quiet"},
   403  		ui.VerbosityLevelQuiet,
   404  	},
   405  	{
   406  		[]string{"tusk", "--verbose"},
   407  		ui.VerbosityLevelVerbose,
   408  	},
   409  	{
   410  		[]string{"tusk", "--quiet", "--verbose"},
   411  		ui.VerbosityLevelQuiet,
   412  	},
   413  	{
   414  		[]string{"tusk", "--silent", "--quiet"},
   415  		ui.VerbosityLevelSilent,
   416  	},
   417  	{
   418  		[]string{"tusk", "--silent", "--verbose"},
   419  		ui.VerbosityLevelSilent,
   420  	},
   421  	{
   422  		[]string{"tusk", "--silent", "--quiet", "--verbose"},
   423  		ui.VerbosityLevelSilent,
   424  	},
   425  }
   426  
   427  func TestGetConfigMetadata_verbosity(t *testing.T) {
   428  	for _, tt := range verbosityFlagTests {
   429  		metadata, err := GetConfigMetadata(tt.args)
   430  		if err != nil {
   431  			t.Errorf(
   432  				"GetConfigMetadata(%s):\nunexpected err: %s",
   433  				tt.args, err,
   434  			)
   435  			continue
   436  		}
   437  
   438  		if metadata.Logger.Verbosity != tt.expected {
   439  			t.Errorf(
   440  				"GetConfigMetadata(%s): expected %s, actual: %s",
   441  				tt.args,
   442  				tt.expected,
   443  				metadata.Logger.Verbosity,
   444  			)
   445  		}
   446  	}
   447  }