Skip to content

Commit 39940e0

Browse files
committed
test new cli user behaviour
Signed-off-by: Kristoffer Dalby <[email protected]>
1 parent a61ccc3 commit 39940e0

File tree

1 file changed

+139
-11
lines changed

1 file changed

+139
-11
lines changed

integration/cli_test.go

+139-11
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
package integration
22

33
import (
4+
"cmp"
45
"encoding/json"
56
"fmt"
6-
"sort"
77
"strings"
88
"testing"
99
"time"
1010

11+
tcmp "github.com/google/go-cmp/cmp"
12+
"github.com/google/go-cmp/cmp/cmpopts"
1113
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
1214
"github.com/juanfont/headscale/hscontrol/policy"
1315
"github.com/juanfont/headscale/integration/hsic"
1416
"github.com/juanfont/headscale/integration/tsic"
1517
"github.com/stretchr/testify/assert"
18+
"github.com/stretchr/testify/require"
1619
"golang.org/x/exp/slices"
1720
)
1821

@@ -30,6 +33,16 @@ func executeAndUnmarshal[T any](headscale ControlServer, command []string, resul
3033
return nil
3134
}
3235

36+
// Interface ensuring that we can sort structs from gRPC that
37+
// have an ID field.
38+
type GRPCSortable interface {
39+
GetId() uint64
40+
}
41+
42+
func sortWithID[T GRPCSortable](a, b T) int {
43+
return cmp.Compare(a.GetId(), b.GetId())
44+
}
45+
3346
func TestUserCommand(t *testing.T) {
3447
IntegrationSkip(t)
3548
t.Parallel()
@@ -49,7 +62,7 @@ func TestUserCommand(t *testing.T) {
4962
headscale, err := scenario.Headscale()
5063
assertNoErr(t, err)
5164

52-
var listUsers []v1.User
65+
var listUsers []*v1.User
5366
err = executeAndUnmarshal(headscale,
5467
[]string{
5568
"headscale",
@@ -62,8 +75,8 @@ func TestUserCommand(t *testing.T) {
6275
)
6376
assertNoErr(t, err)
6477

78+
slices.SortFunc(listUsers, sortWithID)
6579
result := []string{listUsers[0].GetName(), listUsers[1].GetName()}
66-
sort.Strings(result)
6780

6881
assert.Equal(
6982
t,
@@ -76,15 +89,14 @@ func TestUserCommand(t *testing.T) {
7689
"headscale",
7790
"users",
7891
"rename",
79-
"--output",
80-
"json",
81-
"user2",
82-
"newname",
92+
"--output=json",
93+
fmt.Sprintf("--identifier=%d", listUsers[1].GetId()),
94+
"--new-name=newname",
8395
},
8496
)
8597
assertNoErr(t, err)
8698

87-
var listAfterRenameUsers []v1.User
99+
var listAfterRenameUsers []*v1.User
88100
err = executeAndUnmarshal(headscale,
89101
[]string{
90102
"headscale",
@@ -97,14 +109,131 @@ func TestUserCommand(t *testing.T) {
97109
)
98110
assertNoErr(t, err)
99111

112+
slices.SortFunc(listUsers, sortWithID)
100113
result = []string{listAfterRenameUsers[0].GetName(), listAfterRenameUsers[1].GetName()}
101-
sort.Strings(result)
102114

103115
assert.Equal(
104116
t,
105-
[]string{"newname", "user1"},
117+
[]string{"user1", "newname"},
106118
result,
107119
)
120+
121+
var listByUsername []*v1.User
122+
err = executeAndUnmarshal(headscale,
123+
[]string{
124+
"headscale",
125+
"users",
126+
"list",
127+
"--output",
128+
"json",
129+
"--name=user1",
130+
},
131+
&listByUsername,
132+
)
133+
assertNoErr(t, err)
134+
135+
slices.SortFunc(listByUsername, sortWithID)
136+
want := []*v1.User{
137+
{
138+
Id: 1,
139+
Name: "user1",
140+
},
141+
}
142+
143+
if diff := tcmp.Diff(want, listByUsername, cmpopts.IgnoreUnexported(v1.User{}), cmpopts.IgnoreFields(v1.User{}, "CreatedAt")); diff != "" {
144+
t.Errorf("unexpected users (-want +got):\n%s", diff)
145+
}
146+
147+
var listByID []*v1.User
148+
err = executeAndUnmarshal(headscale,
149+
[]string{
150+
"headscale",
151+
"users",
152+
"list",
153+
"--output",
154+
"json",
155+
"--identifier=1",
156+
},
157+
&listByID,
158+
)
159+
assertNoErr(t, err)
160+
161+
slices.SortFunc(listByID, sortWithID)
162+
want = []*v1.User{
163+
{
164+
Id: 1,
165+
Name: "user1",
166+
},
167+
}
168+
169+
if diff := tcmp.Diff(want, listByID, cmpopts.IgnoreUnexported(v1.User{}), cmpopts.IgnoreFields(v1.User{}, "CreatedAt")); diff != "" {
170+
t.Errorf("unexpected users (-want +got):\n%s", diff)
171+
}
172+
173+
deleteResult, err := headscale.Execute(
174+
[]string{
175+
"headscale",
176+
"users",
177+
"destroy",
178+
"--force",
179+
// Delete "user1"
180+
"--identifier=1",
181+
},
182+
)
183+
assert.Nil(t, err)
184+
assert.Contains(t, deleteResult, "User destroyed")
185+
186+
var listAfterIDDelete []*v1.User
187+
err = executeAndUnmarshal(headscale,
188+
[]string{
189+
"headscale",
190+
"users",
191+
"list",
192+
"--output",
193+
"json",
194+
},
195+
&listAfterIDDelete,
196+
)
197+
assertNoErr(t, err)
198+
199+
slices.SortFunc(listAfterIDDelete, sortWithID)
200+
want = []*v1.User{
201+
{
202+
Id: 2,
203+
Name: "newname",
204+
},
205+
}
206+
207+
if diff := tcmp.Diff(want, listAfterIDDelete, cmpopts.IgnoreUnexported(v1.User{}), cmpopts.IgnoreFields(v1.User{}, "CreatedAt")); diff != "" {
208+
t.Errorf("unexpected users (-want +got):\n%s", diff)
209+
}
210+
211+
deleteResult, err = headscale.Execute(
212+
[]string{
213+
"headscale",
214+
"users",
215+
"destroy",
216+
"--force",
217+
"--name=newname",
218+
},
219+
)
220+
assert.Nil(t, err)
221+
assert.Contains(t, deleteResult, "User destroyed")
222+
223+
var listAfterNameDelete []v1.User
224+
err = executeAndUnmarshal(headscale,
225+
[]string{
226+
"headscale",
227+
"users",
228+
"list",
229+
"--output",
230+
"json",
231+
},
232+
&listAfterNameDelete,
233+
)
234+
assertNoErr(t, err)
235+
236+
require.Len(t, listAfterNameDelete, 0)
108237
}
109238

110239
func TestPreAuthKeyCommand(t *testing.T) {
@@ -1716,4 +1845,3 @@ func TestPolicyBrokenConfigCommand(t *testing.T) {
17161845
)
17171846
assert.ErrorContains(t, err, "acl policy not found")
17181847
}
1719-

0 commit comments

Comments
 (0)