github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/operators/operators_test.go (about)

     1  // Copyright 2023 The Inspektor Gadget authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package operators
    16  
    17  import (
    18  	"testing"
    19  
    20  	"github.com/stretchr/testify/assert"
    21  
    22  	"github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets"
    23  	"github.com/inspektor-gadget/inspektor-gadget/pkg/params"
    24  )
    25  
    26  type testOp struct {
    27  	name         string
    28  	dependencies []string
    29  }
    30  
    31  func (op testOp) Name() string {
    32  	return op.name
    33  }
    34  
    35  func (op testOp) Dependencies() []string {
    36  	return op.dependencies
    37  }
    38  
    39  func (op testOp) GlobalParamDescs() params.ParamDescs {
    40  	return nil
    41  }
    42  
    43  func (op testOp) ParamDescs() params.ParamDescs {
    44  	return nil
    45  }
    46  
    47  func (op testOp) Description() string {
    48  	return ""
    49  }
    50  
    51  func (op testOp) CanOperateOn(gadgets.GadgetDesc) bool {
    52  	return true
    53  }
    54  
    55  func (op testOp) Init(*params.Params) error {
    56  	return nil
    57  }
    58  
    59  func (op testOp) Close() error {
    60  	return nil
    61  }
    62  
    63  func (op testOp) Instantiate(gadgetContext GadgetContext, gadgetInstance any, perGadgetParams *params.Params) (OperatorInstance, error) {
    64  	return nil, nil
    65  }
    66  
    67  func checkDependencies(t *testing.T, ops, sortedOps Operators) {
    68  	assert.Equal(t, len(ops), len(sortedOps), "Length of sorted ops has to be the same as the original ops")
    69  
    70  outerLoop:
    71  	for _, op := range ops {
    72  		deps := op.Dependencies()
    73  		for _, sortedOp := range sortedOps {
    74  			if len(deps) == 0 {
    75  				continue outerLoop
    76  			}
    77  			if sortedOp.Name() == op.Name() {
    78  				assert.Failf(t, "Dependencies of %q were not met", op.Name())
    79  			}
    80  			for i, dep := range deps {
    81  				if sortedOp.Name() == dep {
    82  					deps = append(deps[0:i], deps[i+1:]...)
    83  				}
    84  			}
    85  		}
    86  	}
    87  }
    88  
    89  func createOp(name string, deps []string) testOp {
    90  	return testOp{name, deps}
    91  }
    92  
    93  func Test_SortOperatorsSimple(t *testing.T) {
    94  	ops := Operators{
    95  		createOp("b", []string{"a"}),
    96  		createOp("a", []string{}),
    97  	}
    98  
    99  	sortedOps, err := SortOperators(ops)
   100  	if assert.NoError(t, err) {
   101  		checkDependencies(t, ops, sortedOps)
   102  	}
   103  }
   104  
   105  func Test_SortOperatorsTwoIncomingDeps(t *testing.T) {
   106  	ops := Operators{
   107  		createOp("b", []string{"a"}),
   108  		createOp("c", []string{"a"}),
   109  		createOp("a", []string{}),
   110  	}
   111  
   112  	sortedOps, err := SortOperators(ops)
   113  	if assert.NoError(t, err) {
   114  		checkDependencies(t, ops, sortedOps)
   115  	}
   116  }
   117  
   118  func Test_SortOperatorsTwoOutgoingDeps(t *testing.T) {
   119  	ops := Operators{
   120  		createOp("b", []string{"a"}),
   121  		createOp("c", []string{"a", "b"}),
   122  		createOp("a", []string{}),
   123  	}
   124  
   125  	sortedOps, err := SortOperators(ops)
   126  	if assert.NoError(t, err) {
   127  		checkDependencies(t, ops, sortedOps)
   128  	}
   129  }
   130  
   131  func Test_SortOperatorsTwoOutgoingDepsReversed(t *testing.T) {
   132  	ops := Operators{
   133  		createOp("c", []string{"a", "b"}),
   134  		createOp("b", []string{"a"}),
   135  		createOp("a", []string{}),
   136  	}
   137  
   138  	sortedOps, err := SortOperators(ops)
   139  	if assert.NoError(t, err) {
   140  		checkDependencies(t, ops, sortedOps)
   141  	}
   142  }
   143  
   144  func Test_SortOperatorsLargeGraph(t *testing.T) {
   145  	ops := Operators{
   146  		createOp("a", []string{}),
   147  		createOp("b", []string{"a"}),
   148  		createOp("c", []string{"a", "h"}),
   149  		createOp("d", []string{"a"}),
   150  		createOp("e", []string{"d", "b"}),
   151  		createOp("f", []string{"h"}),
   152  		createOp("g", []string{"e"}),
   153  		createOp("h", []string{"d"}),
   154  		createOp("i", []string{"g", "f"}),
   155  	}
   156  
   157  	sortedOps, err := SortOperators(ops)
   158  	if assert.NoError(t, err) {
   159  		checkDependencies(t, ops, sortedOps)
   160  	}
   161  }
   162  
   163  func Test_SortOperatorsMissingDep(t *testing.T) {
   164  	ops := Operators{
   165  		createOp("a", []string{"b"}),
   166  	}
   167  
   168  	_, err := SortOperators(ops)
   169  	assert.ErrorContains(t, err, "dependency \""+ops[0].Dependencies()[0]+"\" is not available in operators")
   170  }
   171  
   172  func Test_SortOperatorsCyclicDep(t *testing.T) {
   173  	ops := Operators{
   174  		createOp("a", []string{"b"}),
   175  		createOp("b", []string{"a"}),
   176  		createOp("c", []string{"a"}),
   177  	}
   178  
   179  	_, err := SortOperators(ops)
   180  	assert.ErrorContains(t, err, "dependency cycle detected")
   181  }
   182  
   183  func Test_SortOperatorsLargeCyclicDep(t *testing.T) {
   184  	ops := Operators{
   185  		createOp("a", []string{"b"}),
   186  		createOp("b", []string{"c"}),
   187  		createOp("c", []string{"d"}),
   188  		createOp("d", []string{"e"}),
   189  		createOp("e", []string{"f"}),
   190  		createOp("f", []string{"a"}),
   191  	}
   192  
   193  	_, err := SortOperators(ops)
   194  	assert.ErrorContains(t, err, "dependency cycle detected")
   195  }