lib/api/members/members_client/track_relationship_contract...

219 lines
7.4 KiB
Go
Raw Normal View History

package members_client
import (
"os"
"path/filepath"
"strings"
"testing"
"code.tnxs.net/vernonkeenan/lib/api/members/members_client/track_topics"
"code.tnxs.net/vernonkeenan/lib/api/members/members_client/track_users"
"code.tnxs.net/vernonkeenan/lib/api/members/members_models"
"github.com/go-openapi/strfmt"
)
func TestTrackTopicClientExposesOnlyReadAndImmutableCreate(t *testing.T) {
client := track_topics.New(nil, strfmt.Default)
if client == nil {
t.Fatal("generated TrackTopic client is nil")
}
var _ track_topics.ClientService = client
params := track_topics.NewGetTrackTopicsParams().
WithID(trackRelationshipString("association")).
WithTrackID(trackRelationshipString("track")).
WithTopicID(trackRelationshipString("topic"))
if params.ID == nil || *params.ID != "association" ||
params.TrackID == nil || *params.TrackID != "track" ||
params.TopicID == nil || *params.TopicID != "topic" {
t.Fatal("generated TrackTopic GET filters do not preserve values")
}
request := &members_models.TrackTopicRequest{Data: []*members_models.TrackTopic{{
TopicID: "topic", TrackID: "track",
}}}
create := track_topics.NewPostTrackTopicsParams().WithTrackTopicRequest(request)
if create.TrackTopicRequest != request {
t.Fatal("generated TrackTopic POST does not preserve its request")
}
assertNoGeneratedOperation(t, "track_topics", "put_", "delete_")
}
func TestTrackUserClientExposesReadCreateAndRoleOnlyUpdate(t *testing.T) {
client := track_users.New(nil, strfmt.Default)
if client == nil {
t.Fatal("generated TrackUser client is nil")
}
var _ track_users.ClientService = client
params := track_users.NewGetTrackUsersParams().
WithID(trackRelationshipString("association")).
WithTrackID(trackRelationshipString("track")).
WithUserID(trackRelationshipString("user")).
WithRole(trackRelationshipString(members_models.TrackUserRoleModerator))
if params.ID == nil || *params.ID != "association" ||
params.TrackID == nil || *params.TrackID != "track" ||
params.UserID == nil || *params.UserID != "user" ||
params.Role == nil || *params.Role != "Moderator" {
t.Fatal("generated TrackUser GET filters do not preserve values")
}
request := &members_models.TrackUserRequest{Data: []*members_models.TrackUser{{
ID: "association", LastModifiedDate: trackRelationshipString("version"),
Role: members_models.TrackUserRolePresenter,
}}}
create := track_users.NewPostTrackUsersParams().WithTrackUserRequest(request)
update := track_users.NewPutTrackUsersParams().WithTrackUserRequest(request)
if create.TrackUserRequest != request || update.TrackUserRequest != request {
t.Fatal("generated TrackUser mutations do not preserve their request")
}
if members_models.TrackUserRoleAttendee != "Attendee" ||
members_models.TrackUserRoleModerator != "Moderator" ||
members_models.TrackUserRolePresenter != "Presenter" {
t.Fatal("generated TrackUser role vocabulary changed")
}
assertNoGeneratedOperation(t, "track_users", "delete_")
}
func TestMembersClientWiresTrackRelationshipServices(t *testing.T) {
client := New(nil, strfmt.Default)
if client.TrackTopics == nil || client.TrackUsers == nil {
t.Fatal("Members root client does not wire Track relationship services")
}
}
func TestTrackRelationshipSpecPreservesExactScopesAndCompoundAuth(t *testing.T) {
raw, err := os.ReadFile("../../../swagger/members-vernonkeenan.yaml")
if err != nil {
t.Fatal(err)
}
spec := string(raw)
tests := []struct {
path, method, operationID, scope string
}{
{"/tracktopics", "get", "getTrackTopics", "members:track-topic:read"},
{"/tracktopics", "post", "postTrackTopics", "members:track-topic:create"},
{"/trackusers", "get", "getTrackUsers", "members:track-user:read"},
{"/trackusers", "post", "postTrackUsers", "members:track-user:create"},
{"/trackusers", "put", "putTrackUsers", "members:track-user:update"},
}
const compoundSecurity = " security:\n - ApiKeyAuth: []\n kvSessionCookie: []"
for _, test := range tests {
block := trackRelationshipOperationBlock(t, spec, test.path, test.method)
if !strings.Contains(block, " operationId: "+test.operationID+"\n") {
t.Errorf("%s %s lost operationId %q", strings.ToUpper(test.method), test.path, test.operationID)
}
if strings.Count(block, compoundSecurity) != 1 {
t.Errorf("%s %s does not preserve compound authentication", strings.ToUpper(test.method), test.path)
}
if !strings.Contains(block, test.scope) {
t.Errorf("%s %s lost exact scope %q", strings.ToUpper(test.method), test.path, test.scope)
}
}
if strings.Contains(trackRelationshipPathBlock(t, spec, "/tracktopics"), " put:") ||
strings.Contains(trackRelationshipPathBlock(t, spec, "/tracktopics"), " delete:") {
t.Fatal("TrackTopic spec exposes unsupported mutation")
}
if strings.Contains(trackRelationshipPathBlock(t, spec, "/trackusers"), " delete:") {
t.Fatal("TrackUser spec exposes unsupported delete")
}
if !track_users.NewPutTrackUsersConflict().IsCode(409) {
t.Fatal("TrackUser update client lost the optimistic concurrency response")
}
}
func TestTrackRelationshipClientHasNoLegacyOrCredentialSurface(t *testing.T) {
for _, root := range []string{
"track_topics", "track_users", "../members_models",
} {
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() ||
(root == "../members_models" &&
!strings.Contains(path, "track_topic") &&
!strings.Contains(path, "track_user")) {
return nil
}
raw, readErr := os.ReadFile(path)
if readErr != nil {
return readErr
}
source := strings.ToLower(string(raw))
forbiddenValues := []string{
"salesforce", "sf-gate", "go-force", "cache",
}
if root == "../members_models" {
forbiddenValues = append(
forbiddenValues,
"api_key", "credential", "password", "token",
)
}
for _, forbidden := range forbiddenValues {
if strings.Contains(source, forbidden) {
t.Errorf("%s contains forbidden coupling %q", path, forbidden)
}
}
return nil
})
if err != nil {
t.Fatal(err)
}
}
}
func assertNoGeneratedOperation(t *testing.T, directory string, prefixes ...string) {
t.Helper()
entries, err := os.ReadDir(directory)
if err != nil {
t.Fatal(err)
}
for _, entry := range entries {
name := strings.ToLower(entry.Name())
for _, prefix := range prefixes {
if strings.HasPrefix(name, prefix) {
t.Errorf("forbidden operation artifact: %s/%s", directory, name)
}
}
}
}
func trackRelationshipString(value string) *string { return &value }
func trackRelationshipPathBlock(t *testing.T, spec, path string) string {
t.Helper()
startMarker := "\n " + path + ":\n"
start := strings.Index(spec, startMarker)
if start < 0 {
t.Fatalf("missing path %s", path)
}
block := spec[start+1:]
if end := strings.Index(block, "\n /"); end >= 0 {
block = block[:end]
}
return block
}
func trackRelationshipOperationBlock(t *testing.T, spec, path, method string) string {
t.Helper()
pathBlock := trackRelationshipPathBlock(t, spec, path)
startMarker := "\n " + method + ":\n"
start := strings.Index("\n"+pathBlock, startMarker)
if start < 0 {
t.Fatalf("missing %s operation for %s", method, path)
}
block := ("\n" + pathBlock)[start+1:]
for _, next := range []string{"get", "post", "put", "patch", "delete"} {
if next == method {
continue
}
if end := strings.Index(block, "\n "+next+":\n"); end >= 0 {
block = block[:end]
}
}
return block
}