README

Resource Tree

resourcetree package contains types and interfaces that define a resource tree(n-ary tree based representation of an API resource). Each resource tree is composed of nodes which have data encapsulated inside nodeData and operations that can be performed on each node in the interface NodeInterface. Type of a node is logically defined by reflect.Kind. Each node type is expected to satisfy the NodeInterface interface.

Resource Forest

ResourceForest groups all resource trees that are part of an API version into a single construct and defines operations that span across them. As an example for Knative Serving, we will have individual resource trees for Configuration, Revision, Route and Service, and they are encapsulated inside a resource forest under version v1alpha1. Example of an operation that spans resource trees would be to get coverage details for outlined types connected using ConnectedNodes.

ConnectedNodes represent connections between nodes that are of same type(reflect.Type) and belong to same package but span across different trees or branches of same tree. An example of ConnectedNodes would be v1alpha1.Route.Spec.Traffic and v1alpha1.Route.Status.Traffic, both these Traffic fields are of type v1alpha1.TrafficTarget, but are present in different paths inside the resource tree. ConnectedNodes connects these two nodes, and an outlining of this type would present the coverage across the two branches and gives a unified view of what fields are covered.

Type Analysis

A Resource tree is built using reflect.Type Each node type is expected to implement NodeInterface method buildChildNodes(t reflect.Type). Inside this method each node creates child nodes based on its type, for e.g. StructKindNode creates one child for each field defined in the struct. Type analysis are defined inside typeanalyzer_tests

Value Analysis

A Resource tree is updated using reflect.Value Each node type is expected to implement NodeInterface method updateCoverage(v reflect.Value). Inisde this method each node updates its nodeData.covered field based on whether the reflect.Value parameter being passed is set or not.

Rules

To define traversal pattern on a resourcetree coveragecalculator package supports defining rules that are applied during apicoverage walk-through. Currently the tool supports two types of Rule objects:

  1. NodeRules: Enforces node level semantics. e.g.: Avoid traversing any type that belong to a particular package. To enforce this rule, the repo would define an object that implements the NodeRule interface's Apply(nodeInterface resourcetree.NodeInterface) bool method and pass that onto the resourcetree traversal routine.

  2. FieldRules: Enforces field level semantics. e.g. Avoid calculating coverage for any field that starts with prefix deprecated. To enforce this rule, the repo would define an object that implements FieldRule interface's Apply(fieldName string) bool method and pass that onto the resourcetree traversal routine.

Expand ▾ Collapse ▴

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ArrayKindNode

