Skip to content

tests: Added unit tests for user list command and user view#685

Open
rkcoder101 wants to merge 1 commit intogoharbor:mainfrom
rkcoder101:test/user-list
Open

tests: Added unit tests for user list command and user view#685
rkcoder101 wants to merge 1 commit intogoharbor:mainfrom
rkcoder101:test/user-list

Conversation

@rkcoder101
Copy link
Contributor

Description

This PR introduces unit tests for the user list command (cmd/harbor/root/user/list.go) and user view (pkg/views/user)

Relates to #591

Is a sub-part of #653

Note

No changes have been done to the core logic of the application, only a little refactoring for the purpose of writing some nice and clean test code :)

@rkcoder101 rkcoder101 marked this pull request as ready for review February 7, 2026 09:08
Copilot AI review requested due to automatic review settings February 7, 2026 09:08
Copy link
Contributor

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

This PR improves unit test coverage around the harbor user list command flow and the user list view rendering, with small refactors to make the logic more testable.

Changes:

  • Added unit tests for cmd/harbor/root/user/list.go (command flags, pagination behavior, and output modes).
  • Refactored the user list view to extract row-building into MakeUserRows and made ListUsers return an error instead of exiting.
  • Refactored user listing logic into GetUsers/PrintUsers and introduced a UserLister interface to allow mocking in tests.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 8 comments.

File Description
pkg/views/user/list/view.go Extracts row creation (MakeUserRows) and makes ListUsers return an error.
pkg/views/user/list/view_test.go Adds tests for MakeUserRows.
cmd/harbor/root/user/list.go Refactors command to separate fetching vs printing and adds UserLister for testability.
cmd/harbor/root/user/list_test.go Adds unit tests for printing, pagination behavior, and command flag wiring.

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

Comment on lines +19 to 21
"github.com/goharbor/go-client/pkg/sdk/v2.0/client/user"
"github.com/goharbor/go-client/pkg/sdk/v2.0/models"
"github.com/goharbor/harbor-cli/pkg/api"
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

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

In this file’s package user, importing github.com/goharbor/go-client/pkg/sdk/v2.0/client/user as user is very easy to confuse with the current package name and makes types like *user.ListUsersOK hard to read. Consider aliasing the import (e.g., clientuser) and updating the interface return type accordingly.

Copilot uses AI. Check for mistakes.
if formatFlag != "" {
err := utils.PrintFormat(allUsers, formatFlag)
if err != nil {
log.Error(err)
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

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

PrintUsers returns an error, but in the formatted-output branch a utils.PrintFormat failure is only logged and the function still returns nil. This makes the command exit successfully even though output failed; return the formatting error instead of swallowing it.

Suggested change
log.Error(err)
log.Error(err)
return err

Copilot uses AI. Check for mistakes.
Comment on lines +52 to +56
if isUnauthorizedError(err) {
return nil, fmt.Errorf("Permission denied: Admin privileges are required to execute this command.")
}
} else {
response, err := api.ListUsers(opts)
if err != nil {
if isUnauthorizedError(err) {
return fmt.Errorf("Permission denied: Admin privileges are required to execute this command.")
}
return fmt.Errorf("failed to list users: %v", err)
}
allUsers = response.Payload
return nil, fmt.Errorf("failed to list users: %v", err)
}
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

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

This error wrapping uses %v, which prevents callers from unwrapping/inspecting the underlying error. Prefer %w when re-wrapping (e.g., fmt.Errorf("failed to list users: %w", err)).

Copilot uses AI. Check for mistakes.
Comment on lines +68 to +72
if isUnauthorizedError(err) {
return nil, fmt.Errorf("Permission denied: Admin privileges are required to execute this command.")
}
formatFlag := viper.GetString("output-format")
if formatFlag != "" {
err := utils.PrintFormat(allUsers, formatFlag)
if err != nil {
log.Error(err)
}
} else {
list.ListUsers(allUsers)
return nil, fmt.Errorf("failed to list users: %v", err)
}
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

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

Same as above: use %w when re-wrapping err so it can be unwrapped by callers.

Copilot uses AI. Check for mistakes.
Comment on lines +30 to +33
expectedTimeStr, err := utils.FormatCreatedTime(dateStr)
if err != nil {
t.Fatalf("failed to format created time %q: %v", dateStr, err)
}
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

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

This test asserts an exact string produced by FormatCreatedTime (which is based on time.Since). Because that value changes over time (and can flip at a day boundary), the assertion can be flaky. Prefer asserting the time column is non-empty or matches a suffix/pattern (e.g., contains "day ago").

Copilot uses AI. Check for mistakes.
origStdout := os.Stdout
defer func() { os.Stdout = origStdout }()

r, w, _ := os.Pipe()
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

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

os.Pipe()’s error return is ignored here. Even in tests, handle the error (and fail the test) so the helper doesn’t panic or behave unpredictably if pipe creation fails.

Suggested change
r, w, _ := os.Pipe()
r, w, err := os.Pipe()
if err != nil {
return "", err
}

Copilot uses AI. Check for mistakes.
Comment on lines +42 to +49
r, w, _ := os.Pipe()
os.Stdout = w

if err := f(); err != nil {
return "", err
}

w.Close()
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

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

If f() returns an error, this helper returns early without closing the pipe writer/reader, which can leak file descriptors across test cases. Use defer to close w/r (and restore stdout) so cleanup happens on all paths.

Suggested change
r, w, _ := os.Pipe()
os.Stdout = w
if err := f(); err != nil {
return "", err
}
w.Close()
r, w, err := os.Pipe()
if err != nil {
return "", err
}
defer func() {
_ = w.Close()
_ = r.Close()
}()
os.Stdout = w
if err := f(); err != nil {
return "", err
}
if err := w.Close(); err != nil {
return "", err
}

Copilot uses AI. Check for mistakes.
return buf.String(), nil
}
func TestPrintUsers(t *testing.T) {
testDate, _ := strfmt.ParseDateTime("2023-01-01T12:00:00Z")
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

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

The strfmt.ParseDateTime error is ignored here. Check err and t.Fatalf on failure to avoid masking unexpected parsing issues.

Suggested change
testDate, _ := strfmt.ParseDateTime("2023-01-01T12:00:00Z")
testDate, err := strfmt.ParseDateTime("2023-01-01T12:00:00Z")
if err != nil {
t.Fatalf("failed to parse test date: %v", err)
}

Copilot uses AI. Check for mistakes.
@rkcoder101 rkcoder101 mentioned this pull request Feb 7, 2026
5 tasks
@rkcoder101
Copy link
Contributor Author

@bupd please review this whenever u get the time. Thanks!

@codecov
Copy link

codecov bot commented Feb 8, 2026

Codecov Report

❌ Patch coverage is 69.49153% with 18 lines in your changes missing coverage. Please review.
✅ Project coverage is 7.72%. Comparing base (60ad0bd) to head (709ad8f).
⚠️ Report is 98 commits behind head on main.

Files with missing lines Patch % Lines
cmd/harbor/root/user/list.go 76.47% 9 Missing and 3 partials ⚠️
pkg/views/user/list/view.go 25.00% 6 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff            @@
##             main    #685      +/-   ##
=========================================
- Coverage   10.99%   7.72%   -3.27%     
=========================================
  Files         173     260      +87     
  Lines        8671   12925    +4254     
=========================================
+ Hits          953     998      +45     
- Misses       7612   11816    +4204     
- Partials      106     111       +5     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

…g previous commits into one to resolve merge conflicts)

Signed-off-by: Rayyan Khan <rayyanrehman101@gmail.com>
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.

2 participants