github.com/jlmeeker/kismatic@v1.10.1-0.20180612190640-57f9005a1f1a/pkg/inspector/rule/engine_test.go (about)

     1  package rule
     2  
     3  import (
     4  	"errors"
     5  	"reflect"
     6  	"testing"
     7  
     8  	"github.com/apprenda/kismatic/pkg/inspector/check"
     9  )
    10  
    11  type fakeCheck struct {
    12  	ok  bool
    13  	err error
    14  }
    15  
    16  func (c fakeCheck) Check() (bool, error) {
    17  	return c.ok, c.err
    18  }
    19  
    20  type fakeRule struct {
    21  	Meta
    22  	name     string
    23  	isRemote bool
    24  }
    25  
    26  func (r fakeRule) Name() string       { return r.name }
    27  func (r fakeRule) IsRemoteRule() bool { return r.isRemote }
    28  func (r fakeRule) Validate() []error  { return nil }
    29  
    30  type fakeRuleCheckMapper struct {
    31  	check check.Check
    32  	err   error
    33  }
    34  
    35  func (m fakeRuleCheckMapper) GetCheckForRule(Rule) (check.Check, error) {
    36  	return m.check, m.err
    37  }
    38  
    39  func TestEngine(t *testing.T) {
    40  	dummyError := errors.New("dummy error...")
    41  	tests := []struct {
    42  		mapper          fakeRuleCheckMapper
    43  		rule            fakeRule
    44  		ruleWhen        [][]string
    45  		facts           []string
    46  		expectedResults []Result
    47  		expectErr       bool
    48  	}{
    49  		// Single rule that passes
    50  		{
    51  			mapper: fakeRuleCheckMapper{
    52  				check: fakeCheck{ok: true},
    53  			},
    54  			rule: fakeRule{
    55  				name: "SuccessRule",
    56  			},
    57  			facts: []string{},
    58  			expectedResults: []Result{
    59  				{
    60  					Name:    "SuccessRule",
    61  					Success: true,
    62  				},
    63  			},
    64  		},
    65  		// Single rule that fails
    66  		{
    67  			mapper: fakeRuleCheckMapper{
    68  				check: fakeCheck{ok: false, err: dummyError},
    69  			},
    70  			rule: fakeRule{
    71  				name: "FailRule",
    72  			},
    73  			facts: []string{},
    74  			expectedResults: []Result{
    75  				{
    76  					Name:    "FailRule",
    77  					Success: false,
    78  					Error:   dummyError.Error(),
    79  				},
    80  			},
    81  		},
    82  		// Single rule that should run due to facts
    83  		{
    84  			mapper: fakeRuleCheckMapper{
    85  				check: fakeCheck{ok: false, err: dummyError},
    86  			},
    87  			rule: fakeRule{
    88  				name: "FailRule",
    89  			},
    90  			ruleWhen: [][]string{[]string{"ubuntu"}, []string{"worker"}},
    91  			facts:    []string{"ubuntu", "worker", "otherFact"},
    92  			expectedResults: []Result{
    93  				{
    94  					Name:    "FailRule",
    95  					Success: false,
    96  					Error:   dummyError.Error(),
    97  				},
    98  			},
    99  		},
   100  		{
   101  			mapper: fakeRuleCheckMapper{
   102  				check: fakeCheck{ok: false, err: dummyError},
   103  			},
   104  			rule: fakeRule{
   105  				name: "FailRule",
   106  			},
   107  			ruleWhen: [][]string{[]string{"ubuntu"}, []string{"master", "worker"}},
   108  			facts:    []string{"ubuntu", "worker", "otherFact"},
   109  			expectedResults: []Result{
   110  				{
   111  					Name:    "FailRule",
   112  					Success: false,
   113  					Error:   dummyError.Error(),
   114  				},
   115  			},
   116  		},
   117  		{
   118  			mapper: fakeRuleCheckMapper{
   119  				check: fakeCheck{ok: false, err: dummyError},
   120  			},
   121  			rule: fakeRule{
   122  				name: "FailRule",
   123  			},
   124  			ruleWhen: [][]string{[]string{"centos", "rhel"}, []string{"worker"}},
   125  			facts:    []string{"centos", "worker", "otherFact"},
   126  			expectedResults: []Result{
   127  				{
   128  					Name:    "FailRule",
   129  					Success: false,
   130  					Error:   dummyError.Error(),
   131  				},
   132  			},
   133  		},
   134  		// Single rule that should not run due to facts
   135  		{
   136  			mapper: fakeRuleCheckMapper{
   137  				check: fakeCheck{ok: false, err: dummyError},
   138  			},
   139  			rule: fakeRule{
   140  				name: "FailRule",
   141  			},
   142  			ruleWhen:        [][]string{[]string{"ubuntu"}},
   143  			facts:           []string{"otherFact"},
   144  			expectedResults: []Result{},
   145  		},
   146  		// Single rule that should run regardless of facts
   147  		{
   148  			mapper: fakeRuleCheckMapper{
   149  				check: fakeCheck{ok: false, err: dummyError},
   150  			},
   151  			rule: fakeRule{
   152  				name: "FailRule",
   153  			},
   154  			ruleWhen: [][]string{},
   155  			facts:    []string{"ubuntu"},
   156  			expectedResults: []Result{
   157  				{
   158  					Name:    "FailRule",
   159  					Success: false,
   160  					Error:   dummyError.Error(),
   161  				},
   162  			},
   163  		},
   164  		// Mapper returns an error, engine should return error
   165  		{
   166  			mapper: fakeRuleCheckMapper{
   167  				err: dummyError,
   168  			},
   169  			rule:      fakeRule{},
   170  			expectErr: true,
   171  		},
   172  	}
   173  
   174  	for _, test := range tests {
   175  		// Set the rule when conditions here because of embedding :(
   176  		if test.ruleWhen != nil {
   177  			test.rule.When = test.ruleWhen
   178  		}
   179  		e := Engine{
   180  			RuleCheckMapper: test.mapper,
   181  		}
   182  		result, err := e.ExecuteRules([]Rule{test.rule}, test.facts)
   183  		if test.expectErr && err == nil {
   184  			t.Errorf("expected an error, but didn't get one")
   185  			continue
   186  		}
   187  		if err != nil && !test.expectErr {
   188  			t.Errorf("got an unexpected error: %v", err)
   189  			continue
   190  		}
   191  
   192  		if !reflect.DeepEqual(test.expectedResults, result) {
   193  			t.Errorf("expected %+v, but got %+v", test.expectedResults, result)
   194  		}
   195  	}
   196  }
   197  
   198  type fakeClosableCheck struct {
   199  	success     bool
   200  	closeCalled bool
   201  }
   202  
   203  func (c *fakeClosableCheck) Check() (bool, error) { return c.success, nil }
   204  
   205  func (c *fakeClosableCheck) Close() error {
   206  	c.closeCalled = true
   207  	return nil
   208  }
   209  
   210  func TestEngineClosableCheckSuccess(t *testing.T) {
   211  	fakeCheck := &fakeClosableCheck{success: true}
   212  	mapper := fakeRuleCheckMapper{
   213  		check: fakeCheck,
   214  	}
   215  	e := Engine{
   216  		RuleCheckMapper: mapper,
   217  	}
   218  	rule := fakeRule{}
   219  	_, err := e.ExecuteRules([]Rule{rule}, []string{})
   220  	if err != nil {
   221  		t.Errorf("unexpected error when executing closable check: %v", err)
   222  	}
   223  
   224  	if err := e.CloseChecks(); err != nil {
   225  		t.Errorf("unexpected error when closing checks: %v", err)
   226  	}
   227  
   228  	if !fakeCheck.closeCalled {
   229  		t.Errorf("The check was not closed")
   230  	}
   231  }
   232  
   233  func TestEngineClosableCheckFail(t *testing.T) {
   234  	fakeCheck := &fakeClosableCheck{success: false}
   235  	mapper := fakeRuleCheckMapper{
   236  		check: fakeCheck,
   237  	}
   238  	e := Engine{
   239  		RuleCheckMapper: mapper,
   240  	}
   241  	rule := fakeRule{}
   242  	_, err := e.ExecuteRules([]Rule{rule}, []string{})
   243  	if err != nil {
   244  		t.Errorf("unexpected error when executing closable check: %v", err)
   245  	}
   246  
   247  	if err := e.CloseChecks(); err != nil {
   248  		t.Errorf("unexpected error when closing checks: %v", err)
   249  	}
   250  
   251  	if fakeCheck.closeCalled {
   252  		t.Errorf("The check failed, and close was called on it")
   253  	}
   254  }