kubernetes/test/e2e/network/netpol/truthtable.go
Matthew Fenwick 65632b8677 NetworkPolicy Validation suite
Co-authored-by: Matt Fenwick <mfenwick100@gmail.com>
Co-authored-by: Jay Vyas <jvyas@vmware.com>
Co-authored-by: Rich Renner <renner@sunder.io>
Co-authored-by: Sedef Savas <ssavas@vmware.com>
Co-authored-by: Guangyang Wang <wguangyuan@vmware.com>
Co-authored-by: Akash Sarda <akashsarda3@gmail.com>
Co-authored-by: Abhishek Raut <rauta@vmware.com>
Co-authored-by: Antonin Bas <abas@vmware.com>
Co-authored-by: Antonio Ojea <aojea@redhat.com>

addressed remaining minor comments

initial netpol-framework
2020-12-14 16:47:39 -05:00

172 lines
4.4 KiB
Go

/*
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")
}