@@ -16,106 +16,143 @@ import (
1616
1717func TestWorkspaceBuild (t * testing.T ) {
1818 t .Parallel ()
19- t .Run ("TemplateRequiresActiveVersion" , func (t * testing.T ) {
20- t .Parallel ()
2119
22- ctx := testutil . Context ( t , testutil . WaitMedium )
23- ownerClient , owner := coderdenttest . New (t , & coderdenttest. Options {
24- Options : & coderdtest .Options {
25- IncludeProvisionerDaemon : true ,
26- } ,
27- LicenseOptions : & coderdenttest. LicenseOptions {
28- Features : license. Features {
29- codersdk . FeatureAccessControl : 1 ,
30- codersdk .FeatureTemplateRBAC : 1 ,
31- codersdk .FeatureAdvancedTemplateScheduling : 1 ,
32- } ,
20+ // Only use this context for setup. Use a separate context for subtests!
21+ setupCtx := testutil . Context (t , testutil . WaitMedium )
22+ ownerClient , owner := coderdenttest . New ( t , & coderdenttest .Options {
23+ Options : & coderdtest. Options {
24+ IncludeProvisionerDaemon : true ,
25+ },
26+ LicenseOptions : & coderdenttest. LicenseOptions {
27+ Features : license. Features {
28+ codersdk .FeatureAccessControl : 1 ,
29+ codersdk .FeatureTemplateRBAC : 1 ,
30+ codersdk . FeatureAdvancedTemplateScheduling : 1 ,
3331 },
34- })
32+ },
33+ })
3534
36- // Create an initial version.
37- oldVersion := coderdtest .CreateTemplateVersion (t , ownerClient , owner .OrganizationID , nil )
38- // Create a template that mandates the promoted version.
39- // This should be enforced for everyone except template admins.
40- template := coderdtest .CreateTemplate (t , ownerClient , owner .OrganizationID , oldVersion .ID )
41- coderdtest .AwaitTemplateVersionJobCompleted (t , ownerClient , oldVersion .ID )
42- require .Equal (t , oldVersion .ID , template .ActiveVersionID )
43- template = coderdtest .UpdateTemplateMeta (t , ownerClient , template .ID , codersdk.UpdateTemplateMeta {
44- RequireActiveVersion : true ,
45- })
46- require .True (t , template .RequireActiveVersion )
35+ // For this test we create two templates:
36+ // tplA will be used to test creation of new workspaces.
37+ // tplB will be used to test builds on existing workspaces.
38+ // This is done to enable parallelization of the sub-tests without them interfering with each other.
39+ // Both templates mandate the promoted version.
40+ // This should be enforced for everyone except template admins.
41+ tplAv1 := coderdtest .CreateTemplateVersion (t , ownerClient , owner .OrganizationID , nil )
42+ tplA := coderdtest .CreateTemplate (t , ownerClient , owner .OrganizationID , tplAv1 .ID )
43+ coderdtest .AwaitTemplateVersionJobCompleted (t , ownerClient , tplAv1 .ID )
44+ require .Equal (t , tplAv1 .ID , tplA .ActiveVersionID )
45+ tplA = coderdtest .UpdateTemplateMeta (t , ownerClient , tplA .ID , codersdk.UpdateTemplateMeta {
46+ RequireActiveVersion : true ,
47+ })
48+ require .True (t , tplA .RequireActiveVersion )
49+ tplAv2 := coderdtest .CreateTemplateVersion (t , ownerClient , owner .OrganizationID , nil , func (ctvr * codersdk.CreateTemplateVersionRequest ) {
50+ ctvr .TemplateID = tplA .ID
51+ })
52+ coderdtest .AwaitTemplateVersionJobCompleted (t , ownerClient , tplAv2 .ID )
53+ coderdtest .UpdateActiveTemplateVersion (t , ownerClient , tplA .ID , tplAv2 .ID )
4754
48- // Create a new version that we will promote.
49- activeVersion := coderdtest .CreateTemplateVersion (t , ownerClient , owner .OrganizationID , nil , func (ctvr * codersdk.CreateTemplateVersionRequest ) {
50- ctvr .TemplateID = template .ID
51- })
52- coderdtest .AwaitTemplateVersionJobCompleted (t , ownerClient , activeVersion .ID )
53- coderdtest .UpdateActiveTemplateVersion (t , ownerClient , template .ID , activeVersion .ID )
55+ tplBv1 := coderdtest .CreateTemplateVersion (t , ownerClient , owner .OrganizationID , nil )
56+ tplB := coderdtest .CreateTemplate (t , ownerClient , owner .OrganizationID , tplBv1 .ID )
57+ coderdtest .AwaitTemplateVersionJobCompleted (t , ownerClient , tplBv1 .ID )
58+ require .Equal (t , tplBv1 .ID , tplB .ActiveVersionID )
59+ tplB = coderdtest .UpdateTemplateMeta (t , ownerClient , tplB .ID , codersdk.UpdateTemplateMeta {
60+ RequireActiveVersion : true ,
61+ })
62+ require .True (t , tplB .RequireActiveVersion )
5463
55- templateAdminClient , _ := coderdtest .CreateAnotherUser (t , ownerClient , owner .OrganizationID , rbac .RoleTemplateAdmin ())
56- templateACLAdminClient , templateACLAdmin := coderdtest .CreateAnotherUser (t , ownerClient , owner .OrganizationID )
57- templateGroupACLAdminClient , templateGroupACLAdmin := coderdtest .CreateAnotherUser (t , ownerClient , owner .OrganizationID )
58- memberClient , _ := coderdtest .CreateAnotherUser (t , ownerClient , owner .OrganizationID )
64+ templateAdminClient , _ := coderdtest .CreateAnotherUser (t , ownerClient , owner .OrganizationID , rbac .RoleTemplateAdmin ())
65+ templateACLAdminClient , templateACLAdmin := coderdtest .CreateAnotherUser (t , ownerClient , owner .OrganizationID )
66+ templateGroupACLAdminClient , templateGroupACLAdmin := coderdtest .CreateAnotherUser (t , ownerClient , owner .OrganizationID )
67+ memberClient , _ := coderdtest .CreateAnotherUser (t , ownerClient , owner .OrganizationID )
5968
60- // Create a group so we can also test group template admin ownership.
61- // Add the user who gains template admin via group membership.
62- group := coderdtest .CreateGroup (t , ownerClient , owner .OrganizationID , "test" , templateGroupACLAdmin )
69+ // Create a group so we can also test group template admin ownership.
70+ // Add the user who gains template admin via group membership.
71+ group := coderdtest .CreateGroup (t , ownerClient , owner .OrganizationID , "test" , templateGroupACLAdmin )
6372
64- // Update the template for both users and groups.
65- //nolint:gocritic // test setup
66- err := ownerClient .UpdateTemplateACL (ctx , template .ID , codersdk.UpdateTemplateACL {
73+ // Update the template for both users and groups.
74+ //nolint:gocritic // test setup
75+ for _ , tpl := range []codersdk.Template {tplA , tplB } {
76+ err := ownerClient .UpdateTemplateACL (setupCtx , tpl .ID , codersdk.UpdateTemplateACL {
6777 UserPerms : map [string ]codersdk.TemplateRole {
6878 templateACLAdmin .ID .String (): codersdk .TemplateRoleAdmin ,
6979 },
7080 GroupPerms : map [string ]codersdk.TemplateRole {
7181 group .ID .String (): codersdk .TemplateRoleAdmin ,
7282 },
7383 })
74- require .NoError (t , err )
84+ require .NoError (t , err , "updating template ACL for template %q" , tpl .ID )
85+ }
7586
76- type testcase struct {
77- Name string
78- Client * codersdk.Client
79- ExpectedStatusCode int
80- }
87+ type testcase struct {
88+ Name string
89+ Client * codersdk.Client
90+ ExpectedStatusCode int
91+ }
8192
82- cases := []testcase {
83- {
84- Name : "OwnerOK" ,
85- Client : ownerClient ,
86- ExpectedStatusCode : http .StatusOK ,
87- },
88- {
89- Name : "TemplateAdminOK" ,
90- Client : templateAdminClient ,
91- ExpectedStatusCode : http .StatusOK ,
92- },
93- {
94- Name : "TemplateACLAdminOK" ,
95- Client : templateACLAdminClient ,
96- ExpectedStatusCode : http .StatusOK ,
97- },
98- {
99- Name : "TemplateGroupACLAdminOK" ,
100- Client : templateGroupACLAdminClient ,
101- ExpectedStatusCode : http .StatusOK ,
102- },
103- {
104- Name : "MemberFails" ,
105- Client : memberClient ,
106- ExpectedStatusCode : http .StatusForbidden ,
107- },
108- }
93+ cases := []testcase {
94+ {
95+ Name : "OwnerOK" ,
96+ Client : ownerClient ,
97+ ExpectedStatusCode : http .StatusOK ,
98+ },
99+ {
100+ Name : "TemplateAdminOK" ,
101+ Client : templateAdminClient ,
102+ ExpectedStatusCode : http .StatusOK ,
103+ },
104+ {
105+ Name : "TemplateACLAdminOK" ,
106+ Client : templateACLAdminClient ,
107+ ExpectedStatusCode : http .StatusOK ,
108+ },
109+ {
110+ Name : "TemplateGroupACLAdminOK" ,
111+ Client : templateGroupACLAdminClient ,
112+ ExpectedStatusCode : http .StatusOK ,
113+ },
114+ {
115+ Name : "MemberFailsToCreate" ,
116+ Client : memberClient ,
117+ ExpectedStatusCode : http .StatusForbidden ,
118+ },
119+ }
120+
121+ // Create pre-existing workspaces for each of the test cases.
122+ var extantWorkspaces []codersdk.Workspace
123+ for _ , c := range cases {
124+ extantWs , err := c .Client .CreateUserWorkspace (setupCtx , codersdk .Me , codersdk.CreateWorkspaceRequest {
125+ TemplateVersionID : tplB .ActiveVersionID ,
126+ Name : testutil .GetRandomNameHyphenated (t ),
127+ AutomaticUpdates : codersdk .AutomaticUpdatesNever ,
128+ })
129+ require .NoError (t , err , "setup workspace for case %q" , c .Name )
130+ coderdtest .AwaitWorkspaceBuildJobCompleted (t , c .Client , extantWs .LatestBuild .ID )
131+ extantWorkspaces = append (extantWorkspaces , extantWs )
132+ }
133+
134+ // Create a new version of template B and promote it to be the active version.
135+ tplBv2 := coderdtest .CreateTemplateVersion (t , ownerClient , owner .OrganizationID , nil , func (ctvr * codersdk.CreateTemplateVersionRequest ) {
136+ ctvr .TemplateID = tplB .ID
137+ })
138+ coderdtest .AwaitTemplateVersionJobCompleted (t , ownerClient , tplBv2 .ID )
139+ coderdtest .UpdateActiveTemplateVersion (t , ownerClient , tplB .ID , tplBv2 .ID )
140+
141+ t .Run ("NewWorkspace" , func (t * testing.T ) {
142+ t .Parallel ()
109143
110144 for _ , c := range cases {
111145 t .Run (c .Name , func (t * testing.T ) {
112- _ , err = c .Client .CreateUserWorkspace (ctx , codersdk .Me , codersdk.CreateWorkspaceRequest {
113- TemplateVersionID : oldVersion .ID ,
114- Name : "abc123" ,
146+ t .Parallel ()
147+ ctx := testutil .Context (t , testutil .WaitMedium )
148+ ws , err := c .Client .CreateUserWorkspace (ctx , codersdk .Me , codersdk.CreateWorkspaceRequest {
149+ TemplateVersionID : tplAv1 .ID ,
150+ Name : testutil .GetRandomNameHyphenated (t ),
115151 AutomaticUpdates : codersdk .AutomaticUpdatesNever ,
116152 })
117153 if c .ExpectedStatusCode == http .StatusOK {
118154 require .NoError (t , err )
155+ require .Equal (t , tplAv1 .ID , ws .LatestBuild .TemplateVersionID , "workspace did not use expected version for case %q" , c .Name )
119156 } else {
120157 require .Error (t , err )
121158 cerr , ok := codersdk .AsError (err )
@@ -125,4 +162,37 @@ func TestWorkspaceBuild(t *testing.T) {
125162 })
126163 }
127164 })
165+
166+ t .Run ("ExistingWorkspace" , func (t * testing.T ) {
167+ t .Parallel ()
168+
169+ for idx , c := range cases {
170+ t .Run (c .Name , func (t * testing.T ) {
171+ t .Parallel ()
172+ ctx := testutil .Context (t , testutil .WaitMedium )
173+ // Stopping the workspace must always succeed.
174+ wb , err := c .Client .CreateWorkspaceBuild (ctx , extantWorkspaces [idx ].ID , codersdk.CreateWorkspaceBuildRequest {
175+ Transition : codersdk .WorkspaceTransitionStop ,
176+ })
177+ require .NoError (t , err , "stopping workspace for case %q" , c .Name )
178+ coderdtest .AwaitWorkspaceBuildJobCompleted (t , c .Client , wb .ID )
179+
180+ // Attempt to start the workspace with the given version.
181+ wb , err = c .Client .CreateWorkspaceBuild (ctx , extantWorkspaces [idx ].ID , codersdk.CreateWorkspaceBuildRequest {
182+ Transition : codersdk .WorkspaceTransitionStart ,
183+ TemplateVersionID : tplBv1 .ID ,
184+ })
185+ if c .ExpectedStatusCode == http .StatusOK {
186+ require .NoError (t , err , "starting workspace for case %q" , c .Name )
187+ coderdtest .AwaitWorkspaceBuildJobCompleted (t , c .Client , wb .ID )
188+ require .Equal (t , tplBv1 .ID , wb .TemplateVersionID , "workspace did not use expected version for case %q" , c .Name )
189+ } else {
190+ require .Error (t , err , "starting workspace for case %q" , c .Name )
191+ cerr , ok := codersdk .AsError (err )
192+ require .True (t , ok )
193+ require .Equal (t , c .ExpectedStatusCode , cerr .StatusCode ())
194+ }
195+ })
196+ }
197+ })
128198}
0 commit comments