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/transactions" "code.tnxs.net/vernonkeenan/lib/api/members/members_models" openapiruntime "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" ) type transactionCaptureTransport struct { operation *openapiruntime.ClientOperation } func (transport *transactionCaptureTransport) Submit( operation *openapiruntime.ClientOperation, ) (any, error) { return transport.SubmitContext(context.Background(), operation) } func (transport *transactionCaptureTransport) SubmitContext( _ context.Context, operation *openapiruntime.ClientOperation, ) (any, error) { transport.operation = operation switch operation.ID { case "getTransactions": return transactions.NewGetTransactionsOK(), nil case "postTransactions": return transactions.NewPostTransactionsOK(), nil case "putTransactions": return transactions.NewPutTransactionsOK(), nil default: panic("unexpected generated Transaction operation: " + operation.ID) } } func TestGeneratedTransactionOperationContract(t *testing.T) { tenantID := strfmt.UUID("55555555-5555-4555-8555-555555555555") auth := openapiruntime.ClientAuthInfoWriterFunc( func(openapiruntime.ClientRequest, strfmt.Registry) error { return nil }, ) type operationCall func(openapiruntime.ContextualTransport) error tests := []struct { name, wantID, wantMethod string call operationCall }{ { name: "list or get", wantID: "getTransactions", wantMethod: "GET", call: func(transport openapiruntime.ContextualTransport) error { _, err := transactions.New(transport, strfmt.Default).GetTransactions( transactions.NewGetTransactionsParams().WithTenantID(tenantID), auth, ) return err }, }, { name: "create", wantID: "postTransactions", wantMethod: "POST", call: func(transport openapiruntime.ContextualTransport) error { _, err := transactions.New(transport, strfmt.Default).PostTransactions( transactions.NewPostTransactionsParams().WithTenantID(tenantID), auth, ) return err }, }, { name: "CAS transition", wantID: "putTransactions", wantMethod: "PUT", call: func(transport openapiruntime.ContextualTransport) error { _, err := transactions.New(transport, strfmt.Default).PutTransactions( transactions.NewPutTransactionsParams().WithTenantID(tenantID), auth, ) return err }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { transport := &transactionCaptureTransport{} 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 != "/transactions" { t.Fatalf( "operation = %s %s %s, want %s %s /transactions", 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 TestTransactionTenantBindingExactScopesAndCAS(t *testing.T) { specText := readMembersLearningSpec(t) pathBlock := learningSpecPathBlock(t, specText, "/transactions") for _, forbidden := range []string{" delete:", " patch:"} { if strings.Contains(pathBlock, forbidden) { t.Errorf("/transactions exposes unsupported %s", strings.TrimSpace(forbidden)) } } operations := map[string]struct{ id, scope string }{ "get": {id: "getTransactions", scope: "members:transaction:read"}, "post": {id: "postTransactions", scope: "members:transaction:create"}, "put": {id: "putTransactions", scope: "members:transaction:update"}, } const compoundSecurity = " security:\n - ApiKeyAuth: []\n kvSessionCookie: []" for method, expected := range operations { block := learningSpecOperationBlock(t, specText, "/transactions", method) if !strings.Contains(block, " operationId: "+expected.id+"\n") { t.Errorf("%s /transactions lost operationId %q", strings.ToUpper(method), expected.id) } if strings.Count(block, compoundSecurity) != 1 { t.Errorf("%s /transactions does not preserve compound authentication", strings.ToUpper(method)) } if !strings.Contains(block, expected.scope) { t.Errorf("%s /transactions lost exact scope %q", strings.ToUpper(method), expected.scope) } if !strings.Contains(block, `- $ref: "#/parameters/transactionTenantId"`) { t.Errorf("%s /transactions is not tenantId-bound", strings.ToUpper(method)) } } tenantID := strfmt.UUID("55555555-5555-4555-8555-555555555555") recordID := strfmt.UUID("66666666-6666-4666-8666-666666666666") get := transactions.NewGetTransactionsParams(). WithTenantID(tenantID). WithTransactionID(&recordID) if get.TenantID != tenantID || get.TransactionID == nil || *get.TransactionID != recordID { t.Fatal("Transaction list/get client lost its tenant or record filter") } if transactions.NewPostTransactionsParams().WithTenantID(tenantID).TenantID != tenantID { t.Fatal("Transaction create client lost required tenantId") } if transactions.NewPutTransactionsParams().WithTenantID(tenantID).TenantID != tenantID { t.Fatal("Transaction update client lost required tenantId") } if !transactions.NewPutTransactionsConflict().IsCode(409) { t.Fatal("Transaction update client lost optimistic concurrency response") } } func TestTransactionModelIsExactDecimalAndPaymentTokenFree(t *testing.T) { assertExactModelFields(t, members_models.Transaction{}, map[string]string{ "Amount": "string", "CreatedByID": "*strfmt.UUID", "CreatedDate": "*strfmt.DateTime", "Currency": "string", "ID": "strfmt.UUID", "LastModifiedByID": "*strfmt.UUID", "LastModifiedDate": "*strfmt.DateTime", "Status": "*string", "TenantID": "*strfmt.UUID", "TransactionDate": "*strfmt.DateTime", }) valid := &members_models.TransactionRequest{Data: []*members_models.Transaction{{ Amount: "10.25", Currency: "USD", }}} if err := valid.Validate(strfmt.Default); err != nil { t.Fatalf("generated Transaction request rejected one valid record: %v", err) } valid.Data = append(valid.Data, &members_models.Transaction{Amount: "11.00", Currency: "USD"}) if err := valid.Validate(strfmt.Default); err == nil { t.Fatal("generated Transaction request accepted a bulk payload") } } func TestTransactionSurfaceHasNoDeleteOrProtectedRelationshipMethods(t *testing.T) { contract := reflect.TypeOf((*transactions.ClientService)(nil)).Elem() for index := 0; index < contract.NumMethod(); index++ { method := contract.Method(index).Name for _, forbidden := range []string{ "Delete", "Payment", "Processor", "Database", "DSN", } { if strings.Contains(method, forbidden) { t.Errorf("Transaction client exposes forbidden method %s", method) } } } root := reflect.TypeOf(members_client.Members{}) if _, exists := root.FieldByName("Transactions"); !exists { t.Fatal("root Members client does not expose governed Transactions") } } func TestGeneratedTransactionSurfaceHasNoExternalBypassOrSecrets(t *testing.T) { repoRoot := learningRepoRoot(t) targets := []string{ filepath.Join(repoRoot, "api", "members", "members_client", "transactions"), filepath.Join(repoRoot, "api", "members", "members_models", "transaction.go"), filepath.Join(repoRoot, "api", "members", "members_models", "transaction_request.go"), filepath.Join(repoRoot, "api", "members", "members_models", "transaction_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", "sf-gate", "go-force", "private key-----", "members_client/databases", "processortoken", "dsn", } { if strings.Contains(lower, forbidden) { t.Errorf("%s contains forbidden boundary %q", path, forbidden) } } if credentialLiteral.Match(content) { t.Errorf("%s contains a credential-shaped literal", path) } return nil }) if err != nil { t.Fatalf("scan generated Transaction target %s: %v", target, err) } } }