blob: fcdaf84ba0744c49cd3789cd7d48d6f11c4ec524 [file] [log] [blame]
// Copyright 2021 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 scanner
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"time"
lpb "chromiumos/system_api/lorgnette_proto"
"chromiumos/tast/ctxutil"
"chromiumos/tast/local/bundles/cros/scanner/lorgnette"
"chromiumos/tast/local/chrome"
"chromiumos/tast/local/printing/cups"
"chromiumos/tast/local/printing/usbprinter"
"chromiumos/tast/testing"
)
func init() {
testing.AddTest(&testing.Test{
Func: ADFJustification,
Desc: "Tests that scanners with specified ADF justification values have correct scan regions",
Contacts: []string{"kmoed@google.com", "project-bolton@google.com"},
Attr: []string{
"group:mainline",
"informational",
"group:paper-io",
"paper-io_scanning",
},
SoftwareDeps: []string{"virtual_usb_printer", "cups", "chrome"},
Pre: chrome.LoggedIn(),
})
}
const (
descriptors = "/usr/local/etc/virtual-usb-printer/ippusb_printer.json"
attributes = "/usr/local/etc/virtual-usb-printer/ipp_attributes.json"
)
type scannerParams struct {
name string
justification string
esclCapabilities string
expectedXOffset int
}
type scanSettingsJSON struct {
ColorMode int `json:"ColorMode"`
DocumentFormat string `json:"DocumentFormat"`
InputSource string `json:"InputSource"`
Regions []scanRegionsJSON `json:"Regions"`
XResolution int `json:"XResolution"`
YResolution int `json:"YResolution"`
}
type scanRegionsJSON struct {
Height int `json:"Height"`
Units string `json:"Units"`
Width int `json:"Width"`
XOffset int `json:"XOffset"`
YOffset int `json:"YOffset"`
}
func ADFJustification(ctx context.Context, s *testing.State) {
// Use cleanupCtx for any deferred cleanups in case of timeouts or
// cancellations on the shortened context.
cleanupCtx := ctx
ctx, cancel := ctxutil.Shorten(ctx, 5*time.Second)
defer cancel()
// Set up the virtual USB printer.
if err := usbprinter.InstallModules(ctx); err != nil {
s.Fatal("Failed to install kernel modules: ", err)
}
defer func(ctx context.Context) {
if err := usbprinter.RemoveModules(ctx); err != nil {
s.Error("Failed to remove kernel modules: ", err)
}
}(cleanupCtx)
for _, params := range []scannerParams{{
name: "Left-Justified ADF Scanner",
justification: "Left",
esclCapabilities: "/usr/local/etc/virtual-usb-printer/escl_capabilities_left_justified.json",
// Left Justification is the standard, offset should be 0
expectedXOffset: 0,
}, {
name: "Center-Justified ADF Scanner",
justification: "Center",
esclCapabilities: "/usr/local/etc/virtual-usb-printer/escl_capabilities_center_justified.json",
// Center Justification XOffset Calculations
// Unit conversion:
// Width = 100 (requested width in mm) * 300 (dpi) / 25.4 (conversion mm to 3/100ths in)
// MaxWidth = 2550 (hardcoded in xml_util.cc)
// Adjustment Math:
// XOffset = (MaxWidth - Width) / 2
expectedXOffset: 673,
}, {
name: "Right-Justified ADF Scanner",
justification: "Right",
esclCapabilities: "/usr/local/etc/virtual-usb-printer/escl_capabilities_right_justified.json",
// Right Justification XOffset Calculations
// Unit conversion:
// Width = 100 (requested width in mm) * 300 (dpi) / 25.4 (conversion mm to 3/100ths in)
// MaxWidth = 2550 (hardcoded in xml_util.cc)
// Adjustment Math:
// XOffset = MaxWidth - Width
expectedXOffset: 1358,
}} {
runJustificationTest(ctx, s, params)
}
}
// runJustificationTest sets up the virtual usb printer and scan request according to specified params,
// performs a scan, and compares the XOffset of the scan versus the expected calculated value.
func runJustificationTest(ctx context.Context, s *testing.State, params scannerParams) {
s.Log("Performing scan on ", params.name)
devInfo, err := usbprinter.LoadPrinterIDs(descriptors)
if err != nil {
s.Fatalf("Failed to load printer IDs from %v: %v", descriptors, err)
}
if err := cups.RestartPrintingSystem(ctx, devInfo); err != nil {
s.Fatal("Failed to restart printing system: ", err)
}
tmpDir, err := ioutil.TempDir("", "tast.scanner.ADFJustification.")
if err != nil {
s.Fatal("Failed to create temporary directory: ", err)
}
defer os.RemoveAll(tmpDir)
printer, err := usbprinter.StartScanner(ctx, devInfo, descriptors, attributes, params.esclCapabilities, "", tmpDir)
if err != nil {
s.Fatal("Failed to attach virtual printer: ", err)
}
defer usbprinter.StopPrinter(ctx, printer, devInfo)
if err := cups.EnsurePrinterIdle(ctx, devInfo); err != nil {
s.Fatal("Failed to wait for CUPS configuration: ", err)
}
// Requesting total width is 100 mm
region := &lpb.ScanRegion{
TopLeftX: 0,
TopLeftY: 0,
BottomRightX: 100,
BottomRightY: 100,
}
deviceName := fmt.Sprintf("ippusb:escl:TestScanner:%s_%s/eSCL", devInfo.VID, devInfo.PID)
startScanRequest := &lpb.StartScanRequest{
DeviceName: deviceName,
Settings: &lpb.ScanSettings{
Resolution: 300,
SourceName: "ADF",
ColorMode: lpb.ColorMode_MODE_COLOR,
ScanRegion: region,
},
}
s.Log("Performing scan")
if _, err := lorgnette.RunScan(ctx, startScanRequest, tmpDir); err != nil {
s.Fatal("Failed to run scan: ", err)
}
s.Log("Reading in scan settings log file")
logFile, err := os.Open(tmpDir + "/01_createscanjob.json")
if err != nil {
s.Fatal("Failed to open scan settings log file: ", err)
}
defer logFile.Close()
var loggedSettings scanSettingsJSON
if err := json.NewDecoder(logFile).Decode(&loggedSettings); err != nil {
s.Fatal("Failed to decode log file: ", err)
}
var loggedRegion scanRegionsJSON
if len(loggedSettings.Regions) > 0 {
loggedRegion = loggedSettings.Regions[len(loggedSettings.Regions)-1]
}
s.Log("Comparing logged scan region to expected scan region")
// Lorgnette passes justification as uint32_t, so flooring required to match
if params.expectedXOffset != loggedRegion.XOffset {
s.Fatalf("Unexpected offset: got %d, wanted %d", loggedRegion.XOffset, params.expectedXOffset)
}
}