spec_util

package
v0.0.0-...-f1bff1d Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 29, 2024 License: Apache-2.0 Imports: 25 Imported by: 6

README

Package spec_util provides utilities for working with our generic API spec format.

Documentation

Index

Constants

View Source
const (
	XAkitaCLIGitVersion = "x-akita-cli-git-version"
	XAkitaRequestID     = "x-akita-request-id"
	XAkitaDogfood       = "x-akita-dogfood"
)

Variables

View Source
var (
	NoneData = &pb.Data{
		Value: &pb.Data_Optional{
			Optional: &pb.Optional{
				Value: &pb.Optional_None{
					None: &pb.None{},
				},
			},
		},
	}
)

Functions

func AddAnnotationToData

func AddAnnotationToData(d *pb.Data, aa *pb.AkitaAnnotations)

func ContainsCLITraffic

func ContainsCLITraffic(w *pb.Witness) bool

Returns true if the witness represents traffic from the CLI to our backend. These should get filtered out.

func DataMapKeys

func DataMapKeys(fields map[string]*pb.Data) []string

func EquivalentDataTemplates

func EquivalentDataTemplates(sharedPrefix []*pb.MethodTemplate, dt1 *pb.DataTemplate, dt2 *pb.DataTemplate) (bool, error)

Given 2 DataTemplates that may contain references to Data in the common prefix, return whether the 2 DataTemplates are equivalent. Equivalence is defined as identical (modulo non-fixed values) after constant propagation, and there's a bijection between the non-fixed values. We can't use bijection to define equivalence over fixed values because each fixed value has a different meaning. For example, in enum{WRITER, READER}, it would be wrong to say WRITER == READER. Note we always treat bool primitives as "fixed", so bijection does not apply to bool values.

func ExtractValueFromTemplate

func ExtractValueFromTemplate(t *pb.DataTemplate, ref *pb.DataRef) (*pb.Data, error)

Extracts a constant value from the given template. Does not recursively resolve references. Use in conjunction with PropagateConstants to handle recursive references, though the sequence generator should never generate recursive references in the first place since that is wasteful. Treats none value as an error.

func FlattenAlternatives

func FlattenAlternatives(alts map[string][]*pb.Data) []map[string]*pb.Data

Converts {"a": [1, 2], "b": [3]} to [{"a": 1, "b": 3}, {"a": 2, "b": 3}] Passing in a nil returns [nil].

func GetDataRef

func GetDataRef(r *pb.DataRef, d *pb.Data) (*pb.Data, error)

GetDataRef resolves a reference to the value being referenced. It treats references to a None value as an error. The caller may decide to ignore the error if the references are made by optional fields. TODO: Add unit tests for GetDataRef. Currently, unit test coverage comes from instantiator_test in worker, which is where we extract this piece of code from.

func HTTPAuthFromData

func HTTPAuthFromData(d *pb.Data) *pb.HTTPAuth

func HTTPBodyFromData

func HTTPBodyFromData(d *pb.Data) *pb.HTTPBody

func HTTPBodyFromTemplate

func HTTPBodyFromTemplate(dt *pb.DataTemplate) *pb.HTTPBody

func HTTPCookieFromData

func HTTPCookieFromData(d *pb.Data) *pb.HTTPCookie

func HTTPCookieFromTemplate

func HTTPCookieFromTemplate(dt *pb.DataTemplate) *pb.HTTPCookie

func HTTPEmptyFromData

func HTTPEmptyFromData(d *pb.Data) *pb.HTTPEmpty

func HTTPHeaderFromData

func HTTPHeaderFromData(d *pb.Data) *pb.HTTPHeader

func HTTPHeaderFromTemplate

func HTTPHeaderFromTemplate(dt *pb.DataTemplate) *pb.HTTPHeader

func HTTPMetaFromData

func HTTPMetaFromData(d *pb.Data) *pb.HTTPMeta

func HTTPMetaFromMethod

func HTTPMetaFromMethod(m *pb.Method) *pb.HTTPMethodMeta

func HTTPMultipartFromData

func HTTPMultipartFromData(d *pb.Data) *pb.HTTPMultipart

func HTTPPathFromData

func HTTPPathFromData(d *pb.Data) *pb.HTTPPath

func HTTPPathFromTemplate

func HTTPPathFromTemplate(dt *pb.DataTemplate) *pb.HTTPPath

func HTTPQueryFromData

func HTTPQueryFromData(d *pb.Data) *pb.HTTPQuery

func HTTPQueryFromTemplate

func HTTPQueryFromTemplate(dt *pb.DataTemplate) *pb.HTTPQuery

func HTTPResponseCode

func HTTPResponseCode(m *pb.Method) (int32, error)

Extract the response code from the first response (meaningful for witnesses, which contain only at most one response.)

