github.com/ferranbt/nomad@v0.9.3-0.20190607002617-85c449b7667c/plugins/shared/structs/attribute_test.go (about)

     1  package structs
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	"github.com/hashicorp/nomad/helper"
     8  	"github.com/stretchr/testify/require"
     9  )
    10  
    11  func TestAttribute_Validate(t *testing.T) {
    12  	cases := []struct {
    13  		Input *Attribute
    14  		Fail  bool
    15  	}{
    16  		{
    17  			Input: &Attribute{
    18  				Bool: helper.BoolToPtr(true),
    19  			},
    20  		},
    21  		{
    22  			Input: &Attribute{
    23  				String: helper.StringToPtr("foo"),
    24  			},
    25  		},
    26  		{
    27  			Input: &Attribute{
    28  				Int: helper.Int64ToPtr(123),
    29  			},
    30  		},
    31  		{
    32  			Input: &Attribute{
    33  				Float: helper.Float64ToPtr(123.2),
    34  			},
    35  		},
    36  		{
    37  			Input: &Attribute{
    38  				Bool: helper.BoolToPtr(true),
    39  				Unit: "MB",
    40  			},
    41  			Fail: true,
    42  		},
    43  		{
    44  			Input: &Attribute{
    45  				String: helper.StringToPtr("foo"),
    46  				Unit:   "MB",
    47  			},
    48  			Fail: true,
    49  		},
    50  		{
    51  			Input: &Attribute{
    52  				Int:  helper.Int64ToPtr(123),
    53  				Unit: "lolNO",
    54  			},
    55  			Fail: true,
    56  		},
    57  		{
    58  			Input: &Attribute{
    59  				Float: helper.Float64ToPtr(123.2),
    60  				Unit:  "lolNO",
    61  			},
    62  			Fail: true,
    63  		},
    64  		{
    65  			Input: &Attribute{
    66  				Int:   helper.Int64ToPtr(123),
    67  				Float: helper.Float64ToPtr(123.2),
    68  				Unit:  "mW",
    69  			},
    70  			Fail: true,
    71  		},
    72  	}
    73  
    74  	for _, c := range cases {
    75  		t.Run(c.Input.GoString(), func(t *testing.T) {
    76  			if err := c.Input.Validate(); err != nil && !c.Fail {
    77  				require.NoError(t, err)
    78  			}
    79  		})
    80  	}
    81  }
    82  
    83  type compareTestCase struct {
    84  	A             *Attribute
    85  	B             *Attribute
    86  	Expected      int
    87  	NotComparable bool
    88  }
    89  
    90  func TestAttribute_Compare_Bool(t *testing.T) {
    91  	cases := []*compareTestCase{
    92  		{
    93  			A: &Attribute{
    94  				Bool: helper.BoolToPtr(true),
    95  			},
    96  			B: &Attribute{
    97  				Bool: helper.BoolToPtr(true),
    98  			},
    99  			Expected: 0,
   100  		},
   101  		{
   102  			A: &Attribute{
   103  				Bool: helper.BoolToPtr(true),
   104  			},
   105  			B: &Attribute{
   106  				Bool: helper.BoolToPtr(false),
   107  			},
   108  			Expected: 1,
   109  		},
   110  		{
   111  			A: &Attribute{
   112  				Bool: helper.BoolToPtr(true),
   113  			},
   114  			B: &Attribute{
   115  				String: helper.StringToPtr("foo"),
   116  			},
   117  			NotComparable: true,
   118  		},
   119  		{
   120  			A: &Attribute{
   121  				Bool: helper.BoolToPtr(true),
   122  			},
   123  			B: &Attribute{
   124  				Int: helper.Int64ToPtr(123),
   125  			},
   126  			NotComparable: true,
   127  		},
   128  		{
   129  			A: &Attribute{
   130  				Bool: helper.BoolToPtr(true),
   131  			},
   132  			B: &Attribute{
   133  				Float: helper.Float64ToPtr(123.2),
   134  			},
   135  			NotComparable: true,
   136  		},
   137  	}
   138  	testComparison(t, cases)
   139  }
   140  
   141  func TestAttribute_Compare_String(t *testing.T) {
   142  	cases := []*compareTestCase{
   143  		{
   144  			A: &Attribute{
   145  				String: helper.StringToPtr("a"),
   146  			},
   147  			B: &Attribute{
   148  				String: helper.StringToPtr("b"),
   149  			},
   150  			Expected: -1,
   151  		},
   152  		{
   153  			A: &Attribute{
   154  				String: helper.StringToPtr("hello"),
   155  			},
   156  			B: &Attribute{
   157  				String: helper.StringToPtr("hello"),
   158  			},
   159  			Expected: 0,
   160  		},
   161  		{
   162  			A: &Attribute{
   163  				String: helper.StringToPtr("b"),
   164  			},
   165  			B: &Attribute{
   166  				String: helper.StringToPtr("a"),
   167  			},
   168  			Expected: 1,
   169  		},
   170  		{
   171  			A: &Attribute{
   172  				String: helper.StringToPtr("hello"),
   173  			},
   174  			B: &Attribute{
   175  				Bool: helper.BoolToPtr(true),
   176  			},
   177  			NotComparable: true,
   178  		},
   179  		{
   180  			A: &Attribute{
   181  				String: helper.StringToPtr("hello"),
   182  			},
   183  			B: &Attribute{
   184  				Int: helper.Int64ToPtr(123),
   185  			},
   186  			NotComparable: true,
   187  		},
   188  		{
   189  			A: &Attribute{
   190  				String: helper.StringToPtr("hello"),
   191  			},
   192  			B: &Attribute{
   193  				Float: helper.Float64ToPtr(123.2),
   194  			},
   195  			NotComparable: true,
   196  		},
   197  	}
   198  	testComparison(t, cases)
   199  }
   200  
   201  func TestAttribute_Compare_Float(t *testing.T) {
   202  	cases := []*compareTestCase{
   203  		{
   204  			A: &Attribute{
   205  				Float: helper.Float64ToPtr(101.5),
   206  			},
   207  			B: &Attribute{
   208  				Float: helper.Float64ToPtr(100001.5),
   209  			},
   210  			Expected: -1,
   211  		},
   212  		{
   213  			A: &Attribute{
   214  				Float: helper.Float64ToPtr(100001.5),
   215  			},
   216  			B: &Attribute{
   217  				Float: helper.Float64ToPtr(100001.5),
   218  			},
   219  			Expected: 0,
   220  		},
   221  		{
   222  			A: &Attribute{
   223  				Float: helper.Float64ToPtr(999999999.5),
   224  			},
   225  			B: &Attribute{
   226  				Float: helper.Float64ToPtr(101.5),
   227  			},
   228  			Expected: 1,
   229  		},
   230  		{
   231  			A: &Attribute{
   232  				Float: helper.Float64ToPtr(101.5),
   233  			},
   234  			B: &Attribute{
   235  				Bool: helper.BoolToPtr(true),
   236  			},
   237  			NotComparable: true,
   238  		},
   239  		{
   240  			A: &Attribute{
   241  				Float: helper.Float64ToPtr(101.5),
   242  			},
   243  			B: &Attribute{
   244  				String: helper.StringToPtr("hello"),
   245  			},
   246  			NotComparable: true,
   247  		},
   248  	}
   249  	testComparison(t, cases)
   250  }
   251  
   252  func TestAttribute_Compare_Int(t *testing.T) {
   253  	cases := []*compareTestCase{
   254  		{
   255  			A: &Attribute{
   256  				Int: helper.Int64ToPtr(3),
   257  			},
   258  			B: &Attribute{
   259  				Int: helper.Int64ToPtr(10),
   260  			},
   261  			Expected: -1,
   262  		},
   263  		{
   264  			A: &Attribute{
   265  				Int: helper.Int64ToPtr(10),
   266  			},
   267  			B: &Attribute{
   268  				Int: helper.Int64ToPtr(10),
   269  			},
   270  			Expected: 0,
   271  		},
   272  		{
   273  			A: &Attribute{
   274  				Int: helper.Int64ToPtr(100),
   275  			},
   276  			B: &Attribute{
   277  				Int: helper.Int64ToPtr(10),
   278  			},
   279  			Expected: 1,
   280  		},
   281  		{
   282  			A: &Attribute{
   283  				Int: helper.Int64ToPtr(10),
   284  			},
   285  			B: &Attribute{
   286  				Bool: helper.BoolToPtr(true),
   287  			},
   288  			NotComparable: true,
   289  		},
   290  		{
   291  			A: &Attribute{
   292  				Int: helper.Int64ToPtr(10),
   293  			},
   294  			B: &Attribute{
   295  				String: helper.StringToPtr("hello"),
   296  			},
   297  			NotComparable: true,
   298  		},
   299  	}
   300  	testComparison(t, cases)
   301  }
   302  
   303  func TestAttribute_Compare_Int_With_Units(t *testing.T) {
   304  	cases := []*compareTestCase{
   305  		{
   306  			A: &Attribute{
   307  				Int:  helper.Int64ToPtr(3),
   308  				Unit: "MB",
   309  			},
   310  			B: &Attribute{
   311  				Int:  helper.Int64ToPtr(10),
   312  				Unit: "MB",
   313  			},
   314  			Expected: -1,
   315  		},
   316  		{
   317  			A: &Attribute{
   318  				Int:  helper.Int64ToPtr(10),
   319  				Unit: "MB",
   320  			},
   321  			B: &Attribute{
   322  				Int:  helper.Int64ToPtr(10),
   323  				Unit: "MB",
   324  			},
   325  			Expected: 0,
   326  		},
   327  		{
   328  			A: &Attribute{
   329  				Int:  helper.Int64ToPtr(100),
   330  				Unit: "MB",
   331  			},
   332  			B: &Attribute{
   333  				Int:  helper.Int64ToPtr(10),
   334  				Unit: "MB",
   335  			},
   336  			Expected: 1,
   337  		},
   338  		{
   339  			A: &Attribute{
   340  				Int:  helper.Int64ToPtr(3),
   341  				Unit: "GB",
   342  			},
   343  			B: &Attribute{
   344  				Int:  helper.Int64ToPtr(3),
   345  				Unit: "MB",
   346  			},
   347  			Expected: 1,
   348  		},
   349  		{
   350  			A: &Attribute{
   351  				Int:  helper.Int64ToPtr(1),
   352  				Unit: "GiB",
   353  			},
   354  			B: &Attribute{
   355  				Int:  helper.Int64ToPtr(1024),
   356  				Unit: "MiB",
   357  			},
   358  			Expected: 0,
   359  		},
   360  		{
   361  			A: &Attribute{
   362  				Int:  helper.Int64ToPtr(1),
   363  				Unit: "GiB",
   364  			},
   365  			B: &Attribute{
   366  				Int:  helper.Int64ToPtr(1025),
   367  				Unit: "MiB",
   368  			},
   369  			Expected: -1,
   370  		},
   371  		{
   372  			A: &Attribute{
   373  				Int:  helper.Int64ToPtr(1000),
   374  				Unit: "mW",
   375  			},
   376  			B: &Attribute{
   377  				Int:  helper.Int64ToPtr(1),
   378  				Unit: "W",
   379  			},
   380  			Expected: 0,
   381  		},
   382  	}
   383  	testComparison(t, cases)
   384  }
   385  
   386  func TestAttribute_Compare_Float_With_Units(t *testing.T) {
   387  	cases := []*compareTestCase{
   388  		{
   389  			A: &Attribute{
   390  				Float: helper.Float64ToPtr(3.0),
   391  				Unit:  "MB",
   392  			},
   393  			B: &Attribute{
   394  				Float: helper.Float64ToPtr(10.0),
   395  				Unit:  "MB",
   396  			},
   397  			Expected: -1,
   398  		},
   399  		{
   400  			A: &Attribute{
   401  				Float: helper.Float64ToPtr(10.0),
   402  				Unit:  "MB",
   403  			},
   404  			B: &Attribute{
   405  				Float: helper.Float64ToPtr(10.0),
   406  				Unit:  "MB",
   407  			},
   408  			Expected: 0,
   409  		},
   410  		{
   411  			A: &Attribute{
   412  				Float: helper.Float64ToPtr(100.0),
   413  				Unit:  "MB",
   414  			},
   415  			B: &Attribute{
   416  				Float: helper.Float64ToPtr(10.0),
   417  				Unit:  "MB",
   418  			},
   419  			Expected: 1,
   420  		},
   421  		{
   422  			A: &Attribute{
   423  				Float: helper.Float64ToPtr(3.0),
   424  				Unit:  "GB",
   425  			},
   426  			B: &Attribute{
   427  				Float: helper.Float64ToPtr(3.0),
   428  				Unit:  "MB",
   429  			},
   430  			Expected: 1,
   431  		},
   432  		{
   433  			A: &Attribute{
   434  				Float: helper.Float64ToPtr(1.0),
   435  				Unit:  "GiB",
   436  			},
   437  			B: &Attribute{
   438  				Float: helper.Float64ToPtr(1024.0),
   439  				Unit:  "MiB",
   440  			},
   441  			Expected: 0,
   442  		},
   443  		{
   444  			A: &Attribute{
   445  				Float: helper.Float64ToPtr(1.0),
   446  				Unit:  "GiB",
   447  			},
   448  			B: &Attribute{
   449  				Float: helper.Float64ToPtr(1025.0),
   450  				Unit:  "MiB",
   451  			},
   452  			Expected: -1,
   453  		},
   454  		{
   455  			A: &Attribute{
   456  				Float: helper.Float64ToPtr(1000.0),
   457  				Unit:  "mW",
   458  			},
   459  			B: &Attribute{
   460  				Float: helper.Float64ToPtr(1.0),
   461  				Unit:  "W",
   462  			},
   463  			Expected: 0,
   464  		},
   465  		{
   466  			A: &Attribute{
   467  				Float: helper.Float64ToPtr(1.5),
   468  				Unit:  "GiB",
   469  			},
   470  			B: &Attribute{
   471  				Float: helper.Float64ToPtr(1400.0),
   472  				Unit:  "MiB",
   473  			},
   474  			Expected: 1,
   475  		},
   476  	}
   477  	testComparison(t, cases)
   478  }
   479  
   480  func TestAttribute_Compare_IntToFloat(t *testing.T) {
   481  	cases := []*compareTestCase{
   482  		{
   483  			A: &Attribute{
   484  				Int: helper.Int64ToPtr(3),
   485  			},
   486  			B: &Attribute{
   487  				Float: helper.Float64ToPtr(10.0),
   488  			},
   489  			Expected: -1,
   490  		},
   491  		{
   492  			A: &Attribute{
   493  				Int: helper.Int64ToPtr(10),
   494  			},
   495  			B: &Attribute{
   496  				Float: helper.Float64ToPtr(10.0),
   497  			},
   498  			Expected: 0,
   499  		},
   500  		{
   501  			A: &Attribute{
   502  				Int: helper.Int64ToPtr(10),
   503  			},
   504  			B: &Attribute{
   505  				Float: helper.Float64ToPtr(10.1),
   506  			},
   507  			Expected: -1,
   508  		},
   509  		{
   510  			A: &Attribute{
   511  				Int: helper.Int64ToPtr(100),
   512  			},
   513  			B: &Attribute{
   514  				Float: helper.Float64ToPtr(10.0),
   515  			},
   516  			Expected: 1,
   517  		},
   518  		{
   519  			A: &Attribute{
   520  				Int: helper.Int64ToPtr(100),
   521  			},
   522  			B: &Attribute{
   523  				Float: helper.Float64ToPtr(100.00001),
   524  			},
   525  			Expected: -1,
   526  		},
   527  	}
   528  	testComparison(t, cases)
   529  }
   530  
   531  func testComparison(t *testing.T, cases []*compareTestCase) {
   532  	for _, c := range cases {
   533  		t.Run(fmt.Sprintf("%#v vs %#v", c.A, c.B), func(t *testing.T) {
   534  			v, ok := c.A.Compare(c.B)
   535  			if !ok && !c.NotComparable {
   536  				t.Fatal("should be comparable")
   537  			} else if ok {
   538  				require.Equal(t, c.Expected, v)
   539  			}
   540  		})
   541  	}
   542  }
   543  
   544  func TestAttribute_ParseAndValidate(t *testing.T) {
   545  	cases := []struct {
   546  		Input    string
   547  		Expected *Attribute
   548  	}{
   549  		{
   550  			Input: "true",
   551  			Expected: &Attribute{
   552  				Bool: helper.BoolToPtr(true),
   553  			},
   554  		},
   555  		{
   556  			Input: "false",
   557  			Expected: &Attribute{
   558  				Bool: helper.BoolToPtr(false),
   559  			},
   560  		},
   561  		{
   562  			Input: "1",
   563  			Expected: &Attribute{
   564  				Int: helper.Int64ToPtr(1),
   565  			},
   566  		},
   567  		{
   568  			Input: "100",
   569  			Expected: &Attribute{
   570  				Int: helper.Int64ToPtr(100),
   571  			},
   572  		},
   573  		{
   574  			Input: "-100",
   575  			Expected: &Attribute{
   576  				Int: helper.Int64ToPtr(-100),
   577  			},
   578  		},
   579  		{
   580  			Input: "-1.0",
   581  			Expected: &Attribute{
   582  				Float: helper.Float64ToPtr(-1.0),
   583  			},
   584  		},
   585  		{
   586  			Input: "-100.25",
   587  			Expected: &Attribute{
   588  				Float: helper.Float64ToPtr(-100.25),
   589  			},
   590  		},
   591  		{
   592  			Input: "1.01",
   593  			Expected: &Attribute{
   594  				Float: helper.Float64ToPtr(1.01),
   595  			},
   596  		},
   597  		{
   598  			Input: "100.25",
   599  			Expected: &Attribute{
   600  				Float: helper.Float64ToPtr(100.25),
   601  			},
   602  		},
   603  		{
   604  			Input: "foobar",
   605  			Expected: &Attribute{
   606  				String: helper.StringToPtr("foobar"),
   607  			},
   608  		},
   609  		{
   610  			Input: "foo123bar",
   611  			Expected: &Attribute{
   612  				String: helper.StringToPtr("foo123bar"),
   613  			},
   614  		},
   615  		{
   616  			Input: "100MB",
   617  			Expected: &Attribute{
   618  				Int:  helper.Int64ToPtr(100),
   619  				Unit: "MB",
   620  			},
   621  		},
   622  		{
   623  			Input: "-100MHz",
   624  			Expected: &Attribute{
   625  				Int:  helper.Int64ToPtr(-100),
   626  				Unit: "MHz",
   627  			},
   628  		},
   629  		{
   630  			Input: "-1.0MB/s",
   631  			Expected: &Attribute{
   632  				Float: helper.Float64ToPtr(-1.0),
   633  				Unit:  "MB/s",
   634  			},
   635  		},
   636  		{
   637  			Input: "-100.25GiB/s",
   638  			Expected: &Attribute{
   639  				Float: helper.Float64ToPtr(-100.25),
   640  				Unit:  "GiB/s",
   641  			},
   642  		},
   643  		{
   644  			Input: "1.01TB",
   645  			Expected: &Attribute{
   646  				Float: helper.Float64ToPtr(1.01),
   647  				Unit:  "TB",
   648  			},
   649  		},
   650  		{
   651  			Input: "100.25mW",
   652  			Expected: &Attribute{
   653  				Float: helper.Float64ToPtr(100.25),
   654  				Unit:  "mW",
   655  			},
   656  		},
   657  	}
   658  
   659  	for _, c := range cases {
   660  		t.Run(c.Input, func(t *testing.T) {
   661  			a := ParseAttribute(c.Input)
   662  			require.Equal(t, c.Expected, a)
   663  			require.NoError(t, a.Validate())
   664  		})
   665  	}
   666  }
   667  
   668  func BenchmarkParse(b *testing.B) {
   669  	cases := []string{
   670  		"true",
   671  		"false",
   672  		"100",
   673  		"-100",
   674  		"-1.0",
   675  		"-100.25",
   676  		"1.01",
   677  		"100.25",
   678  		"foobar",
   679  		"foo123bar",
   680  		"100MB",
   681  		"-100MHz",
   682  		"-1.0MB/s",
   683  		"-100.25GiB/s",
   684  		"1.01TB",
   685  		"100.25mW",
   686  	}
   687  
   688  	for n := 0; n < b.N; n++ {
   689  		for _, c := range cases {
   690  			ParseAttribute(c)
   691  		}
   692  	}
   693  }