/
google_sheets_cuj.go
197 lines (176 loc) · 6.57 KB
/
google_sheets_cuj.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
// Copyright 2022 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 ui
import (
"context"
"time"
"chromiumos/tast/common/perf"
"chromiumos/tast/ctxutil"
"chromiumos/tast/errors"
"chromiumos/tast/local/bundles/cros/ui/cuj"
"chromiumos/tast/local/chrome"
"chromiumos/tast/local/chrome/ash"
"chromiumos/tast/local/chrome/browser"
"chromiumos/tast/local/chrome/display"
"chromiumos/tast/local/chrome/lacros"
"chromiumos/tast/local/chrome/uiauto"
"chromiumos/tast/local/chrome/uiauto/faillog"
"chromiumos/tast/local/chrome/uiauto/nodewith"
"chromiumos/tast/local/chrome/uiauto/role"
"chromiumos/tast/local/input"
"chromiumos/tast/testing"
"chromiumos/tast/testing/hwdep"
)
func init() {
testing.AddTest(&testing.Test{
Func: GoogleSheetsCUJ,
LacrosStatus: testing.LacrosVariantExists,
Desc: "Measures the total performance of critical user journey for Google Sheets",
Contacts: []string{"yichenz@chromium.org", "chromeos-perfmetrics-eng@google.com"},
Attr: []string{"group:crosbolt", "crosbolt_perbuild", "group:cuj"},
SoftwareDeps: []string{"chrome", "arc"},
HardwareDeps: hwdep.D(hwdep.InternalDisplay()),
Timeout: 10 * time.Minute,
Params: []testing.Param{{
Val: browser.TypeAsh,
Fixture: "loggedInToCUJUser",
}, {
Name: "lacros",
Val: browser.TypeLacros,
Fixture: "loggedInToCUJUserLacros",
ExtraSoftwareDeps: []string{"lacros"},
}},
})
}
func GoogleSheetsCUJ(ctx context.Context, s *testing.State) {
const (
timeout = 10 * time.Second
sheetURL = "https://docs.google.com/spreadsheets/d/1I9jmmdWkBaH6Bdltc2j5KVSyrJYNAhwBqMmvTdmVOgM/edit?usp=sharing&resourcekey=0-60wBsoTfOkoQ6t4yx2w7FQ"
scrollTimeout = 7 * time.Minute
)
// Shorten context a bit to allow for cleanup.
closeCtx := ctx
ctx, cancel := ctxutil.Shorten(ctx, 10*time.Second)
defer cancel()
bt := s.Param().(browser.Type)
var cs ash.ConnSource
var cr *chrome.Chrome
if bt == browser.TypeAsh {
cr = s.FixtValue().(chrome.HasChrome).Chrome()
cs = cr
} else {
var err error
var l *lacros.Lacros
cr, l, cs, err = lacros.Setup(ctx, s.FixtValue(), bt)
if err != nil {
s.Fatal("Failed to initialize test: ", err)
}
defer lacros.CloseLacros(closeCtx, l)
}
tconn, err := cr.TestAPIConn(ctx)
if err != nil {
s.Fatal("Failed to connect to test API: ", err)
}
defer faillog.DumpUITreeOnError(closeCtx, s.OutDir(), s.HasError, tconn)
inTabletMode, err := ash.TabletModeEnabled(ctx, tconn)
if err != nil {
s.Fatal("Failed to detect it is in tablet-mode or not: ", err)
}
if inTabletMode {
// If it is in tablet mode, ensure it it in landscape orientation.
orientation, err := display.GetOrientation(ctx, tconn)
if err != nil {
s.Fatal("Failed to get display orientation: ", err)
}
if orientation.Type == display.OrientationPortraitPrimary {
info, err := display.GetPrimaryInfo(ctx, tconn)
if err != nil {
s.Fatal("Failed to get the primary display info: ", err)
}
s.Log("Rotating display 90 degrees")
if err := display.SetDisplayRotationSync(ctx, tconn, info.ID, display.Rotate90); err != nil {
s.Fatal("Failed to rotate display: ", err)
}
defer display.SetDisplayRotationSync(closeCtx, tconn, info.ID, display.Rotate0)
}
}
s.Logf("Is in tablet-mode: %t", inTabletMode)
ui := uiauto.New(tconn)
// TODO(b/222729608): Add scroll metrics.
configs := []cuj.MetricConfig{
cuj.NewCustomMetricConfig("PageLoad.PaintTiming.NavigationToFirstContentfulPaint", "ms",
perf.SmallerIsBetter, []int64{4000, 5000}),
cuj.NewCustomMetricConfig("PageLoad.PaintTiming.NavigationToLargestContentfulPaint2", "ms",
perf.SmallerIsBetter, []int64{4000, 5000})}
recorder, err := cuj.NewRecorder(ctx, cr, nil, cuj.RecorderOptions{}, configs...)
if err != nil {
s.Fatal("Failed to create a CUJ recorder: ", err)
}
defer recorder.Close(closeCtx)
// Create a virtual trackpad.
tpw, err := input.Trackpad(ctx)
if err != nil {
s.Fatal("Failed to create a trackpad device: ", err)
}
defer tpw.Close()
tw, err := tpw.NewMultiTouchWriter(2)
if err != nil {
s.Fatal("Failed to create a multi touch writer: ", err)
}
defer tw.Close()
if err := recorder.Run(ctx, func(ctx context.Context) error {
// Open Google Sheets file.
sheetConn, err := cs.NewConn(ctx, sheetURL, browser.WithNewWindow())
if err != nil {
return errors.Wrap(err, "failed to open the Google Sheets website")
}
defer sheetConn.Close()
defer sheetConn.CloseTarget(closeCtx)
s.Log("Creating a Google Sheets window")
// Pop-up content regarding view history privacy might show up.
privacyButton := nodewith.Name("I understand").Role(role.Button)
if err := uiauto.IfSuccessThen(ui.WaitUntilExists(privacyButton), ui.LeftClick(privacyButton))(ctx); err != nil {
return errors.Wrap(err, "failed to click the spreadsheet privacy button")
}
fingerSpacing := tpw.Width() / 4
end := time.Now().Add(scrollTimeout)
// Swipe and scroll down the spreadsheet.
s.Logf("Scrolling down the Google Sheets file for %d minutes", int(scrollTimeout.Minutes()))
for end.Sub(time.Now()).Seconds() > 0 {
// Double swipe from the middle buttom to the middle top of the touchpad.
var startX, startY, endX, endY input.TouchCoord
startX, startY, endX, endY = tpw.Width()/2, 1, tpw.Width()/2, tpw.Height()-1
fingerNum := 2
if err := tw.Swipe(ctx, startX, startY, endX, endY, fingerSpacing,
fingerNum, 500*time.Millisecond); err != nil {
return errors.Wrap(err, "failed to swipe")
}
}
var scrollTop int
// Ensure scrollbar gets scrolled.
if err := sheetConn.Eval(ctx, "parseInt(document.getElementsByClassName('native-scrollbar-y')[0].scrollTop)", &scrollTop); err != nil {
return errors.Wrap(err, "failed to get the number of pixels that the scrollbar is scrolled vertically")
}
if scrollTop == 0 {
return errors.New("scroll didn't happen")
}
// Navigate away to record PageLoad.PaintTiming.NavigationToLargestContentfulPaint2.
if err := sheetConn.Navigate(ctx, "chrome://version"); err != nil {
return errors.Wrap(err, "failed to navigate to chrome://version")
}
return nil
}); err != nil {
s.Fatal("Failed to run the test scenario: ", err)
}
pv := perf.NewValues()
if err := recorder.Record(ctx, pv); err != nil {
s.Fatal("Failed to record the data: ", err)
}
if err := pv.Save(s.OutDir()); err != nil {
s.Error("Failed to save the perf data: ", err)
}
if err := recorder.SaveHistograms(s.OutDir()); err != nil {
s.Error("Failed to save histogram raw data: ", err)
}
}