mesh/merge-gate head d5f9cd465c96 merged into trunk d62c2edc35f3 — pass: builds brother → shanks; no bus step; every machine composes with the change as it…
mesh/repo-check head d5f9cd465c96 merged into trunk d62c2edc35f3 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery delivered
The Brother ignores the whole body when it holds a line break, so every setting was ignored and the glass was scanned at its default.
217 lines
7.5 KiB
Go
217 lines
7.5 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// 1440/AC1: the captured capabilities, job creation, document and status replies, served by a test server.
|
|
func TestScanPostsOnePlatenJobOverTheWholeGlassAndAsksNextDocumentAgainToCloseIt(t *testing.T) {
|
|
f := newFakeScanner(t, fixture(t, "scan.jpg"))
|
|
image, err := NewClient(f.base()).Scan(context.Background(), 300, "color")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if f.posts != 1 {
|
|
t.Fatalf("%d ScanJobs posts, want 1", f.posts)
|
|
}
|
|
// The scanner ignores the whole body when it holds a line break (issue 1452), so the settings must have taken
|
|
// effect: the Platen, 300 dpi, A4 cut to the glass (2480 x 3507).
|
|
if f.job != (scannerJob{Source: "Platen", Resolution: 300, Region: "2480x3507"}) {
|
|
t.Fatalf("the scanner took %+v from the body %q", f.job, f.postBody)
|
|
}
|
|
// The page, then the second request that the scanner answers 404, which closes the job.
|
|
if f.documents != 2 || f.open || f.deletes != 0 {
|
|
t.Fatalf("%d NextDocument requests, job open %v, %d DELETEs, want 2, closed, 0", f.documents, f.open, f.deletes)
|
|
}
|
|
if want := fixture(t, "scan.jpg"); string(image) != string(want) {
|
|
t.Fatalf("the returned image is %d bytes, want the scanner's %d", len(image), len(want))
|
|
}
|
|
}
|
|
|
|
// 1440/AC1: the colour mode and resolution asked are the configured ones.
|
|
func TestScanAsksForTheConfiguredResolutionAndColourMode(t *testing.T) {
|
|
f := newFakeScanner(t, fixture(t, "scan.jpg"))
|
|
if _, err := NewClient(f.base()).Scan(context.Background(), 600, "gray"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, want := range []string{"<scan:ColorMode>Grayscale8</scan:ColorMode>", "<scan:XResolution>600</scan:XResolution>", "<scan:YResolution>600</scan:YResolution>"} {
|
|
if !strings.Contains(f.postBody, want) {
|
|
t.Errorf("the job lacks %s:\n%s", want, f.postBody)
|
|
}
|
|
}
|
|
}
|
|
|
|
// 1440/AC1: a job the scanner refuses is an error that says so, and no page is fetched.
|
|
func TestScanSaysWhyAScannerRefusal(t *testing.T) {
|
|
f := newFakeScanner(t, fixture(t, "scan.jpg"))
|
|
f.refuse = 503
|
|
_, err := NewClient(f.base()).Scan(context.Background(), 300, "color")
|
|
if err == nil || !strings.Contains(err.Error(), "503") {
|
|
t.Fatalf("error = %v, want the refusal's 503", err)
|
|
}
|
|
if f.documents != 0 {
|
|
t.Fatalf("%d documents fetched after a refusal", f.documents)
|
|
}
|
|
}
|
|
|
|
// 1440/AC2: the image's own density, never the request's.
|
|
func TestDensityIsTheImagesOwn(t *testing.T) {
|
|
dpi, err := Density(fixture(t, "scan.jpg"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if dpi != 200 {
|
|
t.Fatalf("density = %d dpi, want the captured scan's 200 (the request said 300)", dpi)
|
|
}
|
|
}
|
|
|
|
func TestDensityOfAnImageWithNoneIsAnError(t *testing.T) {
|
|
if _, err := Density([]byte{0xFF, 0xD8, 0xFF, 0xDA, 0, 2}); err == nil {
|
|
t.Fatal("an image with no JFIF header has a resolution")
|
|
}
|
|
}
|
|
|
|
// 1440/AC8: the captured status replies.
|
|
func TestStatusReadsStateAndAdfState(t *testing.T) {
|
|
f := newFakeScanner(t, nil)
|
|
s, err := NewClient(f.base()).Status(context.Background())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if s.State != "Idle" || s.AdfState != "ScannerAdfEmpty" {
|
|
t.Fatalf("status = %+v, want Idle / ScannerAdfEmpty", s)
|
|
}
|
|
}
|
|
|
|
// 1440/AC7: which value is unset is said by name.
|
|
func TestMissingNamesWhatIsUnset(t *testing.T) {
|
|
for _, c := range []struct {
|
|
s Settings
|
|
want string
|
|
}{
|
|
{Settings{Folder: "/x"}, "scanner"},
|
|
{Settings{Scanner: "http://192.0.2.10/eSCL"}, "scan-folder"},
|
|
} {
|
|
err := c.s.Missing()
|
|
if err == nil || !strings.Contains(err.Error(), c.want) {
|
|
t.Errorf("Missing(%+v) = %v, want it to name %s", c.s, err, c.want)
|
|
}
|
|
}
|
|
if err := (Settings{Scanner: "a", Folder: "/x"}).Missing(); err != nil {
|
|
t.Errorf("both set: %v", err)
|
|
}
|
|
}
|
|
|
|
// 1531: two scans in a row both succeed, for the scanner answers 503 to a new job while one is open.
|
|
func TestTwoScansInARowBothSucceed(t *testing.T) {
|
|
f := newFakeScanner(t, fixture(t, "scan.jpg"))
|
|
c := NewClient(f.base())
|
|
for i := 1; i <= 2; i++ {
|
|
if _, err := c.Scan(context.Background(), 300, "color"); err != nil {
|
|
t.Fatalf("scan %d: %v", i, err)
|
|
}
|
|
}
|
|
if f.posts != 2 || f.open {
|
|
t.Fatalf("%d posts, job open %v, want 2, closed", f.posts, f.open)
|
|
}
|
|
}
|
|
|
|
// 1531: a page that cannot be had (the answer is lost) leaves no job open: the job is DELETEd.
|
|
func TestAJobWhoseNextDocumentFailsIsDeleted(t *testing.T) {
|
|
f := newFakeScanner(t, fixture(t, "scan.jpg"))
|
|
f.dropConn = true
|
|
if _, err := NewClient(f.base()).Scan(context.Background(), 300, "color"); err == nil {
|
|
t.Fatal("a lost answer is a scan")
|
|
}
|
|
if f.deletes != 1 || f.open {
|
|
t.Fatalf("%d DELETEs, job open %v, want 1, closed", f.deletes, f.open)
|
|
}
|
|
f.mu.Lock()
|
|
f.dropConn = false
|
|
f.mu.Unlock()
|
|
if _, err := NewClient(f.base()).Scan(context.Background(), 300, "color"); err != nil {
|
|
t.Fatalf("the scan after it: %v", err)
|
|
}
|
|
}
|
|
|
|
// 1531: a job with no page (404) is deleted too.
|
|
func TestAJobThatGivesNoPageIsDeleted(t *testing.T) {
|
|
f := newFakeScanner(t, fixture(t, "scan.jpg"))
|
|
f.noPage = true
|
|
if _, err := NewClient(f.base()).Scan(context.Background(), 300, "color"); err == nil {
|
|
t.Fatal("no page is a scan")
|
|
}
|
|
if f.open {
|
|
t.Fatal("the job stays open")
|
|
}
|
|
}
|
|
|
|
// 1531: a 410 on NextDocument is said as a dropped job, and the job is deleted.
|
|
func TestAGoneJobIsSaidAsDroppedAndDeleted(t *testing.T) {
|
|
f := newFakeScanner(t, fixture(t, "scan.jpg"))
|
|
f.gone = true
|
|
_, err := NewClient(f.base()).Scan(context.Background(), 300, "color")
|
|
if err == nil || !strings.Contains(err.Error(), "the scanner dropped the job") {
|
|
t.Fatalf("error = %v, want the scanner dropped the job", err)
|
|
}
|
|
if f.deletes != 1 {
|
|
t.Fatalf("%d DELETEs, want 1", f.deletes)
|
|
}
|
|
}
|
|
|
|
// 1531: a 503 while another job is open is said as busy, with no loop and no retry when brother left no job.
|
|
func TestABusyScannerIsSaidAndNotRetriedWhenBrotherLeftNoJob(t *testing.T) {
|
|
f := newFakeScanner(t, fixture(t, "scan.jpg"))
|
|
f.open = true // another client's job
|
|
c := NewClient(f.base())
|
|
c.RetryWait = time.Millisecond
|
|
_, err := c.Scan(context.Background(), 300, "color")
|
|
if err == nil || !strings.Contains(err.Error(), "the scanner is busy with another job") {
|
|
t.Fatalf("error = %v, want busy", err)
|
|
}
|
|
if f.posts != 1 {
|
|
t.Fatalf("%d posts, want 1", f.posts)
|
|
}
|
|
}
|
|
|
|
// 1531: a job brother left open (it could not close it) is closed after a wait, and the refused POST goes once more.
|
|
func TestABusyScannerWithABrotherJobLeftIsRetriedOnceAfterItCloses(t *testing.T) {
|
|
f := newFakeScanner(t, fixture(t, "scan.jpg"))
|
|
f.stuck = true
|
|
c := NewClient(f.base())
|
|
c.RetryWait = time.Millisecond
|
|
if _, err := c.Scan(context.Background(), 300, "color"); err == nil {
|
|
t.Fatal("a stuck job is a scan")
|
|
}
|
|
f.mu.Lock()
|
|
if !f.open {
|
|
t.Fatal("the fake should have kept the job open")
|
|
}
|
|
f.stuck = false
|
|
f.mu.Unlock()
|
|
c2 := NewClient(f.base())
|
|
c2.RetryWait = time.Millisecond
|
|
if _, err := c2.Scan(context.Background(), 300, "color"); err != nil {
|
|
t.Fatalf("scan after the left job closes: %v", err)
|
|
}
|
|
if f.posts != 3 {
|
|
t.Fatalf("%d posts, want 3 (stuck job, refused, retried)", f.posts)
|
|
}
|
|
}
|
|
|
|
// 1531: a second page for a Platen job is an error, never a silently incomplete scan, and the job is closed.
|
|
func TestMorePagesThanTheGlassHoldsIsAnErrorAndTheJobIsClosed(t *testing.T) {
|
|
f := newFakeScanner(t, fixture(t, "scan.jpg"))
|
|
f.pages = 2
|
|
image, err := NewClient(f.base()).Scan(context.Background(), 300, "color")
|
|
if err == nil || !strings.Contains(err.Error(), "the scanner gave more pages than the glass holds") {
|
|
t.Fatalf("image %d bytes, error = %v, want more pages than the glass holds", len(image), err)
|
|
}
|
|
if f.open || f.deletes != 1 {
|
|
t.Fatalf("job open %v, %d DELETEs, want closed by 1 DELETE", f.open, f.deletes)
|
|
}
|
|
}
|