func HTTPSuccessResponses

func HTTPSuccessResponses(m *pb.Method) map[string]*pb.Data

Extract responses returned under a successful status code

func InferMapsInMethod

func InferMapsInMethod(method *pb.Method)

Check each non-map struct in method, and convert structs to maps if StructShouldBeMap is true.

func InferMapsInModel

func InferMapsInModel(model *pb.APISpec)

Check each non-map struct in model, and convert structs to maps if StructShouldBeMap is true.

func InstantiateOneOf

func InstantiateOneOf(oneof *pb.OneOf, containerMeta *pb.DataMeta, factory OneOfInstantiator) (*pb.Data, error)

Given an OneOfInstantiator, this function feeds all oneof option specs to the factory and returns the "best" output. Currently, "best" is defined as having the most number of non-none fields. If a factory returns an error, its output is not considered. If all factories return error, this function returns ErrNoSuitableOneOf. containerMeta is the DataMeta of the Data object that contains the oneof.

Rationale for the scoring to pick the "best" instantiation: It's possible that multiple oneof options are valid for instantiation. For example, if the spec is:

oneof:

  • struct{ "foo": optional bool } # option 1
  • struct{ "bar": optional bool } # option 2

If the raw data is `{"foo": true}`, technically both options are valid specs for the raw data because option 2 can just treat the "bar" field as null, but option 1 is clearly better.

func IsPrimitive

func IsPrimitive(d *pb.Data) bool

func IsPrimitiveList

func IsPrimitiveList(d *pb.Data) bool

func MergeOneOfMeta

func MergeOneOfMeta(containerMeta, optionMeta *pb.DataMeta) *pb.DataMeta

Merges DataMeta from an oneof option with that of its containing Data object.

func NewPrimitiveBool

func NewPrimitiveBool(v bool) *pb.Primitive

func NewPrimitiveBytes

func NewPrimitiveBytes(v []byte) *pb.Primitive

func NewPrimitiveDouble

func NewPrimitiveDouble(v float64) *pb.Primitive

func NewPrimitiveFloat

func NewPrimitiveFloat(v float32) *pb.Primitive

func NewPrimitiveInt32

func NewPrimitiveInt32(v int32) *pb.Primitive

func NewPrimitiveInt64

func NewPrimitiveInt64(v int64) *pb.Primitive

func NewPrimitiveString

func NewPrimitiveString(v string) *pb.Primitive

func NewPrimitiveUint32

func NewPrimitiveUint32(v uint32) *pb.Primitive

func NewPrimitiveUint64

func NewPrimitiveUint64(v uint64) *pb.Primitive

func OneOf

func OneOf(data []*pb.Data, isConflict bool) (*pb.OneOf, error)

func PropagateConstants

func PropagateConstants(prefix []*pb.MethodTemplate, t *pb.MethodTemplate) error

Propagates constants within prefix that are referred to by references in t. Mutates t and may mutate elements in prefix that are references to constant values themselves.

func RewriteHashKeys

func RewriteHashKeys(spec *pb.APISpec) error

Three maps in the IR use hashes of the values as keys (i.e. map[hash(v)] = v):

  • Method.Args
  • Method.Responses
  • OneOf.Options

This method traverses the spec, recomputes the hash of each value, and updates the map.

func StructShouldBeMap

func StructShouldBeMap(struc *pb.Struct) bool

Heuristically determines whether the given pb.Struct (assumed to not represent a map) should be a map.

func TypeOfPrimitive

func TypeOfPrimitive(p *pb.Primitive) string

func ValueFromPrimitive

func ValueFromPrimitive(p *pb.Primitive) (interface{}, error)

Types

type DataTypeID

type DataTypeID string

Identifies the type of a protobuf Data message.

func DataToTypeID

func DataToTypeID(d *pb.Data) DataTypeID

type ErrNoSuitableOneOf

type ErrNoSuitableOneOf struct{}

func (ErrNoSuitableOneOf) Error

func (e ErrNoSuitableOneOf) Error() string

type InterpretStrings

type InterpretStrings bool
const (
	// Indicates that strings should be interpreted as numbers or boolean values
	// wherever possible.
	INTERPRET_STRINGS InterpretStrings = true

	// Indicates that strings should remain strings.
	NO_INTERPRET_STRINGS InterpretStrings = false
)

type IterMapTuple

type IterMapTuple struct {
	Key   interface{}
	Value interface{}
}

func IterMapInOrder

func IterMapInOrder(m interface{}) []IterMapTuple

type MeldOptions

type MeldOptions struct {
	// Controls the maximum number of cookies that may be present in a meld
	// result. Any extra cookies are discarded.
	MaxNumCookies optionals.Optional[int]

	// Controls the maximum number of examples that are kept for each path
	// parameter.
	MaxNumPathParamExampleValues optionals.Optional[int]

	// Controls whether the examples kept for each path parameter are sampled at
	// random.
	KeepRandomPathParamExampleValues optionals.Optional[bool]
}

