| /* |
| Copyright 2020 The Kubernetes Authors. |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| package netpol |
| |
| import ( |
| "strings" |
| |
| "k8s.io/kubernetes/test/e2e/framework" |
| ) |
| |
| // TruthTable takes in n items and maintains an n x n table of booleans for each ordered pair |
| type TruthTable struct { |
| Froms []string |
| Tos []string |
| toSet map[string]bool |
| Values map[string]map[string]bool |
| } |
| |
| // NewTruthTableFromItems creates a new truth table with items |
| func NewTruthTableFromItems(items []string, defaultValue *bool) *TruthTable { |
| return NewTruthTable(items, items, defaultValue) |
| } |
| |
| // NewTruthTable creates a new truth table with froms and tos |
| func NewTruthTable(froms []string, tos []string, defaultValue *bool) *TruthTable { |
| values := map[string]map[string]bool{} |
| for _, from := range froms { |
| values[from] = map[string]bool{} |
| for _, to := range tos { |
| if defaultValue != nil { |
| values[from][to] = *defaultValue |
| } |
| } |
| } |
| toSet := map[string]bool{} |
| for _, to := range tos { |
| toSet[to] = true |
| } |
| return &TruthTable{ |
| Froms: froms, |
| Tos: tos, |
| toSet: toSet, |
| Values: values, |
| } |
| } |
| |
| // IsComplete returns true if there's a value set for every single pair of items, otherwise it returns false. |
| func (tt *TruthTable) IsComplete() bool { |
| for _, from := range tt.Froms { |
| for _, to := range tt.Tos { |
| if _, ok := tt.Values[from][to]; !ok { |
| return false |
| } |
| } |
| } |
| return true |
| } |
| |
| // Set sets the value for from->to |
| func (tt *TruthTable) Set(from string, to string, value bool) { |
| dict, ok := tt.Values[from] |
| if !ok { |
| framework.Failf("from-key %s not found", from) |
| } |
| if _, ok := tt.toSet[to]; !ok { |
| framework.Failf("to-key %s not allowed", to) |
| } |
| dict[to] = value |
| } |
| |
| // SetAllFrom sets all values where from = 'from' |
| func (tt *TruthTable) SetAllFrom(from string, value bool) { |
| dict, ok := tt.Values[from] |
| if !ok { |
| framework.Failf("from-key %s not found", from) |
| } |
| for _, to := range tt.Tos { |
| dict[to] = value |
| } |
| } |
| |
| // SetAllTo sets all values where to = 'to' |
| func (tt *TruthTable) SetAllTo(to string, value bool) { |
| if _, ok := tt.toSet[to]; !ok { |
| framework.Failf("to-key %s not found", to) |
| } |
| for _, from := range tt.Froms { |
| tt.Values[from][to] = value |
| } |
| } |
| |
| // Get gets the specified value |
| func (tt *TruthTable) Get(from string, to string) bool { |
| dict, ok := tt.Values[from] |
| if !ok { |
| framework.Failf("from-key %s not found", from) |
| } |
| val, ok := dict[to] |
| if !ok { |
| framework.Failf("to-key %s not found in map (%+v)", to, dict) |
| } |
| return val |
| } |
| |
| // Compare is used to check two truth tables for equality, returning its |
| // result in the form of a third truth table. Both tables are expected to |
| // have identical items. |
| func (tt *TruthTable) Compare(other *TruthTable) *TruthTable { |
| if len(tt.Froms) != len(other.Froms) || len(tt.Tos) != len(other.Tos) { |
| framework.Failf("cannot compare tables of different dimensions") |
| } |
| for i, fr := range tt.Froms { |
| if other.Froms[i] != fr { |
| framework.Failf("cannot compare: from keys at index %d do not match (%s vs %s)", i, other.Froms[i], fr) |
| } |
| } |
| for i, to := range tt.Tos { |
| if other.Tos[i] != to { |
| framework.Failf("cannot compare: to keys at index %d do not match (%s vs %s)", i, other.Tos[i], to) |
| } |
| } |
| |
| values := map[string]map[string]bool{} |
| for from, dict := range tt.Values { |
| values[from] = map[string]bool{} |
| for to, val := range dict { |
| values[from][to] = val == other.Values[from][to] |
| } |
| } |
| return &TruthTable{ |
| Froms: tt.Froms, |
| Tos: tt.Tos, |
| toSet: tt.toSet, |
| Values: values, |
| } |
| } |
| |
| // PrettyPrint produces a nice visual representation. |
| func (tt *TruthTable) PrettyPrint(indent string) string { |
| header := indent + strings.Join(append([]string{"-\t"}, tt.Tos...), "\t") |
| lines := []string{header} |
| for _, from := range tt.Froms { |
| line := []string{from} |
| for _, to := range tt.Tos { |
| mark := "X" |
| val, ok := tt.Values[from][to] |
| if !ok { |
| mark = "?" |
| } else if val { |
| mark = "." |
| } |
| line = append(line, mark+"\t") |
| } |
| lines = append(lines, indent+strings.Join(line, "\t")) |
| } |
| return strings.Join(lines, "\n") |
| } |