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

     1  package runner
     2  
     3  import (
     4  	"os"
     5  	"reflect"
     6  	"testing"
     7  
     8  	"github.com/clusterize-io/tusk/marshal"
     9  	yaml "gopkg.in/yaml.v2"
    10  )
    11  
    12  func TestOption_Dependencies(t *testing.T) {
    13  	option := &Option{DefaultValues: ValueList{
    14  		{When: WhenList{whenFalse}, Value: "foo"},
    15  		{When: WhenList{createWhen(
    16  			withWhenEqual("foo", "foovalue"),
    17  			withWhenEqual("bar", "barvalue"),
    18  		)}, Value: "bar"},
    19  		{When: WhenList{createWhen(
    20  			withWhenNotEqual("baz", "bazvalue"),
    21  		)}, Value: "bar"},
    22  	}}
    23  
    24  	expected := []string{"foo", "bar", "baz"}
    25  	actual := option.Dependencies()
    26  	if !equalUnordered(expected, actual) {
    27  		t.Errorf(
    28  			"Option.Dependencies(): expected %s, actual %s",
    29  			expected, actual,
    30  		)
    31  	}
    32  }
    33  
    34  func equalUnordered(a, b []string) bool {
    35  	if len(a) != len(b) {
    36  		return false
    37  	}
    38  
    39  	aMap := make(map[string]interface{})
    40  	for _, val := range a {
    41  		aMap[val] = struct{}{}
    42  	}
    43  
    44  	bMap := make(map[string]interface{})
    45  	for _, val := range b {
    46  		bMap[val] = struct{}{}
    47  	}
    48  
    49  	return reflect.DeepEqual(aMap, bMap)
    50  }
    51  
    52  // Env var `OPTION_VAR` will be set to `option_val`
    53  var valuetests = []struct {
    54  	desc     string
    55  	input    *Option
    56  	expected string
    57  }{
    58  	{"nil", nil, ""},
    59  	{"empty option", &Option{}, ""},
    60  	{
    61  		"default only",
    62  		&Option{DefaultValues: ValueList{
    63  			{Value: "default"},
    64  		}},
    65  		"default",
    66  	},
    67  	{
    68  		"command only",
    69  		&Option{DefaultValues: ValueList{
    70  			{Command: "echo command"},
    71  		}},
    72  		"command",
    73  	},
    74  	{
    75  		"environment variable only",
    76  		&Option{Environment: "OPTION_VAR"},
    77  		"option_val",
    78  	},
    79  	{
    80  		"passed variable only",
    81  		&Option{Passed: "passed"},
    82  		"passed",
    83  	},
    84  	{
    85  		"conditional value",
    86  		&Option{DefaultValues: ValueList{
    87  			{When: WhenList{whenFalse}, Value: "foo"},
    88  			{When: WhenList{whenTrue}, Value: "bar"},
    89  			{When: WhenList{whenFalse}, Value: "baz"},
    90  		}},
    91  		"bar",
    92  	},
    93  	{
    94  		"passed when all settings are defined",
    95  		&Option{
    96  			Environment: "OPTION_VAR",
    97  			DefaultValues: ValueList{
    98  				{When: WhenList{whenTrue}, Value: "when"},
    99  			},
   100  			Passed: "passed",
   101  		},
   102  		"passed",
   103  	},
   104  }
   105  
   106  func TestOption_Evaluate(t *testing.T) {
   107  	if err := os.Setenv("OPTION_VAR", "option_val"); err != nil {
   108  		t.Fatalf("unexpected err setting environment variable: %s", err)
   109  	}
   110  
   111  	for _, tt := range valuetests {
   112  		actual, err := tt.input.Evaluate(Context{}, nil)
   113  		if err != nil {
   114  			t.Errorf(
   115  				"Option.Evaluate() for %s: unexpected err: %q",
   116  				tt.desc, err,
   117  			)
   118  			continue
   119  		}
   120  
   121  		if tt.expected != actual {
   122  			t.Errorf(
   123  				"Option.Evaluate() for %s: expected %q, actual %q",
   124  				tt.desc, tt.expected, actual,
   125  			)
   126  		}
   127  	}
   128  }
   129  
   130  func TestOption_Evaluate_required_nothing_passed(t *testing.T) {
   131  	option := Option{Required: true}
   132  
   133  	if _, err := option.Evaluate(Context{}, nil); err == nil {
   134  		t.Fatal(
   135  			"Option.Evaluate() for required option: expected err, actual nil",
   136  		)
   137  	}
   138  }
   139  
   140  func TestOption_Evaluate_passes_vars(t *testing.T) {
   141  	expected := "some value"
   142  	opt := Option{
   143  		DefaultValues: ValueList{
   144  			{When: WhenList{whenFalse}, Value: "wrong"},
   145  			{
   146  				When:  WhenList{createWhen(withWhenEqual("foo", "foovalue"))},
   147  				Value: expected,
   148  			},
   149  			{When: WhenList{whenFalse}, Value: "oops"},
   150  		},
   151  	}
   152  
   153  	actual, err := opt.Evaluate(Context{}, map[string]string{"foo": "foovalue"})
   154  	if err != nil {
   155  		t.Fatalf("Option.Evaluate(): unexpected error: %s", err)
   156  	}
   157  
   158  	if expected != actual {
   159  		t.Errorf(
   160  			"Option.Evaluate(): expected %q, actual %q",
   161  			expected, actual,
   162  		)
   163  	}
   164  }
   165  
   166  func TestOption_Evaluate_required_with_passed(t *testing.T) {
   167  	expected := "foo"
   168  	option := Option{Required: true, Passed: expected}
   169  
   170  	actual, err := option.Evaluate(Context{}, nil)
   171  	if err != nil {
   172  		t.Fatalf("Option.Evaluate(): unexpected error: %s", err)
   173  	}
   174  
   175  	if expected != actual {
   176  		t.Errorf(
   177  			"Option.Evaluate(): expected %q, actual %q",
   178  			expected, actual,
   179  		)
   180  	}
   181  }
   182  
   183  func TestOption_Evaluate_required_with_environment(t *testing.T) {
   184  	envVar := "OPTION_VAR"
   185  	expected := "foo"
   186  
   187  	option := Option{Required: true, Environment: envVar}
   188  	if err := os.Setenv(envVar, expected); err != nil {
   189  		t.Fatalf("unexpected err setting environment variable: %s", err)
   190  	}
   191  
   192  	actual, err := option.Evaluate(Context{}, nil)
   193  	if err != nil {
   194  		t.Fatalf("Option.Evaluate(): unexpected error: %s", err)
   195  	}
   196  
   197  	if expected != actual {
   198  		t.Errorf(
   199  			"Option.Evaluate(): expected %q, actual %q",
   200  			expected, actual,
   201  		)
   202  	}
   203  }
   204  
   205  func TestOption_Evaluate_values_none_specified(t *testing.T) {
   206  	expected := ""
   207  	option := Option{
   208  		ValueWithList: ValueWithList{
   209  			ValuesAllowed: marshal.StringList{"red", "herring"},
   210  		},
   211  	}
   212  
   213  	actual, err := option.Evaluate(Context{}, nil)
   214  	if err != nil {
   215  		t.Fatalf("Option.Evaluate(): unexpected error: %s", err)
   216  	}
   217  
   218  	if expected != actual {
   219  		t.Errorf(
   220  			"Option.Evaluate(): expected %q, actual %q",
   221  			expected, actual,
   222  		)
   223  	}
   224  }
   225  
   226  func TestOption_Evaluate_values_with_passed(t *testing.T) {
   227  	expected := "foo"
   228  	option := Option{
   229  		Passed: expected,
   230  		ValueWithList: ValueWithList{
   231  			ValuesAllowed: marshal.StringList{"red", expected, "herring"},
   232  		},
   233  	}
   234  
   235  	actual, err := option.Evaluate(Context{}, nil)
   236  	if err != nil {
   237  		t.Fatalf("Option.Evaluate(): unexpected error: %s", err)
   238  	}
   239  
   240  	if expected != actual {
   241  		t.Errorf(
   242  			"Option.Evaluate(): expected %q, actual %q",
   243  			expected, actual,
   244  		)
   245  	}
   246  }
   247  
   248  func TestOption_Evaluate_values_with_environment(t *testing.T) {
   249  	envVar := "OPTION_VAR"
   250  	expected := "foo"
   251  
   252  	option := Option{
   253  		Environment: envVar,
   254  		ValueWithList: ValueWithList{
   255  			ValuesAllowed: marshal.StringList{"red", expected, "herring"},
   256  		},
   257  	}
   258  
   259  	if err := os.Setenv(envVar, expected); err != nil {
   260  		t.Fatalf("unexpected err setting environment variable: %s", err)
   261  	}
   262  
   263  	actual, err := option.Evaluate(Context{}, nil)
   264  	if err != nil {
   265  		t.Fatalf("Option.Evaluate(): unexpected error: %s", err)
   266  	}
   267  
   268  	if expected != actual {
   269  		t.Errorf(
   270  			"Option.Evaluate(): expected %q, actual %q",
   271  			expected, actual,
   272  		)
   273  	}
   274  }
   275  
   276  func TestOption_Evaluate_values_with_invalid_passed(t *testing.T) {
   277  	expected := "foo"
   278  	option := Option{
   279  		Passed: expected,
   280  		ValueWithList: ValueWithList{
   281  			ValuesAllowed: marshal.StringList{"bad", "values", "FOO"},
   282  		},
   283  	}
   284  
   285  	_, err := option.Evaluate(Context{}, nil)
   286  	if err == nil {
   287  		t.Fatalf(
   288  			"Option.Evaluate(): expected error for invalid passed value, got nil",
   289  		)
   290  	}
   291  }
   292  
   293  func TestOption_Evaluate_values_with_invalid_environment(t *testing.T) {
   294  	envVar := "OPTION_VAR"
   295  	expected := "foo"
   296  
   297  	option := Option{
   298  		Environment: envVar,
   299  		ValueWithList: ValueWithList{
   300  			ValuesAllowed: marshal.StringList{"bad", "values", "FOO"},
   301  		},
   302  	}
   303  
   304  	if err := os.Setenv(envVar, expected); err != nil {
   305  		t.Fatalf("unexpected err setting environment variable: %s", err)
   306  	}
   307  
   308  	_, err := option.Evaluate(Context{}, nil)
   309  	if err == nil {
   310  		t.Fatalf(
   311  			"Option.Evaluate(): expected error for invalid environment value, got nil",
   312  		)
   313  	}
   314  }
   315  
   316  var evaluteTypeDefaultTests = []struct {
   317  	typeName string
   318  	expected string
   319  }{
   320  	{"int", "0"},
   321  	{"INTEGER", "0"},
   322  	{"Float", "0"},
   323  	{"float64", "0"},
   324  	{"double", "0"},
   325  	{"bool", "false"},
   326  	{"boolean", "false"},
   327  	{"", ""},
   328  }
   329  
   330  func TestOption_Evaluate_type_defaults(t *testing.T) {
   331  	for _, tt := range evaluteTypeDefaultTests {
   332  		opt := Option{Type: tt.typeName}
   333  		actual, err := opt.Evaluate(Context{}, nil)
   334  		if err != nil {
   335  			t.Errorf("Option.Evaluate(): unexpected error: %s", err)
   336  			continue
   337  		}
   338  
   339  		if tt.expected != actual {
   340  			t.Errorf(
   341  				"Option.Evaluate(): expected %q, actual %q",
   342  				tt.expected, actual,
   343  			)
   344  		}
   345  	}
   346  }
   347  
   348  func TestOption_UnmarshalYAML(t *testing.T) {
   349  	s := []byte(`{usage: foo, values: [foo, bar]}`)
   350  	expected := Option{
   351  		Usage: "foo",
   352  		ValueWithList: ValueWithList{
   353  			ValuesAllowed: []string{"foo", "bar"},
   354  		},
   355  		Name: "",
   356  	}
   357  	actual := Option{}
   358  
   359  	if err := yaml.UnmarshalStrict(s, &actual); err != nil {
   360  		t.Fatalf("yaml.UnmarshalStrict(%s, ...): unexpected error: %s", s, err)
   361  	}
   362  
   363  	if !reflect.DeepEqual(expected, actual) {
   364  		t.Errorf(
   365  			`yaml.UnmarshalStrict(%s, ...): expected "%#v", actual "%#v"`,
   366  			s, expected, actual,
   367  		)
   368  	}
   369  }
   370  
   371  var unmarshalOptionErrorTests = []struct {
   372  	desc  string
   373  	input string
   374  }{
   375  	{
   376  		"invalid option definition",
   377  		"string only",
   378  	},
   379  	{
   380  		"short name exceeds one character",
   381  		"{short: foo}",
   382  	},
   383  	{
   384  		"private and required defined",
   385  		"{private: true, required: true}",
   386  	},
   387  	{
   388  		"private and environment defined",
   389  		"{private: true, environment: ENV_VAR}",
   390  	},
   391  	{
   392  		"private and values defined",
   393  		"{private: true, values: [foo, bar]}",
   394  	},
   395  	{
   396  		"required and default defined",
   397  		"{required: true, default: foo}",
   398  	},
   399  }
   400  
   401  func TestOption_UnmarshalYAML_invalid_definitions(t *testing.T) {
   402  	for _, tt := range unmarshalOptionErrorTests {
   403  		o := Option{}
   404  		if err := yaml.UnmarshalStrict([]byte(tt.input), &o); err == nil {
   405  			t.Errorf(
   406  				"yaml.UnmarshalStrict(%s, ...): expected error for %s, actual nil",
   407  				tt.input, tt.desc,
   408  			)
   409  		}
   410  	}
   411  }
   412  
   413  func TestGetOptionsWithOrder(t *testing.T) {
   414  	name := "foo"
   415  	env := "fooenv"
   416  	ms := yaml.MapSlice{
   417  		{Key: name, Value: &Option{Environment: env}},
   418  		{Key: "bar", Value: &Option{Environment: "barenv"}},
   419  	}
   420  
   421  	options, err := getOptionsWithOrder(ms)
   422  	if err != nil {
   423  		t.Fatalf("GetOptionsWithOrder(ms) => unexpected error: %v", err)
   424  	}
   425  
   426  	if len(ms) != len(options) {
   427  		t.Fatalf(
   428  			"GetOptionsWithOrder(ms) => want %d items, got %d",
   429  			len(ms), len(options),
   430  		)
   431  	}
   432  
   433  	opt := options[0]
   434  
   435  	if name != opt.Name {
   436  		t.Errorf(
   437  			"GetOptionsWithOrder(ms) => want opt.Name %q, got %q",
   438  			name, opt.Name,
   439  		)
   440  	}
   441  
   442  	if env != opt.Environment {
   443  		t.Errorf(
   444  			"GetOptionsWithOrder(ms) => want opt.Environment %q, got %q",
   445  			env, opt.Environment,
   446  		)
   447  	}
   448  
   449  	if options[1].Name != "bar" {
   450  		t.Errorf("GetOptionsWithOrder(ms) => want 2nd option %q, got %q", "bar", options[1].Name)
   451  	}
   452  }