2026-07-24 05:36:20 +00:00
package members_client_test
import (
"bytes"
"context"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"os"
"path/filepath"
"reflect"
"regexp"
"runtime"
"strings"
"testing"
"code.tnxs.net/vernonkeenan/lib/api/members/members_client/courses"
"code.tnxs.net/vernonkeenan/lib/api/members/members_client/enrollments"
"code.tnxs.net/vernonkeenan/lib/api/members/members_client/issued_certificates"
"code.tnxs.net/vernonkeenan/lib/api/members/members_client/lesson_progress"
"code.tnxs.net/vernonkeenan/lib/api/members/members_models"
openapiruntime "github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
)
2026-07-24 14:54:36 +00:00
const membersProviderSpecSHA256 = "6f60547e3faf342bf4b9f6aad15eebfde0cd553f60550f67d71e469dbd83cc7f"
2026-07-24 05:36:20 +00:00
var learningTestAuth = openapiruntime . ClientAuthInfoWriterFunc ( func ( openapiruntime . ClientRequest , strfmt . Registry ) error {
return nil
} )
type learningCaptureTransport struct {
operation * openapiruntime . ClientOperation
}
func ( transport * learningCaptureTransport ) Submit ( operation * openapiruntime . ClientOperation ) ( any , error ) {
return transport . SubmitContext ( context . Background ( ) , operation )
}
func ( transport * learningCaptureTransport ) SubmitContext ( _ context . Context , operation * openapiruntime . ClientOperation ) ( any , error ) {
transport . operation = operation
switch operation . ID {
case "getCourses" :
return courses . NewGetCoursesOK ( ) , nil
case "postCourses" :
return courses . NewPostCoursesOK ( ) , nil
case "updateCourses" :
return courses . NewUpdateCoursesOK ( ) , nil
case "getCourseSections" :
return courses . NewGetCourseSectionsOK ( ) , nil
case "postCourseSections" :
return courses . NewPostCourseSectionsOK ( ) , nil
case "updateCourseSections" :
return courses . NewUpdateCourseSectionsOK ( ) , nil
case "getCourseLessons" :
return courses . NewGetCourseLessonsOK ( ) , nil
case "postCourseLessons" :
return courses . NewPostCourseLessonsOK ( ) , nil
case "updateCourseLessons" :
return courses . NewUpdateCourseLessonsOK ( ) , nil
case "getEnrollments" :
return enrollments . NewGetEnrollmentsOK ( ) , nil
case "postEnrollments" :
return enrollments . NewPostEnrollmentsOK ( ) , nil
case "putEnrollments" :
return enrollments . NewPutEnrollmentsOK ( ) , nil
case "getLessonProgresses" :
return lesson_progress . NewGetLessonProgressesOK ( ) , nil
case "postLessonProgresses" :
return lesson_progress . NewPostLessonProgressesOK ( ) , nil
case "putLessonProgresses" :
return lesson_progress . NewPutLessonProgressesOK ( ) , nil
case "getIssuedCertificates" :
return issued_certificates . NewGetIssuedCertificatesOK ( ) , nil
default :
panic ( "unexpected generated Learning operation: " + operation . ID )
}
}
func TestGeneratedLearningOperationContract ( t * testing . T ) {
type operationCall func ( openapiruntime . ContextualTransport ) error
tests := [ ] struct {
name string
wantID string
wantMethod string
wantPath string
call operationCall
} {
{
name : "list courses" , wantID : "getCourses" , wantMethod : "GET" , wantPath : "/courses" ,
call : func ( transport openapiruntime . ContextualTransport ) error {
_ , err := courses . New ( transport , strfmt . Default ) . GetCourses ( courses . NewGetCoursesParams ( ) , learningTestAuth )
return err
} ,
} ,
{
name : "create course" , wantID : "postCourses" , wantMethod : "POST" , wantPath : "/courses" ,
call : func ( transport openapiruntime . ContextualTransport ) error {
_ , err := courses . New ( transport , strfmt . Default ) . PostCourses ( courses . NewPostCoursesParams ( ) , learningTestAuth )
return err
} ,
} ,
{
name : "update course" , wantID : "updateCourses" , wantMethod : "PUT" , wantPath : "/courses" ,
call : func ( transport openapiruntime . ContextualTransport ) error {
_ , err := courses . New ( transport , strfmt . Default ) . UpdateCourses ( courses . NewUpdateCoursesParams ( ) , learningTestAuth )
return err
} ,
} ,
{
name : "list sections" , wantID : "getCourseSections" , wantMethod : "GET" , wantPath : "/coursesections" ,
call : func ( transport openapiruntime . ContextualTransport ) error {
_ , err := courses . New ( transport , strfmt . Default ) . GetCourseSections ( courses . NewGetCourseSectionsParams ( ) , learningTestAuth )
return err
} ,
} ,
{
name : "create section" , wantID : "postCourseSections" , wantMethod : "POST" , wantPath : "/coursesections" ,
call : func ( transport openapiruntime . ContextualTransport ) error {
_ , err := courses . New ( transport , strfmt . Default ) . PostCourseSections ( courses . NewPostCourseSectionsParams ( ) , learningTestAuth )
return err
} ,
} ,
{
name : "update section" , wantID : "updateCourseSections" , wantMethod : "PUT" , wantPath : "/coursesections" ,
call : func ( transport openapiruntime . ContextualTransport ) error {
_ , err := courses . New ( transport , strfmt . Default ) . UpdateCourseSections ( courses . NewUpdateCourseSectionsParams ( ) , learningTestAuth )
return err
} ,
} ,
{
name : "list lessons" , wantID : "getCourseLessons" , wantMethod : "GET" , wantPath : "/courselessons" ,
call : func ( transport openapiruntime . ContextualTransport ) error {
_ , err := courses . New ( transport , strfmt . Default ) . GetCourseLessons ( courses . NewGetCourseLessonsParams ( ) , learningTestAuth )
return err
} ,
} ,
{
name : "create lesson" , wantID : "postCourseLessons" , wantMethod : "POST" , wantPath : "/courselessons" ,
call : func ( transport openapiruntime . ContextualTransport ) error {
_ , err := courses . New ( transport , strfmt . Default ) . PostCourseLessons ( courses . NewPostCourseLessonsParams ( ) , learningTestAuth )
return err
} ,
} ,
{
name : "update lesson" , wantID : "updateCourseLessons" , wantMethod : "PUT" , wantPath : "/courselessons" ,
call : func ( transport openapiruntime . ContextualTransport ) error {
_ , err := courses . New ( transport , strfmt . Default ) . UpdateCourseLessons ( courses . NewUpdateCourseLessonsParams ( ) , learningTestAuth )
return err
} ,
} ,
{
name : "list enrollments" , wantID : "getEnrollments" , wantMethod : "GET" , wantPath : "/enrollments" ,
call : func ( transport openapiruntime . ContextualTransport ) error {
_ , err := enrollments . New ( transport , strfmt . Default ) . GetEnrollments ( enrollments . NewGetEnrollmentsParams ( ) , learningTestAuth )
return err
} ,
} ,
{
name : "create enrollment" , wantID : "postEnrollments" , wantMethod : "POST" , wantPath : "/enrollments" ,
call : func ( transport openapiruntime . ContextualTransport ) error {
_ , err := enrollments . New ( transport , strfmt . Default ) . PostEnrollments ( enrollments . NewPostEnrollmentsParams ( ) , learningTestAuth )
return err
} ,
} ,
{
name : "update enrollment" , wantID : "putEnrollments" , wantMethod : "PUT" , wantPath : "/enrollments" ,
call : func ( transport openapiruntime . ContextualTransport ) error {
_ , err := enrollments . New ( transport , strfmt . Default ) . PutEnrollments ( enrollments . NewPutEnrollmentsParams ( ) , learningTestAuth )
return err
} ,
} ,
{
name : "list lesson progress" , wantID : "getLessonProgresses" , wantMethod : "GET" , wantPath : "/lessonprogress" ,
call : func ( transport openapiruntime . ContextualTransport ) error {
_ , err := lesson_progress . New ( transport , strfmt . Default ) . GetLessonProgresses ( lesson_progress . NewGetLessonProgressesParams ( ) , learningTestAuth )
return err
} ,
} ,
{
name : "create lesson progress" , wantID : "postLessonProgresses" , wantMethod : "POST" , wantPath : "/lessonprogress" ,
call : func ( transport openapiruntime . ContextualTransport ) error {
_ , err := lesson_progress . New ( transport , strfmt . Default ) . PostLessonProgresses ( lesson_progress . NewPostLessonProgressesParams ( ) , learningTestAuth )
return err
} ,
} ,
{
name : "update lesson progress" , wantID : "putLessonProgresses" , wantMethod : "PUT" , wantPath : "/lessonprogress" ,
call : func ( transport openapiruntime . ContextualTransport ) error {
_ , err := lesson_progress . New ( transport , strfmt . Default ) . PutLessonProgresses ( lesson_progress . NewPutLessonProgressesParams ( ) , learningTestAuth )
return err
} ,
} ,
{
name : "list issued certificates" , wantID : "getIssuedCertificates" , wantMethod : "GET" , wantPath : "/issuedcertificates" ,
call : func ( transport openapiruntime . ContextualTransport ) error {
_ , err := issued_certificates . New ( transport , strfmt . Default ) . GetIssuedCertificates ( issued_certificates . NewGetIssuedCertificatesParams ( ) , learningTestAuth )
return err
} ,
} ,
}
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
transport := & learningCaptureTransport { }
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 )
}
if transport . operation . AuthInfo == nil {
t . Error ( "generated operation discarded its auth-info writer" )
}
} )
}
}
func TestLearningSpecRequiresExactCompoundAuthentication ( t * testing . T ) {
specText := readMembersLearningSpec ( t )
for _ , definition := range [ ] string {
" ApiKeyAuth:\n type: \"apiKey\"\n in: \"header\"\n name: \"X-API-Key\"" ,
" kvSessionCookie:\n name: Cookie\n in: header\n type: apiKey" ,
} {
if ! strings . Contains ( specText , definition ) {
t . Fatalf ( "authoritative spec is missing exact authentication definition:\n%s" , definition )
}
}
operations := map [ string ] map [ string ] string {
"/courses" : {
"get" : "getCourses" ,
"post" : "postCourses" ,
"put" : "updateCourses" ,
} ,
"/coursesections" : {
"get" : "getCourseSections" ,
"post" : "postCourseSections" ,
"put" : "updateCourseSections" ,
} ,
"/courselessons" : {
"get" : "getCourseLessons" ,
"post" : "postCourseLessons" ,
"put" : "updateCourseLessons" ,
} ,
"/enrollments" : {
"get" : "getEnrollments" ,
"post" : "postEnrollments" ,
"put" : "putEnrollments" ,
} ,
"/lessonprogress" : {
"get" : "getLessonProgresses" ,
"post" : "postLessonProgresses" ,
"put" : "putLessonProgresses" ,
} ,
"/issuedcertificates" : {
"get" : "getIssuedCertificates" ,
} ,
}
for path , methods := range operations {
for method , operationID := range methods {
operation := learningSpecOperationBlock ( t , specText , path , method )
if ! strings . Contains ( operation , " operationId: " + operationID + "\n" ) {
t . Errorf ( "%s %s does not preserve operationId %q" , strings . ToUpper ( method ) , path , operationID )
}
const compoundSecurity = " security:\n - ApiKeyAuth: []\n kvSessionCookie: []"
if strings . Count ( operation , compoundSecurity ) != 1 {
t . Errorf ( "%s %s does not require the exact API-key + human-session compound security" , strings . ToUpper ( method ) , path )
}
}
}
}
func TestLearningUpdateClientsPreserveConflictResponses ( t * testing . T ) {
conflicts := [ ] interface { IsCode ( int ) bool } {
courses . NewUpdateCoursesConflict ( ) ,
courses . NewUpdateCourseSectionsConflict ( ) ,
courses . NewUpdateCourseLessonsConflict ( ) ,
enrollments . NewPutEnrollmentsConflict ( ) ,
lesson_progress . NewPutLessonProgressesConflict ( ) ,
}
for _ , conflict := range conflicts {
if ! conflict . IsCode ( 409 ) {
t . Errorf ( "%T does not preserve the optimistic-conflict response" , conflict )
}
}
}
func TestLearningGetOperationsPreserveIDFilters ( t * testing . T ) {
recordID := "record-id"
filters := [ ] struct {
name string
got * string
} {
{ name : "Course" , got : courses . NewGetCoursesParams ( ) . WithID ( & recordID ) . ID } ,
{ name : "CourseSection" , got : courses . NewGetCourseSectionsParams ( ) . WithID ( & recordID ) . ID } ,
{ name : "CourseLesson" , got : courses . NewGetCourseLessonsParams ( ) . WithID ( & recordID ) . ID } ,
{ name : "Enrollment" , got : enrollments . NewGetEnrollmentsParams ( ) . WithID ( & recordID ) . ID } ,
{ name : "LessonProgress" , got : lesson_progress . NewGetLessonProgressesParams ( ) . WithID ( & recordID ) . ID } ,
{ name : "IssuedCertificate" , got : issued_certificates . NewGetIssuedCertificatesParams ( ) . WithID ( & recordID ) . ID } ,
}
for _ , filter := range filters {
if filter . got == nil || * filter . got != recordID {
t . Errorf ( "%s get-by-ID filter is absent" , filter . name )
}
}
}
func TestLearningModelsMatchSanitizedProviderContract ( t * testing . T ) {
assertExactModelFields ( t , members_models . Course { } , map [ string ] string {
"CreatedByID" : "*string" , "CreatedDate" : "*string" , "Description" : "*string" ,
"Fulldescription" : "*string" , "ID" : "string" , "ImageAltText" : "*string" ,
"ImageURL" : "*string" , "InstructorID" : "*string" , "LastModifiedByID" : "*string" ,
"LastModifiedDate" : "*string" , "Logo" : "*string" , "Price" : "*string" ,
"Slug" : "*string" , "TemplateID" : "*string" , "Title" : "*string" ,
} )
assertExactModelFields ( t , members_models . CourseSection { } , map [ string ] string {
"Content" : "*string" , "CourseID" : "*string" , "CreatedByID" : "*string" ,
"CreatedDate" : "*string" , "ID" : "string" , "ImageAltText" : "*string" ,
"ImageURL" : "*string" , "LastModifiedByID" : "*string" , "LastModifiedDate" : "*string" ,
"Logo" : "*string" , "Order" : "*int64" , "Slug" : "*string" , "Title" : "*string" ,
} )
assertExactModelFields ( t , members_models . CourseLesson { } , map [ string ] string {
"Content" : "*string" , "CreatedByID" : "*string" , "CreatedDate" : "*string" ,
"ID" : "string" , "ImageAltText" : "*string" , "ImageURL" : "*string" ,
"LastModifiedByID" : "*string" , "LastModifiedDate" : "*string" , "Logo" : "*string" ,
"Order" : "*int64" , "SectionID" : "*string" , "Slug" : "*string" ,
"Title" : "*string" , "VideoURL" : "*string" ,
} )
assertExactModelFields ( t , members_models . Enrollment { } , map [ string ] string {
"Completed" : "*bool" , "CourseID" : "*string" , "CreatedByID" : "*string" ,
"CreatedDate" : "*string" , "EnrollmentDate" : "*strfmt.Date" , "ID" : "string" ,
"LastModifiedByID" : "*string" , "LastModifiedDate" : "*string" , "UserID" : "*string" ,
} )
assertExactModelFields ( t , members_models . LessonProgress { } , map [ string ] string {
"Completed" : "bool" , "CompletedAt" : "*string" , "CreatedByID" : "*string" ,
"CreatedDate" : "*string" , "EnrollmentID" : "*string" , "ID" : "string" ,
"LastModifiedByID" : "*string" , "LastModifiedDate" : "*string" , "LessonID" : "*string" ,
"TenantID" : "*string" , "UserID" : "*string" ,
} )
assertExactModelFields ( t , members_models . IssuedCertificate { } , map [ string ] string {
"AccountID" : "*string" , "CreatedByID" : "*string" , "CreatedDate" : "*string" ,
"EnrollmentID" : "*string" , "ExpirationDate" : "*string" , "ID" : "string" ,
"IssueDate" : "*string" , "LastModifiedByID" : "*string" , "LastModifiedDate" : "*string" ,
"TemplateID" : "*string" , "UserID" : "*string" ,
} )
price := "125.50"
if err := ( & members_models . Course { Price : & price } ) . Validate ( strfmt . Default ) ; err != nil {
t . Fatalf ( "valid exact-decimal Course.Price rejected: %v" , err )
}
unsafePrice := "125.505"
if err := ( & members_models . Course { Price : & unsafePrice } ) . Validate ( strfmt . Default ) ; err == nil {
t . Fatal ( "Course.Price accepted a value outside DECIMAL(10,2)" )
}
body , err := json . Marshal ( members_models . IssuedCertificate { ID : "issued-certificate-id" } )
if err != nil {
t . Fatalf ( "marshal IssuedCertificate: %v" , err )
}
for _ , forbidden := range [ ] string { "VerificationCode" , "CertificateID" } {
if bytes . Contains ( body , [ ] byte ( forbidden ) ) {
t . Errorf ( "sanitized IssuedCertificate JSON exposes %s: %s" , forbidden , body )
}
}
}
func TestLearningSingleRecordRequestsRejectBulkPayloads ( t * testing . T ) {
tests := [ ] struct {
name string
validate func ( ) error
} {
{
name : "course" ,
validate : func ( ) error {
return ( & members_models . CourseRequest { Data : [ ] * members_models . Course { { } , { } } } ) . Validate ( strfmt . Default )
} ,
} ,
{
name : "course section" ,
validate : func ( ) error {
return ( & members_models . CourseSectionRequest { Data : [ ] * members_models . CourseSection { { } , { } } } ) . Validate ( strfmt . Default )
} ,
} ,
{
name : "course lesson" ,
validate : func ( ) error {
return ( & members_models . CourseLessonRequest { Data : [ ] * members_models . CourseLesson { { } , { } } } ) . Validate ( strfmt . Default )
} ,
} ,
{
name : "enrollment" ,
validate : func ( ) error {
return ( & members_models . EnrollmentRequest { Data : [ ] * members_models . Enrollment { { } , { } } } ) . Validate ( strfmt . Default )
} ,
} ,
{
name : "lesson progress" ,
validate : func ( ) error {
return ( & members_models . LessonProgressRequest { Data : [ ] * members_models . LessonProgress { { } , { } } } ) . Validate ( strfmt . Default )
} ,
} ,
}
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
if err := test . validate ( ) ; err == nil {
t . Fatal ( "generated single-record request accepted a bulk payload" )
}
} )
}
}
func TestLearningLifecycleBoundariesRemainVisible ( t * testing . T ) {
specText := readMembersLearningSpec ( t )
expectations := [ ] struct {
path string
method string
terms [ ] string
} {
{ path : "/coursesections" , method : "put" , terms : [ ] string { "CourseID is immutable" } } ,
{ path : "/courselessons" , method : "put" , terms : [ ] string { "SectionID is immutable" } } ,
{ path : "/enrollments" , method : "put" , terms : [ ] string { "UserID and CourseID are immutable" , "completion is monotonic" } } ,
{ path : "/lessonprogress" , method : "put" , terms : [ ] string { "TenantID, UserID, EnrollmentID, and LessonID are immutable" , "completion is monotonic" , "CompletedAt is server-owned" } } ,
{ path : "/issuedcertificates" , method : "get" , terms : [ ] string { "verification material is never returned" , "Issuance, mutation, revocation, and deletion" , "intentionally unavailable" } } ,
}
for _ , expectation := range expectations {
block := learningSpecOperationBlock ( t , specText , expectation . path , expectation . method )
for _ , term := range expectation . terms {
if ! strings . Contains ( block , term ) {
t . Errorf ( "%s %s lost lifecycle boundary %q" , strings . ToUpper ( expectation . method ) , expectation . path , term )
}
}
}
}
func TestLearningSurfaceOmitsUnsafeCertificateAndDeleteOperations ( t * testing . T ) {
contracts := [ ] struct {
name string
typ reflect . Type
} {
{ name : "Courses" , typ : reflect . TypeOf ( ( * courses . ClientService ) ( nil ) ) . Elem ( ) } ,
{ name : "Enrollments" , typ : reflect . TypeOf ( ( * enrollments . ClientService ) ( nil ) ) . Elem ( ) } ,
{ name : "LessonProgress" , typ : reflect . TypeOf ( ( * lesson_progress . ClientService ) ( nil ) ) . Elem ( ) } ,
{ name : "IssuedCertificates" , typ : reflect . TypeOf ( ( * issued_certificates . ClientService ) ( nil ) ) . Elem ( ) } ,
}
for _ , contract := range contracts {
for index := 0 ; index < contract . typ . NumMethod ( ) ; index ++ {
method := contract . typ . Method ( index ) . Name
if strings . HasPrefix ( method , "Delete" ) {
t . Errorf ( "%s client exposes unsupported delete operation %s" , contract . name , method )
}
}
}
for _ , method := range [ ] string {
"PostIssuedCertificate" , "PostIssuedCertificateContext" ,
"PostIssuedCertificates" , "PostIssuedCertificatesContext" ,
"PutIssuedCertificate" , "PutIssuedCertificateContext" ,
"PutIssuedCertificates" , "PutIssuedCertificatesContext" ,
"DeleteIssuedCertificate" , "DeleteIssuedCertificateContext" ,
} {
if _ , exists := contracts [ 3 ] . typ . MethodByName ( method ) ; exists {
t . Errorf ( "read-only IssuedCertificate client exposes forbidden operation %s" , method )
}
}
repoRoot := learningRepoRoot ( t )
certificateClientDir := filepath . Join ( repoRoot , "api" , "members" , "members_client" , "certificates" )
if entries , err := os . ReadDir ( certificateClientDir ) ; err == nil {
for _ , entry := range entries {
if strings . HasSuffix ( entry . Name ( ) , ".go" ) {
t . Errorf ( "removed /certificates generated client still contains %s" , entry . Name ( ) )
}
}
} else if ! os . IsNotExist ( err ) {
t . Fatalf ( "inspect removed certificate client directory: %v" , err )
}
for _ , removed := range [ ] string {
filepath . Join ( repoRoot , "api" , "members" , "members_models" , "certificate.go" ) ,
filepath . Join ( repoRoot , "api" , "members" , "members_models" , "certificate_request.go" ) ,
filepath . Join ( repoRoot , "api" , "members" , "members_models" , "certificate_response.go" ) ,
filepath . Join ( repoRoot , "api" , "members" , "members_models" , "issued_certificate_request.go" ) ,
} {
if _ , err := os . Stat ( removed ) ; ! os . IsNotExist ( err ) {
t . Errorf ( "removed unsafe generated surface still exists: %s" , removed )
}
}
specText := readMembersLearningSpec ( t )
if strings . Contains ( specText , "\n /certificates:" ) {
t . Fatal ( "authoritative spec still exposes removed /certificates path" )
}
issuedPath := learningSpecPathBlock ( t , specText , "/issuedcertificates" )
for _ , forbidden := range [ ] string { " post:" , " put:" , " patch:" , " delete:" } {
if strings . Contains ( issuedPath , forbidden ) {
t . Fatalf ( "authoritative IssuedCertificate contract exposes forbidden operation %q" , strings . TrimSpace ( forbidden ) )
}
}
}
2026-07-24 06:07:12 +00:00
func TestMembersSpecIsPinnedToProviderSource ( t * testing . T ) {
2026-07-24 05:36:20 +00:00
repoRoot := learningRepoRoot ( t )
mainSpec , err := os . ReadFile ( filepath . Join ( repoRoot , "swagger" , "members-vernonkeenan.yaml" ) )
if err != nil {
t . Fatalf ( "read Members spec: %v" , err )
}
sum := sha256 . Sum256 ( mainSpec )
2026-07-24 06:07:12 +00:00
if got := hex . EncodeToString ( sum [ : ] ) ; got != membersProviderSpecSHA256 {
2026-07-24 14:54:36 +00:00
t . Fatalf ( "Members spec drifted from the integrated TrackEvent and Transaction provider contract: SHA-256 = %s, want %s" , got , membersProviderSpecSHA256 )
2026-07-24 05:36:20 +00:00
}
externalSpec , err := os . ReadFile ( filepath . Join ( repoRoot , "swagger" , "external" , "members-vernonkeenan.yaml" ) )
if err != nil {
t . Fatalf ( "read external Members spec: %v" , err )
}
normalized := bytes . ReplaceAll ( externalSpec , [ ] byte ( ` "https" ` ) , [ ] byte ( ` "http" ` ) )
normalized = bytes . ReplaceAll ( normalized , [ ] byte ( "gw.tnxs.net" ) , [ ] byte ( "members.vernonkeenan.com:8080" ) )
normalized = bytes . ReplaceAll ( normalized , [ ] byte ( ` "/vk/members/v1" ` ) , [ ] byte ( ` "/v1" ` ) )
if ! bytes . Equal ( normalized , mainSpec ) {
t . Fatal ( "external Members spec differs from the conventional host/scheme/base-path rewrite" )
}
}
func TestGeneratedLearningSurfaceHasNoSalesforceOrEmbeddedSecrets ( t * testing . T ) {
repoRoot := learningRepoRoot ( t )
targets := [ ] string {
filepath . Join ( repoRoot , "api" , "members" , "members_client" , "courses" ) ,
filepath . Join ( repoRoot , "api" , "members" , "members_client" , "enrollments" ) ,
filepath . Join ( repoRoot , "api" , "members" , "members_client" , "lesson_progress" ) ,
filepath . Join ( repoRoot , "api" , "members" , "members_client" , "issued_certificates" ) ,
filepath . Join ( repoRoot , "api" , "members" , "members_models" , "course.go" ) ,
filepath . Join ( repoRoot , "api" , "members" , "members_models" , "course_request.go" ) ,
filepath . Join ( repoRoot , "api" , "members" , "members_models" , "course_section.go" ) ,
filepath . Join ( repoRoot , "api" , "members" , "members_models" , "course_section_request.go" ) ,
filepath . Join ( repoRoot , "api" , "members" , "members_models" , "course_lesson.go" ) ,
filepath . Join ( repoRoot , "api" , "members" , "members_models" , "course_lesson_request.go" ) ,
filepath . Join ( repoRoot , "api" , "members" , "members_models" , "enrollment.go" ) ,
filepath . Join ( repoRoot , "api" , "members" , "members_models" , "enrollment_request.go" ) ,
filepath . Join ( repoRoot , "api" , "members" , "members_models" , "lesson_progress.go" ) ,
filepath . Join ( repoRoot , "api" , "members" , "members_models" , "lesson_progress_request.go" ) ,
filepath . Join ( repoRoot , "api" , "members" , "members_models" , "issued_certificate.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 Learning target %s: %v" , target , err )
}
}
}
func assertExactModelFields ( t * testing . T , model any , want map [ string ] string ) {
t . Helper ( )
modelType := reflect . TypeOf ( model )
if modelType . NumField ( ) != len ( want ) {
t . Errorf ( "%s has %d fields, want exact authoritative set of %d" , modelType . Name ( ) , modelType . NumField ( ) , len ( want ) )
}
for name , wantType := range want {
field , exists := modelType . FieldByName ( name )
if ! exists {
t . Errorf ( "%s is missing authoritative field %s" , modelType . Name ( ) , name )
continue
}
if field . Type . String ( ) != wantType {
t . Errorf ( "%s.%s type = %s, want %s" , modelType . Name ( ) , name , field . Type , wantType )
}
if got := strings . Split ( field . Tag . Get ( "json" ) , "," ) [ 0 ] ; got != name {
t . Errorf ( "%s.%s JSON name = %q, want %q" , modelType . Name ( ) , name , got , name )
}
}
}
func readMembersLearningSpec ( t * testing . T ) string {
t . Helper ( )
content , err := os . ReadFile ( filepath . Join ( learningRepoRoot ( t ) , "swagger" , "members-vernonkeenan.yaml" ) )
if err != nil {
t . Fatalf ( "read Members Swagger: %v" , err )
}
return string ( content )
}
func learningSpecPathBlock ( t * testing . T , specText , path string ) string {
t . Helper ( )
startMarker := " " + path + ":\n"
start := strings . Index ( specText , startMarker )
if start < 0 {
t . Fatalf ( "authoritative spec is missing path %s" , path )
}
block := specText [ start + len ( startMarker ) : ]
if end := strings . Index ( block , "\n /" ) ; end >= 0 {
block = block [ : end ]
}
return block
}
func learningSpecOperationBlock ( t * testing . T , specText , path , method string ) string {
t . Helper ( )
pathBlock := learningSpecPathBlock ( t , specText , path )
startMarker := " " + method + ":\n"
start := strings . Index ( pathBlock , startMarker )
if start < 0 {
t . Fatalf ( "authoritative spec is missing %s %s" , strings . ToUpper ( method ) , path )
}
block := pathBlock [ start + len ( startMarker ) : ]
methodBoundary := regexp . MustCompile ( ` (?m)^ [a-z]+:\n ` )
if end := methodBoundary . FindStringIndex ( block ) ; end != nil {
block = block [ : end [ 0 ] ]
}
return block
}
func learningRepoRoot ( t * testing . T ) string {
t . Helper ( )
_ , testFile , _ , ok := runtime . Caller ( 0 )
if ! ok {
t . Fatal ( "resolve test source path" )
}
return filepath . Clean ( filepath . Join ( filepath . Dir ( testFile ) , ".." , ".." , ".." ) )
}