Skip to content

test: add unit tests for key server/models validation types#230

Open
mason5052 wants to merge 2 commits intovxcontrol:mainfrom
mason5052:test/server-models-validation
Open

test: add unit tests for key server/models validation types#230
mason5052 wants to merge 2 commits intovxcontrol:mainfrom
mason5052:test/server-models-validation

Conversation

@mason5052
Copy link
Copy Markdown
Contributor

@mason5052 mason5052 commented Apr 1, 2026

What

Add unit tests for validation logic across key server/models types: users, providers, API tokens, flows, tasks, containers, assistants, prompts, roles, and custom validators.

This does not cover every exported validator in the package (log models, analytics, msgchains, screenshots, and vecstore models are not included).

Why

These model types contain security-sensitive validation functions (password strength, OAuth scope, JWT claims, API token TTL bounds) and core domain validation (enum status types, struct field requirements, nested model validation). None had test coverage.

Test Files

File Tested Types
users_test.go UserStatus, UserType, Login, Password, User, UserPassword, AuthCallback, UserRole, UserRolePrivileges, UserPreferences
providers_test.go ProviderType (10 types), Provider, CreateProvider, PatchProvider, ProviderInfo
api_tokens_test.go TokenStatus, APIToken, APITokenWithSecret, CreateAPITokenRequest, UpdateAPITokenRequest, APITokenClaims
flows_test.go FlowStatus, TaskStatus, SubtaskStatus, ContainerStatus, ContainerType, Flow, FlowTasksSubtasks, FlowContainers, Task, TaskSubtasks, Subtask, Container, Role, Privilege, RolePrivileges, PatchFlow
init_test.go Custom validators (stpass, vmail, oauth_min_scope, solid, semver, semverex), scanFromJSON
assistants_test.go AssistantStatus, Assistant, CreateAssistant, PatchAssistant, AssistantFlow
prompts_test.go PromptType, Prompt, PatchPrompt

Test Approach

  • All tests use t.Parallel() for fast execution
  • Table-driven tests for enum validation with valid and invalid cases
  • Boundary testing for numeric constraints (TTL min=60, max=94608000)
  • Cross-field validation (Password confirm mismatch, current != new)
  • Nested struct validation (AssistantFlow, FlowTasksSubtasks, FlowContainers, TaskSubtasks, UserRolePrivileges)
  • Same-package testing for access to unexported validate and scanFromJSON

Verification

cd backend && go test ./pkg/server/models/ -count=1 -v
# 347 test cases pass

Add comprehensive test coverage for the server/models package validation
logic including enum types, struct validators, and custom validators.

Test files added:
- users_test.go: UserStatus, UserType, Login, Password, User,
  UserPassword, AuthCallback, UserRole, UserPreferences validation
- providers_test.go: ProviderType, Provider, CreateProvider,
  PatchProvider, ProviderInfo validation
- api_tokens_test.go: TokenStatus, APIToken, CreateAPITokenRequest,
  UpdateAPITokenRequest, APITokenClaims validation
- flows_test.go: FlowStatus, TaskStatus, SubtaskStatus, ContainerStatus,
  ContainerType, Role, Privilege, RolePrivileges, PatchFlow validation
- init_test.go: Custom validators (stpass, vmail, oauth_min_scope,
  solid, semver, semverex) and scanFromJSON helper
Copilot AI review requested due to automatic review settings April 1, 2026 00:38
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds unit test coverage for backend/pkg/server/models validation logic to ensure core model validators (users, providers, flows, API tokens, and custom validators) are exercised and regressions are caught early.

Changes:

  • Introduces table-driven unit tests for enum/string validators and Valid() methods across key models.
  • Adds boundary/negative-case tests for security-sensitive validation rules (password strength, OAuth scopes, JWT-related claims).
  • Adds tests for helper/validator initialization and JSON scan helpers.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 19 comments.

Show a summary per file
File Description
backend/pkg/server/models/users_test.go Adds tests for user/login/password models, role linking, and preferences JSON scan/value behavior.
backend/pkg/server/models/providers_test.go Adds tests for provider type validation and provider create/patch/info payload validation.
backend/pkg/server/models/api_tokens_test.go Adds tests for API token status/struct validation, TTL boundaries, and claims validation.
backend/pkg/server/models/flows_test.go Adds tests for flow/task/subtask/container status/type validation and patch action validation.
backend/pkg/server/models/init_test.go Adds tests for custom validators (stpass, vmail, oauth_min_scope, solid, semver, semverex) and scanFromJSON.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +26 to +29
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
err := tt.status.Valid()
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Subtest uses t.Parallel() inside a for-range over tt; in Go the range variable is reused, so parallel subtests can race and all observe the last tt value. Shadow tt := tt inside the loop (or pass tt as an argument) before calling t.Run.

