mirror of https://github.com/vernonkeenan/lib
270 lines
9.0 KiB
Go
270 lines
9.0 KiB
Go
|
|
package research_client_test
|
||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"encoding/json"
|
||
|
|
"os"
|
||
|
|
"path/filepath"
|
||
|
|
"reflect"
|
||
|
|
"regexp"
|
||
|
|
"runtime"
|
||
|
|
"strings"
|
||
|
|
"testing"
|
||
|
|
|
||
|
|
"code.tnxs.net/vernonkeenan/lib/api/research/research_client/industry"
|
||
|
|
"code.tnxs.net/vernonkeenan/lib/api/research/research_client/industry_companies"
|
||
|
|
"code.tnxs.net/vernonkeenan/lib/api/research/research_client/industry_products"
|
||
|
|
"code.tnxs.net/vernonkeenan/lib/api/research/research_client/industry_services"
|
||
|
|
"code.tnxs.net/vernonkeenan/lib/api/research/research_models"
|
||
|
|
openapiruntime "github.com/go-openapi/runtime"
|
||
|
|
"github.com/go-openapi/strfmt"
|
||
|
|
)
|
||
|
|
|
||
|
|
type captureTransport struct {
|
||
|
|
operation *openapiruntime.ClientOperation
|
||
|
|
}
|
||
|
|
|
||
|
|
func (transport *captureTransport) Submit(operation *openapiruntime.ClientOperation) (any, error) {
|
||
|
|
return transport.SubmitContext(context.Background(), operation)
|
||
|
|
}
|
||
|
|
|
||
|
|
func (transport *captureTransport) SubmitContext(_ context.Context, operation *openapiruntime.ClientOperation) (any, error) {
|
||
|
|
transport.operation = operation
|
||
|
|
|
||
|
|
switch operation.ID {
|
||
|
|
case "getIndustries":
|
||
|
|
return industry.NewGetIndustriesOK(), nil
|
||
|
|
case "postIndustries":
|
||
|
|
return industry.NewPostIndustriesOK(), nil
|
||
|
|
case "putIndustries":
|
||
|
|
return industry.NewPutIndustriesOK(), nil
|
||
|
|
case "getIndustryCompanies":
|
||
|
|
return industry_companies.NewGetIndustryCompaniesOK(), nil
|
||
|
|
case "postIndustryCompanies":
|
||
|
|
return industry_companies.NewPostIndustryCompaniesOK(), nil
|
||
|
|
case "getIndustryProducts":
|
||
|
|
return industry_products.NewGetIndustryProductsOK(), nil
|
||
|
|
case "postIndustryProducts":
|
||
|
|
return industry_products.NewPostIndustryProductsOK(), nil
|
||
|
|
case "getIndustryServices":
|
||
|
|
return industry_services.NewGetIndustryServicesOK(), nil
|
||
|
|
case "postIndustryServices":
|
||
|
|
return industry_services.NewPostIndustryServicesOK(), nil
|
||
|
|
default:
|
||
|
|
panic("unexpected generated operation: " + operation.ID)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGeneratedIndustryOperationContract(t *testing.T) {
|
||
|
|
type operationCall func(openapiruntime.ContextualTransport) error
|
||
|
|
|
||
|
|
tests := []struct {
|
||
|
|
name string
|
||
|
|
wantID string
|
||
|
|
wantMethod string
|
||
|
|
wantPath string
|
||
|
|
call operationCall
|
||
|
|
}{
|
||
|
|
{
|
||
|
|
name: "list industries",
|
||
|
|
wantID: "getIndustries",
|
||
|
|
wantMethod: "GET",
|
||
|
|
wantPath: "/industries",
|
||
|
|
call: func(transport openapiruntime.ContextualTransport) error {
|
||
|
|
_, err := industry.New(transport, strfmt.Default).GetIndustries(industry.NewGetIndustriesParams(), nil)
|
||
|
|
return err
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "create industry",
|
||
|
|
wantID: "postIndustries",
|
||
|
|
wantMethod: "POST",
|
||
|
|
wantPath: "/industries",
|
||
|
|
call: func(transport openapiruntime.ContextualTransport) error {
|
||
|
|
_, err := industry.New(transport, strfmt.Default).PostIndustries(industry.NewPostIndustriesParams(), nil)
|
||
|
|
return err
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "update industry",
|
||
|
|
wantID: "putIndustries",
|
||
|
|
wantMethod: "PUT",
|
||
|
|
wantPath: "/industries",
|
||
|
|
call: func(transport openapiruntime.ContextualTransport) error {
|
||
|
|
_, err := industry.New(transport, strfmt.Default).PutIndustries(industry.NewPutIndustriesParams(), nil)
|
||
|
|
return err
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "list industry companies",
|
||
|
|
wantID: "getIndustryCompanies",
|
||
|
|
wantMethod: "GET",
|
||
|
|
wantPath: "/industrycompanies",
|
||
|
|
call: func(transport openapiruntime.ContextualTransport) error {
|
||
|
|
_, err := industry_companies.New(transport, strfmt.Default).GetIndustryCompanies(industry_companies.NewGetIndustryCompaniesParams(), nil)
|
||
|
|
return err
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "create industry company",
|
||
|
|
wantID: "postIndustryCompanies",
|
||
|
|
wantMethod: "POST",
|
||
|
|
wantPath: "/industrycompanies",
|
||
|
|
call: func(transport openapiruntime.ContextualTransport) error {
|
||
|
|
_, err := industry_companies.New(transport, strfmt.Default).PostIndustryCompanies(industry_companies.NewPostIndustryCompaniesParams(), nil)
|
||
|
|
return err
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "list industry products",
|
||
|
|
wantID: "getIndustryProducts",
|
||
|
|
wantMethod: "GET",
|
||
|
|
wantPath: "/industryproducts",
|
||
|
|
call: func(transport openapiruntime.ContextualTransport) error {
|
||
|
|
_, err := industry_products.New(transport, strfmt.Default).GetIndustryProducts(industry_products.NewGetIndustryProductsParams(), nil)
|
||
|
|
return err
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "create industry product",
|
||
|
|
wantID: "postIndustryProducts",
|
||
|
|
wantMethod: "POST",
|
||
|
|
wantPath: "/industryproducts",
|
||
|
|
call: func(transport openapiruntime.ContextualTransport) error {
|
||
|
|
_, err := industry_products.New(transport, strfmt.Default).PostIndustryProducts(industry_products.NewPostIndustryProductsParams(), nil)
|
||
|
|
return err
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "list industry services",
|
||
|
|
wantID: "getIndustryServices",
|
||
|
|
wantMethod: "GET",
|
||
|
|
wantPath: "/industryservices",
|
||
|
|
call: func(transport openapiruntime.ContextualTransport) error {
|
||
|
|
_, err := industry_services.New(transport, strfmt.Default).GetIndustryServices(industry_services.NewGetIndustryServicesParams(), nil)
|
||
|
|
return err
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "create industry service",
|
||
|
|
wantID: "postIndustryServices",
|
||
|
|
wantMethod: "POST",
|
||
|
|
wantPath: "/industryservices",
|
||
|
|
call: func(transport openapiruntime.ContextualTransport) error {
|
||
|
|
_, err := industry_services.New(transport, strfmt.Default).PostIndustryServices(industry_services.NewPostIndustryServicesParams(), nil)
|
||
|
|
return err
|
||
|
|
},
|
||
|
|
},
|
||
|
|
}
|
||
|
|
|
||
|
|
for _, test := range tests {
|
||
|
|
t.Run(test.name, func(t *testing.T) {
|
||
|
|
transport := &captureTransport{}
|
||
|
|
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 {
|
||
|
|
t.Errorf("operation ID = %q, want %q", transport.operation.ID, test.wantID)
|
||
|
|
}
|
||
|
|
if transport.operation.Method != test.wantMethod {
|
||
|
|
t.Errorf("method = %q, want %q", transport.operation.Method, test.wantMethod)
|
||
|
|
}
|
||
|
|
if transport.operation.PathPattern != test.wantPath {
|
||
|
|
t.Errorf("path = %q, want %q", transport.operation.PathPattern, test.wantPath)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestIndustryServiceDoesNotInventHTML(t *testing.T) {
|
||
|
|
serviceType := reflect.TypeOf(research_models.IndustryService{})
|
||
|
|
if _, exists := serviceType.FieldByName("HTML"); exists {
|
||
|
|
t.Fatal("IndustryService must not grow an HTML field absent from the authoritative contract")
|
||
|
|
}
|
||
|
|
|
||
|
|
productType := reflect.TypeOf(research_models.IndustryProduct{})
|
||
|
|
if _, exists := productType.FieldByName("HTML"); !exists {
|
||
|
|
t.Fatal("IndustryProduct must retain its authoritative HTML field")
|
||
|
|
}
|
||
|
|
|
||
|
|
payload, err := json.Marshal(research_models.IndustryService{ID: "industry-service-id"})
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("marshal IndustryService: %v", err)
|
||
|
|
}
|
||
|
|
if strings.Contains(string(payload), "HTML") {
|
||
|
|
t.Fatalf("IndustryService JSON invented an HTML field: %s", payload)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestIndustryJunctionContractDoesNotInventUpdateOperations(t *testing.T) {
|
||
|
|
interfaces := []struct {
|
||
|
|
name string
|
||
|
|
typ reflect.Type
|
||
|
|
}{
|
||
|
|
{name: "IndustryCompany", typ: reflect.TypeOf((*industry_companies.ClientService)(nil)).Elem()},
|
||
|
|
{name: "IndustryProduct", typ: reflect.TypeOf((*industry_products.ClientService)(nil)).Elem()},
|
||
|
|
{name: "IndustryService", typ: reflect.TypeOf((*industry_services.ClientService)(nil)).Elem()},
|
||
|
|
}
|
||
|
|
|
||
|
|
for _, contract := range interfaces {
|
||
|
|
for _, suffix := range []string{"", "Context"} {
|
||
|
|
method := "Put" + contract.name + suffix
|
||
|
|
if _, exists := contract.typ.MethodByName(method); exists {
|
||
|
|
t.Errorf("%s client invented unsupported operation %s", contract.name, method)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGeneratedIndustrySurfaceHasNoSalesforceOrEmbeddedSecrets(t *testing.T) {
|
||
|
|
_, testFile, _, ok := runtime.Caller(0)
|
||
|
|
if !ok {
|
||
|
|
t.Fatal("resolve test source path")
|
||
|
|
}
|
||
|
|
clientRoot := filepath.Dir(testFile)
|
||
|
|
modelRoot := filepath.Join(clientRoot, "..", "research_models")
|
||
|
|
targets := []string{
|
||
|
|
filepath.Join(clientRoot, "industry"),
|
||
|
|
filepath.Join(clientRoot, "industry_companies"),
|
||
|
|
filepath.Join(clientRoot, "industry_products"),
|
||
|
|
filepath.Join(clientRoot, "industry_services"),
|
||
|
|
filepath.Join(modelRoot, "industry.go"),
|
||
|
|
filepath.Join(modelRoot, "industry_company.go"),
|
||
|
|
filepath.Join(modelRoot, "industry_product.go"),
|
||
|
|
filepath.Join(modelRoot, "industry_service.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-----"} {
|
||
|
|
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 contract target %s: %v", target, err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|