k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/test/e2e/network/netpol/truthtable.go (about) 1 /* 2 Copyright 2020 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package netpol 18 19 import ( 20 "strings" 21 22 "k8s.io/kubernetes/test/e2e/framework" 23 ) 24 25 // TruthTable takes in n items and maintains an n x n table of booleans for each ordered pair 26 type TruthTable struct { 27 Froms []string 28 Tos []string 29 toSet map[string]bool 30 Values map[string]map[string]bool 31 } 32 33 // NewTruthTableFromItems creates a new truth table with items 34 func NewTruthTableFromItems(items []string, defaultValue *bool) *TruthTable { 35 return NewTruthTable(items, items, defaultValue) 36 } 37 38 // NewTruthTable creates a new truth table with froms and tos 39 func NewTruthTable(froms []string, tos []string, defaultValue *bool) *TruthTable { 40 values := map[string]map[string]bool{} 41 for _, from := range froms { 42 values[from] = map[string]bool{} 43 for _, to := range tos { 44 if defaultValue != nil { 45 values[from][to] = *defaultValue 46 } 47 } 48 } 49 toSet := map[string]bool{} 50 for _, to := range tos { 51 toSet[to] = true 52 } 53 return &TruthTable{ 54 Froms: froms, 55 Tos: tos, 56 toSet: toSet, 57 Values: values, 58 } 59 } 60 61 // IsComplete returns true if there's a value set for every single pair of items, otherwise it returns false. 62 func (tt *TruthTable) IsComplete() bool { 63 for _, from := range tt.Froms { 64 for _, to := range tt.Tos { 65 if _, ok := tt.Values[from][to]; !ok { 66 return false 67 } 68 } 69 } 70 return true 71 } 72 73 // Set sets the value for from->to 74 func (tt *TruthTable) Set(from string, to string, value bool) { 75 dict, ok := tt.Values[from] 76 if !ok { 77 framework.Failf("from-key %s not found", from) 78 } 79 if _, ok := tt.toSet[to]; !ok { 80 framework.Failf("to-key %s not allowed", to) 81 } 82 dict[to] = value 83 } 84 85 // SetAllFrom sets all values where from = 'from' 86 func (tt *TruthTable) SetAllFrom(from string, value bool) { 87 dict, ok := tt.Values[from] 88 if !ok { 89 framework.Failf("from-key %s not found", from) 90 } 91 for _, to := range tt.Tos { 92 dict[to] = value 93 } 94 } 95 96 // SetAllTo sets all values where to = 'to' 97 func (tt *TruthTable) SetAllTo(to string, value bool) { 98 if _, ok := tt.toSet[to]; !ok { 99 framework.Failf("to-key %s not found", to) 100 } 101 for _, from := range tt.Froms { 102 tt.Values[from][to] = value 103 } 104 } 105 106 // Get gets the specified value 107 func (tt *TruthTable) Get(from string, to string) bool { 108 dict, ok := tt.Values[from] 109 if !ok { 110 framework.Failf("from-key %s not found", from) 111 } 112 val, ok := dict[to] 113 if !ok { 114 framework.Failf("to-key %s not found in map (%+v)", to, dict) 115 } 116 return val 117 } 118 119 // Compare is used to check two truth tables for equality, returning its 120 // result in the form of a third truth table. Both tables are expected to 121 // have identical items. 122 func (tt *TruthTable) Compare(other *TruthTable) *TruthTable { 123 if len(tt.Froms) != len(other.Froms) || len(tt.Tos) != len(other.Tos) { 124 framework.Failf("cannot compare tables of different dimensions") 125 } 126 for i, fr := range tt.Froms { 127 if other.Froms[i] != fr { 128 framework.Failf("cannot compare: from keys at index %d do not match (%s vs %s)", i, other.Froms[i], fr) 129 } 130 } 131 for i, to := range tt.Tos { 132 if other.Tos[i] != to { 133 framework.Failf("cannot compare: to keys at index %d do not match (%s vs %s)", i, other.Tos[i], to) 134 } 135 } 136 137 values := map[string]map[string]bool{} 138 for from, dict := range tt.Values { 139 values[from] = map[string]bool{} 140 for to, val := range dict { 141 values[from][to] = val == other.Values[from][to] 142 } 143 } 144 return &TruthTable{ 145 Froms: tt.Froms, 146 Tos: tt.Tos, 147 toSet: tt.toSet, 148 Values: values, 149 } 150 } 151 152 // PrettyPrint produces a nice visual representation. 153 func (tt *TruthTable) PrettyPrint(indent string) string { 154 header := indent + strings.Join(append([]string{"-\t"}, tt.Tos...), "\t") 155 lines := []string{header} 156 for _, from := range tt.Froms { 157 line := []string{from} 158 for _, to := range tt.Tos { 159 mark := "X" 160 val, ok := tt.Values[from][to] 161 if !ok { 162 mark = "?" 163 } else if val { 164 mark = "." 165 } 166 line = append(line, mark+"\t") 167 } 168 lines = append(lines, indent+strings.Join(line, "\t")) 169 } 170 return strings.Join(lines, "\n") 171 }