Copilot uses AI. Check for mistakes.
Comment on lines +64 to +67
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
err := tt.userType.Valid()
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Subtest uses t.Parallel() while closing over the for-range variable tt. Because tt is reused across iterations, parallel subtests can read the wrong case. Add tt := tt inside the loop before t.Run.

Copilot uses AI. Check for mistakes.
Comment on lines +121 to +124
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
err := tt.login.Valid()
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

t.Run subtest calls t.Parallel() and captures the loop variable tt from a for-range; this can cause flaky tests due to loop-variable reuse. Shadow tt := tt (or pass as param) inside the loop before launching the subtest.

Copilot uses AI. Check for mistakes.
},
}

for _, tt := range tests {
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parallel subtests capture the for-range variable tt (reused each iteration). With t.Parallel(), this can make subtests execute with the wrong inputs. Fix by shadowing tt := tt inside the loop before t.Run.

Suggested change
for _, tt := range tests {
for _, tt := range tests {
tt := tt

Copilot uses AI. Check for mistakes.
Comment on lines +401 to +402
assert.Error(t, up.Valid())
assert.Contains(t, up.Valid().Error(), "user_id is required")
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assertion calls up.Valid() twice; the second call is unnecessary and can hide issues if Valid() becomes stateful. Store the error once (e.g., err := up.Valid()) and assert on err/err.Error().

Suggested change
assert.Error(t, up.Valid())
assert.Contains(t, up.Valid().Error(), "user_id is required")
err := up.Valid()
assert.Error(t, err)
assert.Contains(t, err.Error(), "user_id is required")

Copilot uses AI. Check for mistakes.
{"invalid unknown", TaskStatus("cancelled"), true},
}

for _, tt := range tests {
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parallel subtests capture the loop variable tt from a for-range. Since tt is reused, this can cause flaky/incorrect subtest inputs. Add tt := tt inside the loop before t.Run.

Suggested change
for _, tt := range tests {
for _, tt := range tests {
tt := tt

Copilot uses AI. Check for mistakes.
Comment on lines +185 to +188
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
err := tt.status.Valid()
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

t.Run subtests use t.Parallel() and capture the for-range variable tt (reused). Shadow tt := tt inside the loop before t.Run to ensure each subtest gets correct data.

Copilot uses AI. Check for mistakes.
Comment on lines +222 to +225
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
err := tt.status.Valid()
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parallel subtests capture for-range variable tt (reused each iteration), which can lead to incorrect ContainerStatus test cases executing. Shadow tt := tt inside the loop before t.Run.

Copilot uses AI. Check for mistakes.
Comment on lines +250 to +253
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
err := tt.ct.Valid()
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This for-range launches parallel subtests that close over tt; since Go reuses the range variable, subtests can run with the wrong ContainerType values. Add tt := tt inside the loop before calling t.Run.

Copilot uses AI. Check for mistakes.
{"invalid deleted", TokenStatus("deleted"), true},
}

for _, tt := range tests {
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parallel subtests capture the for-range variable tt (reused). With t.Parallel(), this can cause cases to execute with the wrong status. Shadow tt := tt inside the loop before t.Run.

Suggested change
for _, tt := range tests {
for _, tt := range tests {
tt := tt

Copilot uses AI. Check for mistakes.
Add missing test coverage identified by cross-review:

New files:
- assistants_test.go: AssistantStatus enum, Assistant struct, CreateAssistant,
  PatchAssistant (stop/input actions), AssistantFlow nested validation
- prompts_test.go: PromptType enum (8 valid constants from templates pkg),
  Prompt struct, PatchPrompt validation

Extended existing files:
- users_test.go: add AuthCallback positive-path test, UserRolePrivileges
  validation, fix brittle double-call assertion in UserPreferences test
- api_tokens_test.go: add APITokenWithSecret validation (valid, invalid
  embedded token, invalid JWT)
- flows_test.go: add Flow.Valid, FlowTasksSubtasks.Valid,
  FlowContainers.Valid, Task.Valid, TaskSubtasks.Valid, Subtask.Valid,
  Container.Valid with valid/invalid/missing-field cases
@mason5052 mason5052 changed the title test: add unit tests for server/models validation functions test: add unit tests for key server/models validation types Apr 1, 2026
@asdek
Copy link
Copy Markdown
Contributor

asdek commented Apr 2, 2026

hey @mason5052

there are correct notice from Copilot side, you need to change these syntax constructions to make immutable tt variable in the loops.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants