lib/api/members/members_client/document_parameter_contract...

237 lines
8.4 KiB
Go
Raw Normal View History

package members_client_test
import (
"context"
"os"
"path/filepath"
"reflect"
"regexp"
"strings"
"testing"
"code.tnxs.net/vernonkeenan/lib/api/members/members_client"
"code.tnxs.net/vernonkeenan/lib/api/members/members_client/document_parameters"
"code.tnxs.net/vernonkeenan/lib/api/members/members_models"
openapiruntime "github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
)
var documentParameterTestAuth = openapiruntime.ClientAuthInfoWriterFunc(
func(openapiruntime.ClientRequest, strfmt.Registry) error { return nil },
)
type documentParameterCaptureTransport struct {
operation *openapiruntime.ClientOperation
}
func (transport *documentParameterCaptureTransport) Submit(
operation *openapiruntime.ClientOperation,
) (any, error) {
return transport.SubmitContext(context.Background(), operation)
}
func (transport *documentParameterCaptureTransport) SubmitContext(
_ context.Context,
operation *openapiruntime.ClientOperation,
) (any, error) {
transport.operation = operation
switch operation.ID {
case "getDocumentParameters":
return document_parameters.NewGetDocumentParametersOK(), nil
case "postDocumentParameters":
return document_parameters.NewPostDocumentParametersOK(), nil
case "putDocumentParameters":
return document_parameters.NewPutDocumentParametersOK(), nil
default:
panic("unexpected generated DocumentParameter operation: " + operation.ID)
}
}
func TestGeneratedDocumentParameterOperationContract(t *testing.T) {
type operationCall func(openapiruntime.ContextualTransport) error
tests := []struct {
name, wantID, wantMethod string
call operationCall
}{
{
name: "list or get", wantID: "getDocumentParameters", wantMethod: "GET",
call: func(transport openapiruntime.ContextualTransport) error {
_, err := document_parameters.New(transport, strfmt.Default).
GetDocumentParameters(
document_parameters.NewGetDocumentParametersParams(),
documentParameterTestAuth,
)
return err
},
},
{
name: "create", wantID: "postDocumentParameters", wantMethod: "POST",
call: func(transport openapiruntime.ContextualTransport) error {
_, err := document_parameters.New(transport, strfmt.Default).
PostDocumentParameters(
document_parameters.NewPostDocumentParametersParams(),
documentParameterTestAuth,
)
return err
},
},
{
name: "CAS update", wantID: "putDocumentParameters", wantMethod: "PUT",
call: func(transport openapiruntime.ContextualTransport) error {
_, err := document_parameters.New(transport, strfmt.Default).
PutDocumentParameters(
document_parameters.NewPutDocumentParametersParams(),
documentParameterTestAuth,
)
return err
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
transport := &documentParameterCaptureTransport{}
if err := test.call(transport); err != nil {
t.Fatalf("generated client operation failed: %v", err)
}
if transport.operation == nil {
t.Fatal("generated client did not submit an operation")
}
if transport.operation.ID != test.wantID ||
transport.operation.Method != test.wantMethod ||
transport.operation.PathPattern != "/documentparameters" {
t.Fatalf(
"operation = %s %s %s, want %s %s /documentparameters",
transport.operation.ID, transport.operation.Method,
transport.operation.PathPattern, test.wantID, test.wantMethod,
)
}
if transport.operation.AuthInfo == nil {
t.Fatal("generated operation discarded its compound auth writer")
}
})
}
}
func TestDocumentParameterSpecPreservesScopesPersonasAndCAS(t *testing.T) {
specText := readMembersLearningSpec(t)
pathBlock := learningSpecPathBlock(t, specText, "/documentparameters")
for _, forbidden := range []string{" delete:", " patch:"} {
if strings.Contains(pathBlock, forbidden) {
t.Errorf("/documentparameters exposes unsupported %s", strings.TrimSpace(forbidden))
}
}
operations := map[string]struct{ id, scope string }{
"get": {id: "getDocumentParameters", scope: "members:document-parameter:read"},
"post": {id: "postDocumentParameters", scope: "members:document-parameter:create"},
"put": {id: "putDocumentParameters", scope: "members:document-parameter:update"},
}
const compoundSecurity = " security:\n - ApiKeyAuth: []\n kvSessionCookie: []"
for method, expected := range operations {
block := learningSpecOperationBlock(t, specText, "/documentparameters", method)
if !strings.Contains(block, " operationId: "+expected.id+"\n") {
t.Errorf("%s lost operationId %q", strings.ToUpper(method), expected.id)
}
if strings.Count(block, compoundSecurity) != 1 {
t.Errorf("%s does not preserve compound authentication", strings.ToUpper(method))
}
if !strings.Contains(block, expected.scope) {
t.Errorf("%s lost exact scope %q", strings.ToUpper(method), expected.scope)
}
if method != "get" &&
(!strings.Contains(block, "Owner") || !strings.Contains(block, "Manager")) {
t.Errorf("%s lost Owner/Manager mutation boundary", strings.ToUpper(method))
}
}
if !document_parameters.NewPutDocumentParametersConflict().IsCode(409) {
t.Fatal("DocumentParameter update client lost stale-write conflict")
}
}
func TestDocumentParameterModelAndRequestAreBounded(t *testing.T) {
assertExactModelFields(t, members_models.DocumentParameter{}, map[string]string{
"CreatedByID": "*string", "CreatedDate": "*string", "DeletedDate": "*string",
"DocumentID": "*string", "ID": "string", "IsDeleted": "*bool",
"LastModifiedByID": "*string", "LastModifiedDate": "*string",
"Name": "*string", "TenantID": "*string", "UserID": "*string",
"Value": "*string",
})
request := &members_models.DocumentParameterRequest{}
if err := request.Validate(strfmt.Default); err == nil {
t.Fatal("generated request accepted an empty write batch")
}
request.Data = make([]*members_models.DocumentParameter, 101)
if err := request.Validate(strfmt.Default); err == nil {
t.Fatal("generated request accepted more than 100 records")
}
request.Data = []*members_models.DocumentParameter{{}}
if err := request.Validate(strfmt.Default); err != nil {
t.Fatalf("generated request rejected a bounded record: %v", err)
}
}
func TestDocumentParameterSurfaceExposesNoDeleteOrFolderBypass(t *testing.T) {
contract := reflect.TypeOf((*document_parameters.ClientService)(nil)).Elem()
for index := 0; index < contract.NumMethod(); index++ {
method := contract.Method(index).Name
for _, forbidden := range []string{"Delete", "Folder", "Salesforce", "Cache"} {
if strings.Contains(method, forbidden) {
t.Errorf("DocumentParameter client exposes forbidden method %s", method)
}
}
}
root := reflect.TypeOf(members_client.Members{})
if _, exists := root.FieldByName("DocumentParameters"); !exists {
t.Fatal("root Members client does not expose governed DocumentParameters")
}
if _, exists := root.FieldByName("Folders"); exists {
t.Fatal("root Members client published deferred Folder operations")
}
}
func TestGeneratedDocumentParameterSurfaceHasNoExternalBypassOrSecrets(t *testing.T) {
repoRoot := learningRepoRoot(t)
targets := []string{
filepath.Join(repoRoot, "api", "members", "members_client", "document_parameters"),
filepath.Join(repoRoot, "api", "members", "members_models", "document_parameter.go"),
filepath.Join(repoRoot, "api", "members", "members_models", "document_parameter_request.go"),
filepath.Join(repoRoot, "api", "members", "members_models", "document_parameter_response.go"),
}
credentialLiteral := regexp.MustCompile(
`(?i)(api[_-]?key|password|secret)\s*[:=]\s*["'][^"']+["']`,
)
for _, target := range targets {
err := filepath.WalkDir(target, func(
path string, entry os.DirEntry, walkErr error,
) error {
if walkErr != nil {
return walkErr
}
if entry.IsDir() || !strings.HasSuffix(path, ".go") ||
strings.HasSuffix(path, "_test.go") {
return nil
}
content, err := os.ReadFile(path)
if err != nil {
return err
}
lower := strings.ToLower(string(content))
for _, forbidden := range []string{
"salesforce", "soql", "apex", "sf-gate", "go-force",
"cache", "processor_token", "private key-----",
} {
if strings.Contains(lower, forbidden) {
t.Errorf("%s contains forbidden boundary %q", path, forbidden)
}
}
if credentialLiteral.Match(content) {
t.Errorf("%s contains a credential-like literal", path)
}
return nil
})
if err != nil {
t.Fatalf("inspect generated DocumentParameter surface: %v", err)
}
}
}