Skip to content

Commit 147da27

Browse files
committed
Preserve configure path ordering
1 parent 8e20aff commit 147da27

3 files changed

Lines changed: 57 additions & 22 deletions

File tree

server/cmd/api/api/chromium_configure.go

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,19 @@ func (s *ApiService) ChromiumConfigure(ctx context.Context, request oapi.Chromiu
8181
defer s.chromiumConfigMu.Unlock()
8282

8383
var configureResp oapi.ChromiumConfigureResponseObject
84+
var stoppedRecordings []stoppedRecordingInfo
8485
switch chromiumConfigureModeFor(st) {
8586
case chromiumConfigureModeLive:
8687
configureResp = s.chromiumConfigureLive(ctx, st)
8788
case chromiumConfigureModeRestart:
88-
configureResp = s.chromiumConfigureRestart(ctx, st, spec)
89+
configureResp, stoppedRecordings = s.chromiumConfigureRestart(ctx, st, spec)
90+
default:
91+
return cfg500Configure("unhandled configure mode"), nil
92+
}
93+
if len(stoppedRecordings) > 0 {
94+
defer func() {
95+
go s.startNewRecordingSegments(context.WithoutCancel(ctx), stoppedRecordings)
96+
}()
8997
}
9098
if configureResp != nil {
9199
return configureResp, nil
@@ -133,7 +141,7 @@ func (s *ApiService) chromiumConfigureLive(ctx context.Context, st *chromiumConf
133141
return chromiumRunPatchDisplay(ctx, s, displayPlan.body)
134142
}
135143

136-
func (s *ApiService) chromiumConfigureRestart(ctx context.Context, st *chromiumConfigureState, spec startURLParsed) (resp oapi.ChromiumConfigureResponseObject) {
144+
func (s *ApiService) chromiumConfigureRestart(ctx context.Context, st *chromiumConfigureState, spec startURLParsed) (resp oapi.ChromiumConfigureResponseObject, stoppedRecordings []stoppedRecordingInfo) {
137145
chromiumStopped := false
138146
restartAfterStop := func() error {
139147
if !chromiumStopped {
@@ -146,6 +154,12 @@ func (s *ApiService) chromiumConfigureRestart(ctx context.Context, st *chromiumC
146154
return nil
147155
}
148156
defer func() {
157+
// Error paths restart recordings before Chromium recovery. Successful paths
158+
// return them so the caller waits until after navigation.
159+
if (resp != nil || chromiumStopped) && len(stoppedRecordings) > 0 {
160+
go s.startNewRecordingSegments(context.WithoutCancel(ctx), stoppedRecordings)
161+
stoppedRecordings = nil
162+
}
149163
if restartErr := restartAfterStop(); restartErr != nil {
150164
if resp != nil {
151165
logger.FromContext(ctx).Error("failed to restart chromium after configure error", "error", restartErr)
@@ -157,51 +171,47 @@ func (s *ApiService) chromiumConfigureRestart(ctx context.Context, st *chromiumC
157171

158172
logger.FromContext(ctx).Info("chromium configure (stop/start path)")
159173
if err := s.stopChromium(ctx); err != nil {
160-
return cfg500ConfigureStep(chromiumConfigureStepStop, err.Error())
174+
return cfg500ConfigureStep(chromiumConfigureStepStop, err.Error()), stoppedRecordings
161175
}
162176
chromiumStopped = true
163177

164178
policyOverrides, err := chromiumValidatePolicies(st.chromePoliciesJSON)
165179
if err != nil {
166-
return cfgResponseFromStepError(chromiumConfigureStepPolicies, err)
180+
return cfgResponseFromStepError(chromiumConfigureStepPolicies, err), stoppedRecordings
167181
}
168182
if err := chromiumApplyPolicies(ctx, s, policyOverrides); err != nil {
169-
return cfgResponseFromStepError(chromiumConfigureStepPolicies, err)
183+
return cfgResponseFromStepError(chromiumConfigureStepPolicies, err), stoppedRecordings
170184
}
171185

172186
if reqMsgs, ierr := chromiumApplyExtensions(ctx, s, st.extItems); reqMsgs != "" {
173-
return cfg400(fmt.Sprintf("%s: %s", chromiumConfigureStepExtensions, reqMsgs))
187+
return cfg400(fmt.Sprintf("%s: %s", chromiumConfigureStepExtensions, reqMsgs)), stoppedRecordings
174188
} else if ierr != nil {
175-
return cfg500ConfigureStep(chromiumConfigureStepExtensions, ierr.Error())
189+
return cfg500ConfigureStep(chromiumConfigureStepExtensions, ierr.Error()), stoppedRecordings
176190
}
177191

178192
if st.displayJSON != nil && strings.TrimSpace(*st.displayJSON) != "" {
179193
displayPlan, displayResp := chromiumPrepareDisplay(ctx, s, st.displayJSON)
180194
if displayResp != nil {
181-
return displayResp
195+
return displayResp, stoppedRecordings
182196
}
183197
if displayPlan != nil {
184198
stopped, stopErr := s.stopActiveRecordings(ctx)
185199
if stopErr != nil {
186-
return cfg500ConfigureStep(chromiumConfigureStepDisplay, fmt.Sprintf("failed to stop recordings: %v", stopErr))
187-
}
188-
if len(stopped) > 0 {
189-
defer func() {
190-
go s.startNewRecordingSegments(context.WithoutCancel(ctx), stopped)
191-
}()
200+
return cfg500ConfigureStep(chromiumConfigureStepDisplay, fmt.Sprintf("failed to stop recordings: %v", stopErr)), stoppedRecordings
192201
}
202+
stoppedRecordings = stopped
193203
if rr := chromiumDisplayApplyWhileStopped(ctx, s, displayPlan); rr != nil {
194-
return rr
204+
return rr, stoppedRecordings
195205
}
196206
}
197207
}
198208

199209
flagsPlan, err := chromiumValidateFlags(st.chromiumFlagsJSON)
200210
if err != nil {
201-
return cfgResponseFromStepError(chromiumConfigureStepFlags, err)
211+
return cfgResponseFromStepError(chromiumConfigureStepFlags, err), stoppedRecordings
202212
}
203213
if err := chromiumMergeFlags(ctx, s, flagsPlan); err != nil {
204-
return cfgResponseFromStepError(chromiumConfigureStepFlags, err)
214+
return cfgResponseFromStepError(chromiumConfigureStepFlags, err), stoppedRecordings
205215
}
206216

207217
if st.hasProfile {
@@ -210,22 +220,22 @@ func (s *ApiService) chromiumConfigureRestart(ctx context.Context, st *chromiumC
210220
defer cleanupProfile()
211221
}
212222
if err != nil {
213-
return cfg500ConfigureStep(chromiumConfigureStepProfile, err.Error())
223+
return cfg500ConfigureStep(chromiumConfigureStepProfile, err.Error()), stoppedRecordings
214224
}
215225
if spec.needsNav {
216226
if err := stripProfileSessionRestore(preparedProfile); err != nil {
217-
return cfg500ConfigureStep(chromiumConfigureStepProfile, err.Error())
227+
return cfg500ConfigureStep(chromiumConfigureStepProfile, err.Error()), stoppedRecordings
218228
}
219229
}
220230
if err := chromiumInstallPreparedProfile(preparedProfile); err != nil {
221-
return cfg500ConfigureStep(chromiumConfigureStepProfile, err.Error())
231+
return cfg500ConfigureStep(chromiumConfigureStepProfile, err.Error()), stoppedRecordings
222232
}
223233
}
224234

225235
if err := restartAfterStop(); err != nil {
226-
return cfg500ConfigureStep(chromiumConfigureStepStart, err.Error())
236+
return cfg500ConfigureStep(chromiumConfigureStepStart, err.Error()), stoppedRecordings
227237
}
228-
return nil
238+
return nil, stoppedRecordings
229239
}
230240

231241
type startURLParsed struct {

server/cmd/api/api/chromium_configure_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,30 @@ func TestChromiumConfigureModeFor(t *testing.T) {
5858
}
5959
}
6060

61+
func TestChromiumConfigureActionables(t *testing.T) {
62+
emptyFlags := `{"flags":[]}`
63+
realFlags := `{"flags":["--kiosk"]}`
64+
emptyPolicies := `{}`
65+
realPolicies := `{"QuicAllowed":false}`
66+
67+
tests := []struct {
68+
name string
69+
state chromiumConfigureState
70+
want int
71+
}{
72+
{name: "empty flags", state: chromiumConfigureState{chromiumFlagsJSON: &emptyFlags}},
73+
{name: "nonempty flags", state: chromiumConfigureState{chromiumFlagsJSON: &realFlags}, want: 1},
74+
{name: "empty policies", state: chromiumConfigureState{chromePoliciesJSON: &emptyPolicies}},
75+
{name: "nonempty policies", state: chromiumConfigureState{chromePoliciesJSON: &realPolicies}, want: 1},
76+
}
77+
78+
for _, tt := range tests {
79+
t.Run(tt.name, func(t *testing.T) {
80+
require.Equal(t, tt.want, cfgActionables(&tt.state))
81+
})
82+
}
83+
}
84+
6185
func TestChromiumStartURLSpec(t *testing.T) {
6286
bareHost := "roblox.com"
6387
out, errs := chromiumStartURLSpec(&bareHost)

server/e2e/e2e_chromium_configure_powerset_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ func TestChromiumConfigureMultipartPowerset(t *testing.T) {
106106
}
107107

108108
func chromiumConfigurePowersetRestarts(bits int) bool {
109+
// This matrix runs against headless Xvfb, where display-only configure stays live.
109110
return bits&(matPolicy|matKioskFlags|matExtension) != 0
110111
}
111112

0 commit comments

Comments
 (0)