remote_session_test.go RawHistoryFolder

1package domain
2
3import "testing"
4
5func TestRemoteSessionKeyID(t *testing.T) {
6	tests := []struct {
7		name string
8		key  RemoteSessionKey
9		want SessionID
10	}{
11		{
12			name: "uses raw URL base64 components",
13			key:  RemoteSessionKey{Host: "arch", Name: "hello"},
14			want: "remote:YXJjaA.aGVsbG8",
15		},
16		{
17			name: "preserves host metacharacters without delimiters",
18			key:  RemoteSessionKey{Host: "build@mule:2222/path.[x]", Name: "work.1"},
19			want: "remote:YnVpbGRAbXVsZToyMjIyL3BhdGguW3hd.d29yay4x",
20		},
21		{
22			name: "supports bracketed IPv6 hosts",
23			key:  RemoteSessionKey{Host: "user@[2001:db8::1]:2222", Name: "work"},
24			want: "remote:dXNlckBbMjAwMTpkYjg6OjFdOjIyMjI.d29yaw",
25		},
26	}
27
28	for _, tt := range tests {
29		t.Run(tt.name, func(t *testing.T) {
30			if got := tt.key.ID(); got != tt.want {
31				t.Fatalf("RemoteSessionKey.ID() = %q, want %q", got, tt.want)
32			}
33			if got := tt.key.ID(); got != tt.key.ID() {
34				t.Fatalf("RemoteSessionKey.ID() is unstable: %q != %q", got, tt.key.ID())
35			}
36		})
37	}
38}
39
40func TestRemoteSessionKeyIDAvoidsRawConcatenationCollisions(t *testing.T) {
41	tests := []struct {
42		name  string
43		first RemoteSessionKey
44		last  RemoteSessionKey
45	}{
46		{
47			name:  "host component delimiter",
48			first: RemoteSessionKey{Host: "arch.work", Name: "shell"},
49			last:  RemoteSessionKey{Host: "arch", Name: "work.shell"},
50		},
51	}
52
53	for _, tt := range tests {
54		t.Run(tt.name, func(t *testing.T) {
55			if tt.first.Host+"."+tt.first.Name != tt.last.Host+"."+tt.last.Name {
56				t.Fatal("test setup does not collide under raw concatenation")
57			}
58			if tt.first.ID() == tt.last.ID() {
59				t.Fatalf("distinct keys have the same ID: %q", tt.first.ID())
60			}
61		})
62	}
63}
64
65func TestRemoteSessionKeyValidate(t *testing.T) {
66	tests := []struct {
67		name    string
68		key     RemoteSessionKey
69		wantErr bool
70	}{
71		{name: "valid", key: RemoteSessionKey{Host: "build@mule:2222/path", Name: "work.1"}},
72		{name: "empty host", key: RemoteSessionKey{Name: "work"}, wantErr: true},
73		{name: "host whitespace", key: RemoteSessionKey{Host: "build mule", Name: "work"}, wantErr: true},
74		{name: "empty session", key: RemoteSessionKey{Host: "arch"}, wantErr: true},
75		{name: "unsafe session", key: RemoteSessionKey{Host: "arch", Name: "work/session"}, wantErr: true},
76	}
77
78	for _, tt := range tests {
79		t.Run(tt.name, func(t *testing.T) {
80			err := tt.key.Validate()
81			if tt.wantErr && err == nil {
82				t.Fatal("RemoteSessionKey.Validate() = nil, want error")
83			}
84			if !tt.wantErr && err != nil {
85				t.Fatalf("RemoteSessionKey.Validate() = %v, want nil", err)
86			}
87		})
88	}
89}
90
91func TestRemoteSessionKeyDisplayIsPresentationOnly(t *testing.T) {
92	tests := []struct {
93		host          string
94		displayOrigin string
95		want          string
96	}{
97		{host: "arch", want: "hello@arch"},
98		{host: "route", displayOrigin: "user@arch", want: "hello@arch"},
99		{host: "test@arch", want: "hello@arch"},
100		{host: "test@arch:2222", want: "hello@arch:2222"},
101		{host: "test@[2001:db8::1]:2222", want: "hello@[2001:db8::1]:2222"},
102		{host: "test@", want: "hello@test@"},
103		{host: "@arch", want: "hello@arch"},
104	}
105	for _, test := range tests {
106		t.Run(test.host, func(t *testing.T) {
107			key := RemoteSessionKey{Host: test.host, Name: "hello", DisplayOrigin: test.displayOrigin}
108			if got := key.Display(); got != test.want {
109				t.Fatalf("RemoteSessionKey.Display() = %q, want %q", got, test.want)
110			}
111			if key.Host != test.host || key.Name != "hello" {
112				t.Fatalf("Display mutated routing key: %#v", key)
113			}
114		})
115	}
116}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 12

Tags 11

↑↓ moveenter openesc close