type ArrayKindNode struct {
	NodeData
	// contains filtered or unexported fields
}

    ArrayKindNode represents resource tree node of types reflect.Kind.Array and reflect.Kind.Slice

    func (*ArrayKindNode) GetData

    func (a *ArrayKindNode) GetData() NodeData

      GetData returns node data

      type BasicTypeKindNode

      type BasicTypeKindNode struct {
      	NodeData
      	// contains filtered or unexported fields
      }

        BasicTypeKindNode represents resource tree node of basic types like int, float, etc.

        func (*BasicTypeKindNode) GetData

        func (b *BasicTypeKindNode) GetData() NodeData

          GetData returns node data

          type FieldRules

          type FieldRules struct {
          	Rules []func(fieldName string) bool
          }

            FieldRules encapsulates all the field level rules defined by a repo.

            func (*FieldRules) Apply

            func (f *FieldRules) Apply(fieldName string) bool

              Apply runs all the rules defined by a repo against a field.

              type NodeData

              type NodeData struct {
              	// Represents the Name of the field e.g. field name inside the struct.
              	Field string
              	// Reference back to the resource tree. Required for cross-tree traversal(connected nodes traversal)
              	Tree *ResourceTree
              	// Required as type information is not available during tree traversal.
              	FieldType reflect.Type
              	// Path in the resource tree reaching this node.
              	NodePath string
              	// Link back to parent.
              	Parent NodeInterface
              	// Child nodes are keyed using field names(nodeData.field).
              	Children map[string]NodeInterface
              	// Storing this as an additional field because type-analysis determines the value,
              	// which gets used later in value-evaluation
              	LeafNode bool
              	Covered  bool
              }

                NodeData is the data stored in each node of the resource tree.

                type NodeInterface

                type NodeInterface interface {
                	GetData() NodeData
                	// contains filtered or unexported methods
                }

                  NodeInterface defines methods that can be performed on each node in the resource tree.

                  type NodeRules

                  type NodeRules struct {
                  	Rules []func(nodeInterface NodeInterface) bool
                  }

                    NodeRules encapsulates all the node level rules defined by a repo.

                    func (*NodeRules) Apply

                    func (n *NodeRules) Apply(node NodeInterface) bool

                      Apply runs all the rules defined by a repo against a node.

                      type OtherKindNode

                      type OtherKindNode struct {
                      	NodeData
                      }

                        OtherKindNode represents nodes in the resource tree of types like maps, interfaces, etc

                        func (*OtherKindNode) GetData

                        func (o *OtherKindNode) GetData() NodeData

                          GetData returns node data

                          type PtrKindNode

                          type PtrKindNode struct {
                          	NodeData
                          	// contains filtered or unexported fields
                          }

                            PtrKindNode represents nodes in the resource tree of type reflect.Kind.Ptr, reflect.Kind.UnsafePointer, etc.

                            func (*PtrKindNode) GetData

                            func (p *PtrKindNode) GetData() NodeData

                              GetData returns node data

                              type ResourceForest

                              type ResourceForest struct {
                              	Version string
                              	// Key is ResourceTree.ResourceName
                              	TopLevelTrees map[string]ResourceTree
                              	// Head of the linked list keyed by nodeData.fieldType.pkg + nodeData.fieldType.Name()
                              	ConnectedNodes map[string]*list.List
                              }

                                ResourceForest represents the top-level forest that contains individual resource trees for top-level resource types and all connected nodes across resource trees.

                                func (*ResourceForest) AddResourceTree

                                func (r *ResourceForest) AddResourceTree(resourceName string, resourceType reflect.Type)

                                  AddResourceTree adds a resource tree to the resource forest.

                                  type ResourceTree

                                  type ResourceTree struct {
                                  	ResourceName string
                                  	Root         NodeInterface
                                  	Forest       *ResourceForest
                                  }

                                    ResourceTree encapsulates a tree corresponding to a resource type.

                                    func (*ResourceTree) BuildCoverageData

                                    func (r *ResourceTree) BuildCoverageData(nodeRules NodeRules, fieldRules FieldRules,
                                    	ignoredFields coveragecalculator.IgnoredFields) []coveragecalculator.TypeCoverage

                                      BuildCoverageData calculates the coverage information for a resource tree by applying provided Node and Field rules.

                                      func (*ResourceTree) BuildResourceTree

                                      func (r *ResourceTree) BuildResourceTree(t reflect.Type)

                                        BuildResourceTree builds a resource tree by calling into analyzeType method starting from root.

                                        func (*ResourceTree) UpdateCoverage

                                        func (r *ResourceTree) UpdateCoverage(v reflect.Value)

                                          UpdateCoverage updates coverage data in the resource tree based on the provided reflect.Value

                                          type StructKindNode

                                          type StructKindNode struct {
                                          	NodeData
                                          }

                                            StructKindNode represents nodes in the resource tree of type reflect.Kind.Struct

                                            func (*StructKindNode) GetData

                                            func (s *StructKindNode) GetData() NodeData

                                              GetData returns node data

                                              type TimeTypeNode

                                              type TimeTypeNode struct {
                                              	NodeData
                                              }

                                                TimeTypeNode is a node type that encapsulates fields that are internally time based. E.g metav1.ObjectMeta.CreationTimestamp or metav1.ObjectMeta.DeletionTimestamp. These are internally of type metav1.Time which use standard time type, but their values are specified as timestamp strings with parsing logic to create time objects. For use-case we only care if the value is set, so we create TimeTypeNodes and mark them as leafnodes.

                                                func (*TimeTypeNode) GetData

                                                func (ti *TimeTypeNode) GetData() NodeData

                                                  GetData returns node data