@@ -2,28 +2,187 @@ package ghcs
22
33import (
44 "context"
5+ "fmt"
6+ "sort"
57 "testing"
8+ "time"
9+
10+ "github.com/github/ghcs/internal/api"
611)
712
813func TestDelete (t * testing.T ) {
14+ user := & api.User {Login : "hubot" }
15+ now , _ := time .Parse (time .RFC3339 , "2021-09-22T00:00:00Z" )
16+ daysAgo := func (n int ) string {
17+ return now .Add (time .Hour * - time .Duration (24 * n )).Format (time .RFC3339 )
18+ }
19+
920 tests := []struct {
10- name string
11- opts deleteOptions
12- wantErr bool
21+ name string
22+ opts deleteOptions
23+ codespaces []* api.Codespace
24+ confirms map [string ]bool
25+ wantErr bool
26+ wantDeleted []string
1327 }{
1428 {
1529 name : "by name" ,
1630 opts : deleteOptions {
17- codespaceName : "foo-bar-123" ,
31+ codespaceName : "hubot-robawt-abc" ,
32+ },
33+ codespaces : []* api.Codespace {
34+ {
35+ Name : "monalisa-spoonknife-123" ,
36+ },
37+ {
38+ Name : "hubot-robawt-abc" ,
39+ },
40+ },
41+ wantDeleted : []string {"hubot-robawt-abc" },
42+ },
43+ {
44+ name : "by repo" ,
45+ opts : deleteOptions {
46+ repoFilter : "monalisa/spoon-knife" ,
47+ },
48+ codespaces : []* api.Codespace {
49+ {
50+ Name : "monalisa-spoonknife-123" ,
51+ RepositoryNWO : "monalisa/Spoon-Knife" ,
52+ },
53+ {
54+ Name : "hubot-robawt-abc" ,
55+ RepositoryNWO : "hubot/ROBAWT" ,
56+ },
57+ {
58+ Name : "monalisa-spoonknife-c4f3" ,
59+ RepositoryNWO : "monalisa/Spoon-Knife" ,
60+ },
61+ },
62+ wantDeleted : []string {"monalisa-spoonknife-123" , "monalisa-spoonknife-c4f3" },
63+ },
64+ {
65+ name : "unused" ,
66+ opts : deleteOptions {
67+ deleteAll : true ,
68+ keepDays : 3 ,
69+ },
70+ codespaces : []* api.Codespace {
71+ {
72+ Name : "monalisa-spoonknife-123" ,
73+ LastUsedAt : daysAgo (1 ),
74+ },
75+ {
76+ Name : "hubot-robawt-abc" ,
77+ LastUsedAt : daysAgo (4 ),
78+ },
79+ {
80+ Name : "monalisa-spoonknife-c4f3" ,
81+ LastUsedAt : daysAgo (10 ),
82+ },
83+ },
84+ wantDeleted : []string {"hubot-robawt-abc" , "monalisa-spoonknife-c4f3" },
85+ },
86+ {
87+ name : "with confirm" ,
88+ opts : deleteOptions {
89+ isInteractive : true ,
90+ deleteAll : true ,
91+ skipConfirm : false ,
92+ },
93+ codespaces : []* api.Codespace {
94+ {
95+ Name : "monalisa-spoonknife-123" ,
96+ Environment : api.CodespaceEnvironment {
97+ GitStatus : api.CodespaceEnvironmentGitStatus {
98+ HasUnpushedChanges : true ,
99+ },
100+ },
101+ },
102+ {
103+ Name : "hubot-robawt-abc" ,
104+ Environment : api.CodespaceEnvironment {
105+ GitStatus : api.CodespaceEnvironmentGitStatus {
106+ HasUncommitedChanges : true ,
107+ },
108+ },
109+ },
110+ {
111+ Name : "monalisa-spoonknife-c4f3" ,
112+ Environment : api.CodespaceEnvironment {
113+ GitStatus : api.CodespaceEnvironmentGitStatus {
114+ HasUnpushedChanges : false ,
115+ HasUncommitedChanges : false ,
116+ },
117+ },
118+ },
18119 },
120+ confirms : map [string ]bool {
121+ "Codespace monalisa-spoonknife-123 has unsaved changes. OK to delete?" : false ,
122+ "Codespace hubot-robawt-abc has unsaved changes. OK to delete?" : true ,
123+ },
124+ wantDeleted : []string {"hubot-robawt-abc" , "monalisa-spoonknife-c4f3" },
19125 },
20126 }
21127 for _ , tt := range tests {
22128 t .Run (tt .name , func (t * testing.T ) {
23- err := delete (context .Background (), tt .opts )
129+ apiMock := & apiClientMock {
130+ GetUserFunc : func (_ context.Context ) (* api.User , error ) {
131+ return user , nil
132+ },
133+ ListCodespacesFunc : func (_ context.Context , userLogin string ) ([]* api.Codespace , error ) {
134+ if userLogin != user .Login {
135+ return nil , fmt .Errorf ("unexpected user %q" , userLogin )
136+ }
137+ return tt .codespaces , nil
138+ },
139+ DeleteCodespaceFunc : func (_ context.Context , userLogin , name string ) error {
140+ if userLogin != user .Login {
141+ return fmt .Errorf ("unexpected user %q" , userLogin )
142+ }
143+ return nil
144+ },
145+ }
146+ opts := tt .opts
147+ opts .apiClient = apiMock
148+ opts .now = func () time.Time { return now }
149+ opts .prompter = & prompterMock {
150+ ConfirmFunc : func (msg string ) (bool , error ) {
151+ res , found := tt .confirms [msg ]
152+ if ! found {
153+ return false , fmt .Errorf ("unexpected prompt %q" , msg )
154+ }
155+ return res , nil
156+ },
157+ }
158+
159+ err := delete (context .Background (), opts )
24160 if (err != nil ) != tt .wantErr {
25161 t .Errorf ("delete() error = %v, wantErr %v" , err , tt .wantErr )
26162 }
163+ if n := len (apiMock .GetUserCalls ()); n != 1 {
164+ t .Errorf ("GetUser invoked %d times, expected %d" , n , 1 )
165+ }
166+ var gotDeleted []string
167+ for _ , delArgs := range apiMock .DeleteCodespaceCalls () {
168+ gotDeleted = append (gotDeleted , delArgs .Name )
169+ }
170+ sort .Strings (gotDeleted )
171+ if ! sliceEquals (gotDeleted , tt .wantDeleted ) {
172+ t .Errorf ("deleted %q, want %q" , gotDeleted , tt .wantDeleted )
173+ }
27174 })
28175 }
29176}
177+
178+ func sliceEquals (a , b []string ) bool {
179+ if len (a ) != len (b ) {
180+ return false
181+ }
182+ for i := range a {
183+ if a [i ] != b [i ] {
184+ return false
185+ }
186+ }
187+ return true
188+ }
0 commit comments