Files
nadir-agent/internal/modules/users/users_handler_test.go
T
2026-06-24 17:29:45 +02:00

146 lines
4.3 KiB
Go

package users
import (
"encoding/json"
"net/http"
"os"
"path/filepath"
"reflect"
"testing"
"nadir/internal/oscmd"
"github.com/danielgtaylor/huma/v2"
"github.com/danielgtaylor/huma/v2/adapters/humago"
"github.com/danielgtaylor/huma/v2/humatest"
)
func TestUsersHandlers(t *testing.T) {
tempPasswd := filepath.Join(t.TempDir(), "passwd")
initialContent := "root:x:0:0:root:/root:/bin/bash\nalice:x:1000:1000:Alice Smith:/home/alice:/bin/bash\n"
if err := os.WriteFile(tempPasswd, []byte(initialContent), 0644); err != nil {
t.Fatal(err)
}
oldPasswd := passwdPath
passwdPath = tempPasswd
defer func() { passwdPath = oldPasswd }()
mux := http.NewServeMux()
api := humatest.Wrap(t, humago.New(mux, huma.DefaultConfig("Test", "1.0.0")))
registerUsers(api, nil)
// 1. Test GET /api/users
resp := api.Get("/api/users")
if resp.Code != http.StatusOK {
t.Errorf("list users: got %d, want %d", resp.Code, http.StatusOK)
}
var listRes ListUsersOutput
if err := json.Unmarshal(resp.Body.Bytes(), &listRes.Body); err != nil {
t.Fatal(err)
}
if len(listRes.Body.Users) != 2 {
t.Errorf("got %d users, want 2", len(listRes.Body.Users))
}
// 2. Test GET /api/users/{username}
resp = api.Get("/api/users/alice")
if resp.Code != http.StatusOK {
t.Errorf("get user: got %d, want %d", resp.Code, http.StatusOK)
}
var getRes GetUserOutput
if err := json.Unmarshal(resp.Body.Bytes(), &getRes.Body); err != nil {
t.Fatal(err)
}
if getRes.Body.Username != "alice" || getRes.Body.UID != 1000 {
t.Errorf("get user: got %+v", getRes.Body)
}
resp = api.Get("/api/users/bob")
if resp.Code != http.StatusNotFound {
t.Errorf("get non-existent user: got %d, want %d", resp.Code, http.StatusNotFound)
}
// 3. Test POST /api/users
oscmd.SetMock("useradd", func(args []string) oscmd.MockCommand {
wantArgs := []string{"-m", "-c", "Bob Jones", "-s", "/bin/sh", "--", "bob"}
if !reflect.DeepEqual(args, wantArgs) {
t.Errorf("useradd args: got %v, want %v", args, wantArgs)
}
bobContent := initialContent + "bob:x:1001:1001:Bob Jones:/home/bob:/bin/sh\n"
os.WriteFile(tempPasswd, []byte(bobContent), 0644)
return oscmd.MockCommand{ExitCode: 0}
})
defer oscmd.ClearMocks()
resp = api.Post("/api/users", struct {
Username string `json:"username"`
Comment string `json:"comment"`
Shell string `json:"shell"`
CreateHome bool `json:"create_home"`
}{
Username: "bob",
Comment: "Bob Jones",
Shell: "/bin/sh",
CreateHome: true,
})
if resp.Code != http.StatusOK {
t.Errorf("create user: got %d, want %d", resp.Code, http.StatusOK)
}
// 4. Test DELETE /api/users/{username}
oscmd.SetMock("userdel", func(args []string) oscmd.MockCommand {
wantArgs := []string{"-r", "--", "bob"}
if !reflect.DeepEqual(args, wantArgs) {
t.Errorf("userdel args: got %v, want %v", args, wantArgs)
}
os.WriteFile(tempPasswd, []byte(initialContent), 0644)
return oscmd.MockCommand{ExitCode: 0}
})
resp = api.Delete("/api/users/bob?remove_home=true")
if resp.Code != http.StatusOK {
t.Errorf("delete user: got %d, want %d", resp.Code, http.StatusOK)
}
// 5. Test POST /api/users/{username}/password
oscmd.SetMock("chpasswd", func(args []string) oscmd.MockCommand {
return oscmd.MockCommand{ExitCode: 0}
})
resp = api.Post("/api/users/alice/password", struct {
Password string `json:"password"`
}{
Password: "newsecretpwd",
})
if resp.Code != http.StatusOK {
t.Errorf("set password: got %d, want %d", resp.Code, http.StatusOK)
}
// 6. Test PUT /api/users/{username}/groups
oscmd.SetMock("usermod", func(args []string) oscmd.MockCommand {
wantArgs := []string{"-G", "wheel,dev", "--", "alice"}
if !reflect.DeepEqual(args, wantArgs) {
t.Errorf("usermod args: got %v, want %v", args, wantArgs)
}
return oscmd.MockCommand{ExitCode: 0}
})
oscmd.SetMock("id", func(args []string) oscmd.MockCommand {
wantArgs := []string{"-nG", "alice"}
if !reflect.DeepEqual(args, wantArgs) {
t.Errorf("id args: got %v, want %v", args, wantArgs)
}
return oscmd.MockCommand{Stdout: "alice wheel dev\n", ExitCode: 0}
})
resp = api.Put("/api/users/alice/groups", struct {
Groups []string `json:"groups"`
}{
Groups: []string{"wheel", "dev"},
})
if resp.Code != http.StatusOK {
t.Errorf("set groups: got %d, want %d", resp.Code, http.StatusOK)
}
}