type MeldedMethod

type MeldedMethod interface {
	GetMethod() *pb.Method

	GetArgs() map[string]*pb.Data
	SetArgs(map[string]*pb.Data)

	GetResponses() map[string]*pb.Data
	SetResponses(map[string]*pb.Data)

	Has4xxOnly() bool
	SetHas4xxOnly(bool)
	Clone() MeldedMethod

	// Melds src into this instance, resolving conflicts using oneof. Assumes that this and src are for the same endpoint.
	//
	// Responses are always melded. But because they are likely to contain bogus data, requests that result in 4xx response codes are ignored where possible:
	//   - If both src and this contain only 4xx responses, then requests are melded.
	//   - Otherwise, if src contains only 4xx responses, then its requests are ignored.
	//   - Otherwise, if this contains only 4xx responses, then its requests are replaced with requests from src.
	//   - Otherwise, neither src nor this contain only 4xx responses, and requests are melded.
	Meld(src MeldedMethod, opts MeldOptions) error
}

func NewMeldedMethod

func NewMeldedMethod(method *pb.Method) MeldedMethod

type Melder

type Melder struct {
	// contains filtered or unexported fields
}

func NewMelder

func NewMelder(opts MeldOptions) *Melder

func (*Melder) MeldData

func (m *Melder) MeldData(dst, src *pb.Data) error

Assumes that dst.Meta == src.Meta.

type OneOfInstantiator

type OneOfInstantiator func(spec *pb.Data) (instantiated *pb.Data, err error)

A function that creates an instantiated Data from a Data spec.

type PrimitiveValue

type PrimitiveValue interface {
	// Returns the zero value for this PrimitiveValue.
	Zero() PrimitiveValue

	// Returns the PrimitiveValue after obfuscating the original value while
	// keeping the type. For example, an int32 remains int32 after obfuscation
	// instead of becoming a []byte.
	Obfuscate() PrimitiveValue

	String() string

	ToProto() *pb.Primitive
	GoValue() interface{}
	// contains filtered or unexported methods
}

Interface for values that our Primitive protobuf can represent.

func CategorizeString

func CategorizeString(str string) PrimitiveValue

func PrimitiveValueFromProto

func PrimitiveValueFromProto(p *pb.Primitive) (PrimitiveValue, error)

func ToPrimitiveValue

func ToPrimitiveValue(v interface{}, interpretStrings InterpretStrings) (PrimitiveValue, error)

type RefMap

type RefMap map[DataTypeID][]*pb.MethodDataRef

A read-only map that stores references to each method's argument and response values. We store MethodDataRef, but since the AkitaAnnotations inside each ref should come from the Data protobuf making the reference, AkitaAnnotations is filled in only in GetDataRefs

func NewRefMap

func NewRefMap(methods []*pb.Method) RefMap

func (RefMap) GetDataRefs

func (m RefMap) GetDataRefs(dID DataTypeID, aa *pb.AkitaAnnotations) []*pb.MethodDataRef

Create MethodDataRefs for all data of the given type in the args/responses of any previous method.

func (RefMap) HasRefs

func (m RefMap) HasRefs(dID DataTypeID) bool

Given a method ID and a data type ID, returns whether there are references to the method's arguments or responses with the data type.

type RefMapView

type RefMapView struct {
	// contains filtered or unexported fields
}

A "view" into RefMap that keeps track of the prefix MethodTemplates in order to avoid returning references that are not useful. A reference is defined as "unuseful" if it:

  • Refers to yet another reference (we will also return the other reference, so the new reference is redundant). RefMap may return references to references in response values, so we should filter these out.
  • Refers to a skipped optional field

This cuts down on the number of possible sequences we can generate for a given data type.

func NewRefMapView

func NewRefMapView(m RefMap, prefix []*pb.MethodTemplate) *RefMapView

func (*RefMapView) Copy

func (v *RefMapView) Copy() *RefMapView

func (*RefMapView) GetDataRefs

func (v *RefMapView) GetDataRefs(dID DataTypeID, aa *pb.AkitaAnnotations) []*pb.MethodDataRef

func (*RefMapView) GetFillableArgs

func (v *RefMapView) GetFillableArgs(arg *pb.Data) []*pb.Data

Returns the set of data specs that can be filled using the data that's currently fillable. In most cases, if the arg is fillable, the returned result is identical. However, if the arg contains oneof fields, all fillable options are expanded and returned as separate results, where each result no longer has oneof fields.

func (*RefMapView) HasRefs

func (v *RefMapView) HasRefs(dID DataTypeID) bool

Directories

Path Synopsis
gen

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL