blob: 68aa00843af05b2f42d6d7c0879eaddb7e0399a6 [file] [log] [blame] [edit]
// Copyright 2019 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 getusermedia
import (
"context"
"net/http"
"net/http/httptest"
"time"
"chromiumos/tast/common/perf"
"chromiumos/tast/ctxutil"
"chromiumos/tast/errors"
"chromiumos/tast/testing"
)
// RunTest checks if the given WebRTC tests work correctly.
// htmlName is a filename of an HTML file in data directory.
// entryPoint is a JavaScript expression that starts the test there.
func RunTest(ctx context.Context, s *testing.State, cr ChromeInterface,
htmlName, entryPoint string, results, logs interface{}) {
server := httptest.NewServer(http.FileServer(s.DataFileSystem()))
defer server.Close()
conn, err := cr.NewConn(ctx, server.URL+"/"+htmlName)
if err != nil {
s.Fatal("Creating renderer failed: ", err)
}
defer conn.Close()
defer conn.CloseTarget(ctx)
if err := conn.WaitForExpr(ctx, "scriptReady"); err != nil {
s.Fatal("Timed out waiting for scripts ready: ", err)
}
if err := conn.WaitForExpr(ctx, "checkVideoInput()"); err != nil {
var msg string
if err := conn.Eval(ctx, "enumerateDevicesError", &msg); err != nil {
s.Error("Failed to evaluate enumerateDevicesError: ", err)
} else if len(msg) > 0 {
s.Error("enumerateDevices failed: ", msg)
}
s.Fatal("Timed out waiting for video device to be available: ", err)
}
if err := conn.Eval(ctx, entryPoint, nil); err != nil {
s.Fatal("Failed to start test: ", err)
}
rctx, rcancel := ctxutil.Shorten(ctx, 3*time.Second)
defer rcancel()
if err := conn.WaitForExpr(rctx, "isTestDone"); err != nil {
// If test didn't finish within the deadline, display error messages stored in "globalErrors".
var errors []string
if err := conn.Eval(ctx, "globalErrors", &errors); err == nil {
for _, msg := range errors {
s.Error("Got JS error: ", msg)
}
}
s.Fatal("Timed out waiting for test completed: ", err)
}
if err := conn.Eval(ctx, "getResults()", results); err != nil {
s.Fatal("Failed to get results from JS: ", err)
}
if err := conn.Eval(ctx, "getLogs()", logs); err != nil {
s.Fatal("Failed to get logs from JS: ", err)
}
}
func percentage(num, total int) float64 {
if total == 0 {
return 100.0
}
return 100.0 * float64(num) / float64(total)
}
// FrameStats is a struct for statistics of frames.
type FrameStats struct {
TotalFrames int `json:"totalFrames"`
BlackFrames int `json:"blackFrames"`
FrozenFrames int `json:"frozenFrames"`
}
// blackFramesPercentage returns the ratio of black frames to total frames
func (s *FrameStats) blackFramesPercentage() float64 {
return percentage(s.BlackFrames, s.TotalFrames)
}
// frozenFramesPercentage returns the ratio of frozen frames to total frames
func (s *FrameStats) frozenFramesPercentage() float64 {
return percentage(s.FrozenFrames, s.TotalFrames)
}
// CheckTotalFrames checks whether video frames were displayed.
func (s *FrameStats) CheckTotalFrames() error {
if s.TotalFrames == 0 {
return errors.New("no frame was displayed")
}
return nil
}
// CheckBrokenFrames checks that there were less than threshold frozen or black
// frames. This test might be too strict for real cameras, but should work fine
// with the Fake video/audio capture device that should be used for WebRTC
// tests.
func (s *FrameStats) CheckBrokenFrames() error {
const threshold = 1.0
blackPercentage := s.blackFramesPercentage()
frozenPercentage := s.frozenFramesPercentage()
if threshold < blackPercentage+frozenPercentage {
return errors.Errorf("too many broken frames: black %.1f%%, frozen %.1f%% (total %d)",
blackPercentage, frozenPercentage, s.TotalFrames)
}
return nil
}
// SetPerf records performance data in FrameStats to perf.Values.
// p is a pointer for perf.Values where data will be stored.
// suffix is a string that will be used as sufixes of metrics' names.
func (s *FrameStats) SetPerf(p *perf.Values, suffix string) {
blackFrames := perf.Metric{
Name: "tast_black_frames_percentage_" + suffix,
Unit: "percent",
Direction: perf.SmallerIsBetter,
}
frozenFrames := perf.Metric{
Name: "tast_frozen_frames_percentage_" + suffix,
Unit: "percent",
Direction: perf.SmallerIsBetter,
}
p.Set(blackFrames, s.blackFramesPercentage())
p.Set(frozenFrames, s.frozenFramesPercentage())
}