fleet/cmd/fleetctl/users_test.go
Ahmed Elshaer a9f48ff561
Create Bulk Users from CSV (#3372)
* Create Bulk Users

* WIP: Adding a test for bulk user import

* adding a user bulk create test

* Fixing description, removing password required, and adding more test cases

* Fixing description, removing password required, and adding more test cases

* Fixed all comments and added Random Password Generator

* returning an error in generateRandomPassword

* Using 2 loops to create user list and then create the actual users

* Adding a bulk user delete

* fixing a mistake in temp csv

* fixed lints and removed yamlFlag
2022-06-22 13:34:58 -03:00

189 lines
5.7 KiB
Go

package main
import (
"context"
"crypto/rand"
"encoding/csv"
"io/ioutil"
"math/big"
"os"
"strings"
"testing"
"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/fleetdm/fleet/v4/server/test"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestUserDelete(t *testing.T) {
_, ds := runServerWithMockedDS(t)
ds.UserByEmailFunc = func(ctx context.Context, email string) (*fleet.User, error) {
return &fleet.User{
ID: 42,
Name: "test1",
Email: "user1@test.com",
}, nil
}
deletedUser := uint(0)
ds.DeleteUserFunc = func(ctx context.Context, id uint) error {
deletedUser = id
return nil
}
assert.Equal(t, "", runAppForTest(t, []string{"user", "delete", "--email", "user1@test.com"}))
assert.Equal(t, uint(42), deletedUser)
}
type notFoundError struct{}
var _ fleet.NotFoundError = (*notFoundError)(nil)
func (e *notFoundError) IsNotFound() bool {
return true
}
func (e *notFoundError) Error() string {
return ""
}
// TestUserCreateForcePasswordReset tests that the `fleetctl user create` command
// creates a user with the proper "AdminForcePasswordReset" value depending on
// the passed flags (e.g. SSO users shouldn't be required to do password reset on first login).
func TestUserCreateForcePasswordReset(t *testing.T) {
_, ds := runServerWithMockedDS(t)
pwd := test.GoodPassword
ds.InviteByEmailFunc = func(ctx context.Context, email string) (*fleet.Invite, error) {
return nil, &notFoundError{}
}
for _, tc := range []struct {
name string
args []string
expectedAdminForcePasswordReset bool
}{
{
name: "sso",
args: []string{"--email", "foo@example.com", "--name", "foo", "--sso"},
expectedAdminForcePasswordReset: false,
},
{
name: "api-only",
args: []string{"--email", "bar@example.com", "--password", pwd, "--name", "bar", "--api-only"},
expectedAdminForcePasswordReset: false,
},
{
name: "api-only-sso",
args: []string{"--email", "baz@example.com", "--name", "baz", "--api-only", "--sso"},
expectedAdminForcePasswordReset: false,
},
{
name: "non-sso-non-api-only",
args: []string{"--email", "zoo@example.com", "--password", pwd, "--name", "zoo"},
expectedAdminForcePasswordReset: true,
},
} {
ds.NewUserFuncInvoked = false
ds.NewUserFunc = func(ctx context.Context, user *fleet.User) (*fleet.User, error) {
assert.Equal(t, tc.expectedAdminForcePasswordReset, user.AdminForcedPasswordReset)
return user, nil
}
require.Equal(t, "", runAppForTest(t, append(
[]string{"user", "create"},
tc.args...,
)))
require.True(t, ds.NewUserFuncInvoked)
}
}
func writeTmpCsv(t *testing.T, contents string) string {
tmpFile, err := ioutil.TempFile(t.TempDir(), "*.csv")
require.NoError(t, err)
_, err = tmpFile.WriteString(contents)
require.NoError(t, err)
require.NoError(t, tmpFile.Close())
return tmpFile.Name()
}
func TestCreateBulkUsers(t *testing.T) {
_, ds := runServerWithMockedDS(t)
ds.InviteByEmailFunc = func(ctx context.Context, email string) (*fleet.Invite, error) {
return nil, nil
}
csvFile := writeTmpCsv(t,
`Name,Email,SSO,API Only,Global Role,Teams
user11,user11@example.com,false,false,maintainer,
user12,user12@example.com,false,false,,
user13,user13@example.com,true,false,admin,
user14,user14@example.com,false,false,,2:maintainer
user15,user15@example.com,false,false,,1:admin
user16,user16@example.com,false,false,,1:admin 2:maintainer`)
expectedText := `{"kind":"user_roles","apiVersion":"v1","spec":{"roles":{"admin1@example.com":{"global_role":"admin","teams":null},"user11@example.com":{"global_role":"maintainer","teams":null},"user12@example.com":{"global_role":"observer","teams":null},"user13@example.com":{"global_role":"admin","teams":null},"user14@example.com":{"global_role":null,"teams":[{"team":"","role":"maintainer"}]},"user15@example.com":{"global_role":null,"teams":[{"team":"","role":"admin"}]},"user16@example.com":{"global_role":null,"teams":[{"team":"","role":"admin"},{"team":"","role":"maintainer"}]},"user1@example.com":{"global_role":"observer","teams":null},"user2@example.com":{"global_role":"observer","teams":null}}}}
`
assert.Equal(t, "", runAppForTest(t, []string{"user", "create-users", "--csv", csvFile}))
assert.Equal(t, expectedText, runAppForTest(t, []string{"get", "user_roles", "--json"}))
}
func TestDeleteBulkUsers(t *testing.T) {
_, ds := runServerWithMockedDS(t)
csvFilePath := writeTmpCsv(t,
`Email
user11@example.com
user12@example.com
user13@example.com`)
csvFile, err := os.Open(csvFilePath)
require.NoError(t, err)
defer csvFile.Close()
csvLines, err := csv.NewReader(csvFile).ReadAll()
require.NoError(t, err)
users := []fleet.User{}
deletedUserIds := []uint{}
for _, user := range csvLines[1:] {
email := user[0]
name := strings.Split(email, "@")[0]
randId, err := rand.Int(rand.Reader, big.NewInt(1000))
require.NoError(t, err)
id := uint(randId.Int64())
users = append(users, fleet.User{
Name: name,
Email: email,
ID: id,
})
deletedUserIds = append(deletedUserIds, id)
}
for _, user := range users {
ds.UserByEmailFunc = func(ctx context.Context, email string) (*fleet.User, error) {
return &user, nil
}
}
deletedUser := uint(0)
ds.DeleteUserFunc = func(ctx context.Context, id uint) error {
deletedUser = id
return nil
}
assert.Equal(t, "", runAppForTest(t, []string{"user", "delete-users", "--csv", csvFilePath}))
for indx, user := range users {
deletedUser = deletedUserIds[indx]
assert.Equal(t, user.ID, deletedUser)
}
}