Ctrl K
ComunidadGuías…

pkg/models/concurrent_keys.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package models

import "sync"

// ConcurrentKeys is how a kind's parser reads its recordings for keploy
// record's full round, which shares the recordings made while several tests'
// requests were open between those tests (Mapping.Groups,
// ExactServing.Concurrent). A kind that registers none shares nothing: each
// of its recordings stays the test that lists it.
//
// Each key is coarser than what the parser's matching under the proven switch
// accepts: two shareable recordings that could both answer one call have equal
// Request keys. The parser's tests pin why. Keys and values never leave the
// process: they are compared, never logged or written.
type ConcurrentKeys struct {
	// Statement is the key of what the recording's call does, apart from
	// the values it sends (for SQL: the statement's shape, its arity, and
	// how many constants it holds): only recordings of one statement are
	// compared. ok is false for a recording the kind does not key.
	Statement func(m *Mock) (key string, ok bool)
	// Request is the key of the recording's request: Statement, and every
	// value it sends but at the places excused names (the places the learn
	// step learned on a recording of the statement).
	Request func(m *Mock, excused []string) (key string, ok bool)
	// Answer is the key of the recording's answer: what the dependency
	// answered, with each cell that holds the value the recording sent at
	// one of echoes (the places the learn step learned as echoed) read as
	// that place.
	Answer func(m *Mock, echoes []string) (key string, ok bool)
	// Positions are the values the recording sends, by place (as the learn
	// step names a place: for SQL bind.$N and literal.N), each whole, as it
	// was sent.
	Positions func(m *Mock) map[string]string
	// Shareable reports whether the recording may be shared at all: false,
	// with why, for one whose recording states what widens its matching
	// beyond equal values (noise, volatile places, variables, a redacted
	// value), or one the kind's matching never answers a data call with.
	// A recording that is not shareable stays the test that lists it.
	Shareable func(m *Mock) (ok bool, why string)
	// Describe, when set, is the protocol and the call a charge of the
	// recording names (no value: for SQL, its statement with its constants
	// written ?); MockSummaryFromSpec and its kind when not.
	Describe func(m *Mock) (protocol, summary string)
}

var concurrentKeys = struct {
	mu   sync.RWMutex
	keys map[Kind]ConcurrentKeys
}{keys: map[Kind]ConcurrentKeys{}}

// RegisterConcurrentKeys registers kind's ConcurrentKeys, replacing any, and
// returns what puts back the previous registration (for tests). A parser
// registers in its package's init.
func RegisterConcurrentKeys(kind Kind, k ConcurrentKeys) (restore func()) {
	concurrentKeys.mu.Lock()
	defer concurrentKeys.mu.Unlock()
	defer mockRulesChanged()
	prev, had := concurrentKeys.keys[kind]
	concurrentKeys.keys[kind] = k
	return func() {
		concurrentKeys.mu.Lock()
		defer concurrentKeys.mu.Unlock()
		defer mockRulesChanged()
		if had {
			concurrentKeys.keys[kind] = prev
		} else {
			delete(concurrentKeys.keys, kind)
		}
	}
}

// ConcurrentKeysOf is kind's registered ConcurrentKeys; ok is false for a kind
// that registered none, or registered one without every key.
func ConcurrentKeysOf(kind Kind) (ConcurrentKeys, bool) {
	concurrentKeys.mu.RLock()
	defer concurrentKeys.mu.RUnlock()
	k, ok := concurrentKeys.keys[kind]
	if !ok || k.Statement == nil || k.Request == nil || k.Answer == nil || k.Positions == nil || k.Shareable == nil {
		return ConcurrentKeys{}, false
	}
	return k, true
}

// protocolKinds are the kinds a call of each canonical protocol (a miss's
// MockMismatchReport.Protocol, as package mismatch names them) is recorded
// as.
var protocolKinds = map[string][]Kind{
	"HTTP":       {HTTP},
	"HTTP/2":     {HTTP2},
	"gRPC":       {GRPC_EXPORT},
	"MySQL":      {MySQL},
	"PostgreSQL": {Postgres, PostgresV2, PostgresV3},
	"MongoDB":    {Mongo},
	"Redis":      {REDIS},
	"Generic":    {GENERIC},
	"DNS":        {DNS},
}

// KindsOfProtocol are the kinds a call of protocol (a miss's
// UnmatchedCall.Protocol) is recorded as; none for a protocol keploy does not
// name.
func KindsOfProtocol(protocol string) []Kind {
	return protocolKinds[protocol]
}