/
opt_in_after_interruption.go
253 lines (228 loc) · 9.43 KB
/
opt_in_after_interruption.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package arc
import (
"context"
"strconv"
"time"
"chromiumos/tast/errors"
"chromiumos/tast/local/arc"
"chromiumos/tast/local/arc/optin"
"chromiumos/tast/local/chrome"
"chromiumos/tast/testing"
)
const (
// Timeout to wait ARC provisioning is completed. Based on UMA stats in released
// versions: http://uma/p/chrome/timeline_v2/?sid=206fdf1b0f02474ec11c6797f5668092
arcProvisionedWaitTimeOut = 90 * time.Second
// Interval to check ARC provisioning status.
arcProvisionedCheckInterval = 1 * time.Second
)
type optInTestParams struct {
username string // username for Chrome login.
password string // password to login.
delays []time.Duration // slice of delays for Chrome restart in seconds.
chromeArgs []string // Arguments to pass to Chrome command line.
}
// unmangedDelays contains delays for unmanaged account tests
var unmangedDelays = []time.Duration{7 * time.Second, 17 * time.Second, 22 * time.Second, 32 * time.Second, 42 * time.Second}
// managedDelays contains delays for managed account tests
var managedDelays = []time.Duration{10 * time.Second, 21 * time.Second, 26 * time.Second, 36 * time.Second, 46 * time.Second}
func init() {
testing.AddTest(&testing.Test{
Func: OptInAfterInterruption,
LacrosStatus: testing.LacrosVariantNeeded,
Desc: "Verify ARC Provisioning completes even with interruptions by restarting Chrome",
Contacts: []string{
"arc-performance@google.com",
"alanding@chromium.org", // Tast port author.
"khmel@chromium.org", // Original autotest author.
},
Attr: []string{"group:mainline", "informational"},
SoftwareDeps: []string{"chrome", "chrome_internal"},
Timeout: 10 * time.Minute,
Params: []testing.Param{{
Name: "unmanaged",
ExtraSoftwareDeps: []string{"android_p"},
Val: optInTestParams{
username: "arc.OptInAfterInterruption.unmanaged_username",
password: "arc.OptInAfterInterruption.unmanaged_password",
delays: unmangedDelays,
chromeArgs: []string{},
},
}, {
Name: "unmanaged_vm",
ExtraSoftwareDeps: []string{"android_vm"},
Val: optInTestParams{
username: "arc.OptInAfterInterruption.unmanaged_username",
password: "arc.OptInAfterInterruption.unmanaged_password",
delays: unmangedDelays,
chromeArgs: []string{"--ignore-arcvm-dev-conf"},
},
}, {
Name: "managed",
ExtraSoftwareDeps: []string{"android_p"},
Val: optInTestParams{
username: "arc.OptInAfterInterruption.managed_username",
password: "arc.OptInAfterInterruption.managed_password",
delays: managedDelays,
chromeArgs: []string{"--arc-force-show-optin-ui"},
},
}, {
Name: "managed_vm",
ExtraSoftwareDeps: []string{"android_vm"},
Val: optInTestParams{
username: "arc.OptInAfterInterruption.managed_username",
password: "arc.OptInAfterInterruption.managed_password",
delays: managedDelays,
chromeArgs: []string{"--arc-force-show-optin-ui", "--ignore-arcvm-dev-conf"},
},
}},
VarDeps: []string{
"arc.OptInAfterInterruption.unmanaged_username",
"arc.OptInAfterInterruption.unmanaged_password",
"arc.OptInAfterInterruption.managed_username",
"arc.OptInAfterInterruption.managed_password",
},
})
}
// OptInAfterInterruption verifies ARC provisioning is completed after interruption.
//
// This test runs for multiple iterations. On each iteration it starts initial
// ARC provisioning and then restarts Chrome after some delay. It confirms that ARC
// completes provisioning on next login. The delays used for each test iteration
// are based on cheets_OptInAfterInterruption autotest data collected during NYC.
// If the expected delays list is exhausted, the test will fail. The test passes
// when ARC is provisioned before Chrome restarts. The pass case indicates that
// trying longer delays does not make sense on this platform because ARC would be
// provisioning in this interval and next Chrome restart will deal with already
// provisioned ARC and provisioning flow won't be initiated.
func OptInAfterInterruption(ctx context.Context, s *testing.State) {
param := s.Param().(optInTestParams)
username := s.RequiredVar(param.username)
password := s.RequiredVar(param.password)
extraArgs := param.chromeArgs
args := append(arc.DisableSyncFlags(), extraArgs...)
attempts := 1
for _, delay := range param.delays {
s.Logf("Start iteration for %v delay", delay)
if continueTesting, err := attemptOptIn(ctx, username, password, args, delay, param.delays[0]); err != nil {
s.Fatal("Failed to attempting to complete optin: ", err)
} else if !continueTesting {
s.Logf("Completed ARC provisioning before finishing iteration for %v delay", delay)
break
}
func() {
// ARC should start automatically due acceptance above.
// chrome.KeepState() is set to prevent data clean-up.
s.Log("Log into another Chrome instance")
cr, err := chrome.New(
ctx,
chrome.ARCSupported(),
chrome.GAIALogin(chrome.Creds{User: username, Pass: password}),
chrome.ExtraArgs(args...),
chrome.KeepState(),
)
if err != nil {
s.Fatal("Failed to connect to Chrome: ", err)
}
defer cr.Close(ctx)
tconn, err := cr.TestAPIConn(ctx)
if err != nil {
s.Fatal("Failed to create test API connection: ", err)
}
s.Log("Wait for ARC to complete provisioning")
if err := waitForArcProvisioned(ctx, tconn); err != nil {
if err := optin.DumpLogCat(ctx, strconv.Itoa(attempts)); err != nil {
s.Logf("WARNING: Failed to dump logcat: %s", err)
}
s.Fatal("Failed to wait for ARC to complete provisioning: ", err)
}
s.Log("ARC is provisioned after restart")
}()
s.Logf("End iteration for %v delay", delay)
attempts++
}
}
// checkArcProvisioned checks whether ARC provisioning is completed.
func checkArcProvisioned(ctx context.Context, tconn *chrome.TestConn) (bool, error) {
var provisioned bool
if err := tconn.Eval(ctx, `tast.promisify(chrome.autotestPrivate.isArcProvisioned)()`, &provisioned); err != nil {
return false, errors.Wrap(err, "failed running autotestPrivate.isArcProvisioned")
}
return provisioned, nil
}
// waitForArcProvisioned waits until ARC provisioning is completed.
func waitForArcProvisioned(ctx context.Context, tconn *chrome.TestConn) error {
err := testing.Poll(ctx, func(ctx context.Context) error {
if provisioned, err := checkArcProvisioned(ctx, tconn); err != nil {
return testing.PollBreak(err)
} else if !provisioned {
return errors.New("provisioning for ARC is not complete yet")
}
return nil
}, &testing.PollOptions{
Timeout: arcProvisionedWaitTimeOut,
Interval: arcProvisionedCheckInterval,
})
if err != nil {
return errors.Wrap(err, "failed to wait for ARC provisioning to complete")
}
return nil
}
// attemptOptIn tries to complete ARC provisioning within the specified delay
// and returns true to continue if provisioning attempt did not succeed.
func attemptOptIn(ctx context.Context, username, password string, args []string, delay, firstRun time.Duration) (bool, error) {
testing.ContextLog(ctx, "Log into Chrome instance")
cr, err := chrome.New(
ctx,
chrome.ARCSupported(),
chrome.GAIALogin(chrome.Creds{User: username, Pass: password}),
chrome.ExtraArgs(args...),
)
if err != nil {
return false, errors.Wrap(err, "failed to connect to Chrome")
}
defer cr.Close(ctx)
tconn, err := cr.TestAPIConn(ctx)
if err != nil {
return false, errors.Wrap(err, "failed to create test API connection")
}
testing.ContextLog(ctx, "Check Play Store state")
if playStoreState, err := optin.GetPlayStoreState(ctx, tconn); err != nil {
return false, errors.Wrap(err, "failed to check Play Store state")
} else if playStoreState["allowed"] == false {
// Validity check in case Play Store account settings or accounts changed.
return false, errors.New("invalid response with Play Store state set to not allowed")
}
testing.ContextLog(ctx, "Performing optin to Play Store (enabling ARC)")
if err := optin.SetPlayStoreEnabled(ctx, tconn, true); err != nil {
return false, errors.Wrap(err, "failed to set enable Play Store")
}
// Press Agree to continue optin. Managed account is normally tuned to
// optin silently, but the Chrome arg "--arc-force-show-optin-ui" is
// used to simplify the unmanaged vs. managed flow.
testing.ContextLog(ctx, "Show optin UI and accept terms of service")
if err := optin.FindOptInExtensionPageAndAcceptTerms(ctx, cr, 1 /*maxAttempts*/, false /*wait*/); err != nil {
return false, errors.Wrap(err, "failed to find optin extension page")
}
if err := testing.Sleep(ctx, delay); err != nil {
return false, errors.Wrap(err, "failed to sleep")
}
testing.ContextLog(ctx, "Sleep completed")
// If provisioning fails after delay, cleanup chrome instance and attempt again.
arcProvisioned, err := checkArcProvisioned(ctx, tconn)
if err != nil {
return false, errors.Wrap(err, "failed to check if ARC is provisioned")
} else if arcProvisioned {
testing.ContextLogf(ctx, "ARC is already provisioned after %v delay", delay)
if delay == firstRun {
const warnString = "This is first iteration and Chrome restart " +
"was not validated. Consider decreasing initial delay value"
testing.ContextLogf(ctx, "WARNING: %s", warnString)
}
}
testing.ContextLog(ctx, "ARC provisioning is not completed")
return !arcProvisioned, nil
}