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 }