From 730c32b9fdfb12fcef98546446efe73dc5e4fd87 Mon Sep 17 00:00:00 2001 From: Sebastian Zagrodzki Date: Sat, 29 Apr 2017 12:57:55 +0200 Subject: [PATCH] Add tests for endpoint NewStream. Rename OpenWithVidPid to OpenWithVIDPID. --- usb/device_test.go | 6 +- usb/endpoint_stream_test.go | 81 +++++++++++++++++++++ usb/endpoint_test.go | 4 +- usb/fakelibusb_devices.go | 141 ++++++++++++++++++++++++++++++++++++ usb/fakelibusb_test.go | 129 +-------------------------------- usb/transfer_stream.go | 3 + usb/transfer_stream_test.go | 2 +- usb/usb.go | 4 +- usb/usb_test.go | 10 +-- 9 files changed, 239 insertions(+), 141 deletions(-) create mode 100644 usb/endpoint_stream_test.go create mode 100644 usb/fakelibusb_devices.go diff --git a/usb/device_test.go b/usb/device_test.go index 478d551..2d8e390 100644 --- a/usb/device_test.go +++ b/usb/device_test.go @@ -34,13 +34,13 @@ func TestClaimAndRelease(t *testing.T) { ) c := NewContext() defer c.Close() - dev, err := c.OpenDeviceWithVidPid(0x8888, 0x0002) + dev, err := c.OpenDeviceWithVIDPID(0x8888, 0x0002) if dev == nil { - t.Fatal("OpenDeviceWithVidPid(0x8888, 0x0002): got nil device, need non-nil") + t.Fatal("OpenDeviceWithVIDPID(0x8888, 0x0002): got nil device, need non-nil") } defer dev.Close() if err != nil { - t.Fatalf("OpenDeviceWithVidPid(0x8888, 0x0002): %v", err) + t.Fatalf("OpenDeviceWithVIDPID(0x8888, 0x0002): %v", err) } cfg, err := dev.Config(cfgNum) if err != nil { diff --git a/usb/endpoint_stream_test.go b/usb/endpoint_stream_test.go new file mode 100644 index 0000000..ba9aee1 --- /dev/null +++ b/usb/endpoint_stream_test.go @@ -0,0 +1,81 @@ +// Copyright 2017 the gousb Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package usb + +import "testing" + +func TestEndpointReadStream(t *testing.T) { + lib, done := newFakeLibusb() + defer done() + + goodTransfers := 7 + go func() { + var num int + for { + xfr := lib.waitForSubmitted() + if xfr == nil { + return + } + if num < goodTransfers { + xfr.status = TransferCompleted + xfr.length = len(xfr.buf) + } else { + xfr.status = TransferError + xfr.length = 0 + } + xfr.done <- struct{}{} + num++ + } + }() + + ctx := NewContext() + dev, err := ctx.OpenDeviceWithVIDPID(0x9999, 0x0001) + if err != nil { + t.Fatalf("OpenDeviceWithVIDPID(9999, 0001): %v", err) + } + defer dev.Close() + cfg, err := dev.Config(1) + if err != nil { + t.Fatalf("%s.Config(1): %v", dev, err) + } + defer cfg.Close() + intf, err := cfg.Interface(0, 0) + if err != nil { + t.Fatalf("%s.Interface(0, 0): %v", cfg, err) + } + defer intf.Close() + ep, err := intf.InEndpoint(2) + if err != nil { + t.Fatalf("%s.Endpoint(2): %v", intf, err) + } + stream, err := ep.NewStream(1024, 5) + if err != nil { + t.Fatalf("%s.NewStream(1024, 5): %v", ep, err) + } + defer stream.Close() + var got int + want := goodTransfers * 1024 + buf := make([]byte, 1024) + for got <= want { + num, err := stream.Read(buf) + if err != nil { + break + } + got += num + } + if got != want { + t.Errorf("%s.Read(): read %d bytes, want %d") + } +} diff --git a/usb/endpoint_test.go b/usb/endpoint_test.go index 10b4292..8b42244 100644 --- a/usb/endpoint_test.go +++ b/usb/endpoint_test.go @@ -163,9 +163,9 @@ func TestEndpointInOut(t *testing.T) { ctx := NewContext() defer ctx.Close() - d, err := ctx.OpenDeviceWithVidPid(0x9999, 0x0001) + d, err := ctx.OpenDeviceWithVIDPID(0x9999, 0x0001) if err != nil { - t.Fatalf("OpenDeviceWithVidPid(0x9999, 0x0001): got error %v, want nil", err) + t.Fatalf("OpenDeviceWithVIDPID(0x9999, 0x0001): got error %v, want nil", err) } defer func() { if err := d.Close(); err != nil { diff --git a/usb/fakelibusb_devices.go b/usb/fakelibusb_devices.go new file mode 100644 index 0000000..c09bb2b --- /dev/null +++ b/usb/fakelibusb_devices.go @@ -0,0 +1,141 @@ +// Copyright 2017 the gousb Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package usb + +// fake devices connected through the fakeLibusb stack. +var fakeDevices = []*Descriptor{ + // Bus 001 Device 001: ID 9999:0001 + // One config, one interface, one setup, + // two endpoints: 0x01 OUT, 0x82 IN. + &Descriptor{ + Bus: 1, + Address: 1, + Spec: Version(2, 0), + Device: Version(1, 0), + Vendor: ID(0x9999), + Product: ID(0x0001), + Protocol: 255, + Configs: map[int]ConfigInfo{1: { + Config: 1, + MaxPower: Milliamperes(100), + Interfaces: []InterfaceInfo{{ + Number: 0, + AltSettings: []InterfaceSetting{{ + Number: 0, + Alternate: 0, + Class: ClassVendorSpec, + Endpoints: map[int]EndpointInfo{ + 1: { + Number: 1, + Direction: EndpointDirectionOut, + MaxPacketSize: 512, + TransferType: TransferTypeBulk, + }, + 2: { + Number: 2, + Direction: EndpointDirectionIn, + MaxPacketSize: 512, + TransferType: TransferTypeBulk, + }, + }, + }}, + }}, + }}, + }, + // Bus 001 Device 002: ID 8888:0002 + // One config, two interfaces. interface #0 with no endpoints, + // interface #1 with two alt setups with different packet sizes for + // endpoints. Two isochronous endpoints, 0x05 OUT and 0x86 OUT. + &Descriptor{ + Bus: 1, + Address: 2, + Spec: Version(2, 0), + Device: Version(1, 3), + Vendor: ID(0x8888), + Product: ID(0x0002), + Protocol: 255, + Configs: map[int]ConfigInfo{1: { + Config: 1, + MaxPower: Milliamperes(100), + Interfaces: []InterfaceInfo{{ + Number: 0, + AltSettings: []InterfaceSetting{{ + Number: 0, + Alternate: 0, + Class: ClassVendorSpec, + }}, + }, { + Number: 1, + AltSettings: []InterfaceSetting{{ + Number: 1, + Alternate: 0, + Class: ClassVendorSpec, + Endpoints: map[int]EndpointInfo{ + 5: { + Number: 5, + Direction: EndpointDirectionOut, + MaxPacketSize: 3 * 1024, + TransferType: TransferTypeIsochronous, + UsageType: IsoUsageTypeData, + }, + 6: { + Number: 6, + Direction: EndpointDirectionIn, + MaxPacketSize: 3 * 1024, + TransferType: TransferTypeIsochronous, + UsageType: IsoUsageTypeData, + }, + }, + }, { + Number: 1, + Alternate: 1, + Class: ClassVendorSpec, + Endpoints: map[int]EndpointInfo{ + 5: { + Number: 5, + Direction: EndpointDirectionOut, + MaxPacketSize: 2 * 1024, + TransferType: TransferTypeIsochronous, + }, + 6: { + Number: 6, + Direction: EndpointDirectionIn, + MaxPacketSize: 2 * 1024, + TransferType: TransferTypeIsochronous, + }, + }, + }, { + Number: 1, + Alternate: 2, + Class: ClassVendorSpec, + Endpoints: map[int]EndpointInfo{ + 5: { + Number: 5, + Direction: EndpointDirectionIn, + MaxPacketSize: 1024, + TransferType: TransferTypeIsochronous, + }, + 6: { + Number: 6, + Direction: EndpointDirectionIn, + MaxPacketSize: 1024, + TransferType: TransferTypeIsochronous, + }, + }, + }}, + }}, + }}, + }, +} diff --git a/usb/fakelibusb_test.go b/usb/fakelibusb_test.go index 25ecac7..7d7d1bb 100644 --- a/usb/fakelibusb_test.go +++ b/usb/fakelibusb_test.go @@ -21,134 +21,6 @@ import ( "time" ) -var ( - // fake devices connected through the fakeLibusb stack. - fakeDevices = []*Descriptor{ - // Bus 001 Device 001: ID 9999:0001 - // One config, one interface, one setup, - // two endpoints: 0x01 OUT, 0x82 IN. - &Descriptor{ - Bus: 1, - Address: 1, - Spec: Version(2, 0), - Device: Version(1, 0), - Vendor: ID(0x9999), - Product: ID(0x0001), - Protocol: 255, - Configs: map[int]ConfigInfo{1: { - Config: 1, - MaxPower: Milliamperes(100), - Interfaces: []InterfaceInfo{{ - Number: 0, - AltSettings: []InterfaceSetting{{ - Number: 0, - Alternate: 0, - Class: ClassVendorSpec, - Endpoints: map[int]EndpointInfo{ - 1: { - Number: 1, - Direction: EndpointDirectionOut, - MaxPacketSize: 512, - TransferType: TransferTypeBulk, - }, - 2: { - Number: 2, - Direction: EndpointDirectionIn, - MaxPacketSize: 512, - TransferType: TransferTypeBulk, - }, - }, - }}, - }}, - }}, - }, - // Bus 001 Device 002: ID 8888:0002 - // One config, two interfaces. interface #0 with no endpoints, - // interface #1 with two alt setups with different packet sizes for - // endpoints. Two isochronous endpoints, 0x05 OUT and 0x86 OUT. - &Descriptor{ - Bus: 1, - Address: 2, - Spec: Version(2, 0), - Device: Version(1, 3), - Vendor: ID(0x8888), - Product: ID(0x0002), - Protocol: 255, - Configs: map[int]ConfigInfo{1: { - Config: 1, - MaxPower: Milliamperes(100), - Interfaces: []InterfaceInfo{{ - Number: 0, - AltSettings: []InterfaceSetting{{ - Number: 0, - Alternate: 0, - Class: ClassVendorSpec, - }}, - }, { - Number: 1, - AltSettings: []InterfaceSetting{{ - Number: 1, - Alternate: 0, - Class: ClassVendorSpec, - Endpoints: map[int]EndpointInfo{ - 5: { - Number: 5, - Direction: EndpointDirectionOut, - MaxPacketSize: 3 * 1024, - TransferType: TransferTypeIsochronous, - UsageType: IsoUsageTypeData, - }, - 6: { - Number: 6, - Direction: EndpointDirectionIn, - MaxPacketSize: 3 * 1024, - TransferType: TransferTypeIsochronous, - UsageType: IsoUsageTypeData, - }, - }, - }, { - Number: 1, - Alternate: 1, - Class: ClassVendorSpec, - Endpoints: map[int]EndpointInfo{ - 5: { - Number: 5, - Direction: EndpointDirectionOut, - MaxPacketSize: 2 * 1024, - TransferType: TransferTypeIsochronous, - }, - 6: { - Number: 6, - Direction: EndpointDirectionIn, - MaxPacketSize: 2 * 1024, - TransferType: TransferTypeIsochronous, - }, - }, - }, { - Number: 1, - Alternate: 2, - Class: ClassVendorSpec, - Endpoints: map[int]EndpointInfo{ - 5: { - Number: 5, - Direction: EndpointDirectionIn, - MaxPacketSize: 1024, - TransferType: TransferTypeIsochronous, - }, - 6: { - Number: 6, - Direction: EndpointDirectionIn, - MaxPacketSize: 1024, - TransferType: TransferTypeIsochronous, - }, - }, - }}, - }}, - }}, - }, - } -) - type fakeDevice struct { desc *Descriptor alt uint8 @@ -335,6 +207,7 @@ func newFakeLibusb() (*fakeLibusb, func() error) { libusb = fl return fl, func() error { defer func() { libusb = origLibusb }() + close(fl.submitted) if got := len(fl.ts); got > 0 { for t := range fl.ts { fl.free(t) diff --git a/usb/transfer_stream.go b/usb/transfer_stream.go index 2cb8f64..3db686a 100644 --- a/usb/transfer_stream.go +++ b/usb/transfer_stream.go @@ -120,6 +120,9 @@ func (r ReadStream) Read(p []byte) (int, error) { // was encountered earlier. // Close cannot be called concurrently with Read. func (r ReadStream) Close() error { + if r.s.transfers == nil { + return nil + } r.s.setDelayedErr(io.EOF) return nil } diff --git a/usb/transfer_stream_test.go b/usb/transfer_stream_test.go index cabad9f..b98647d 100644 --- a/usb/transfer_stream_test.go +++ b/usb/transfer_stream_test.go @@ -105,7 +105,7 @@ func (r readRes) String() string { return buf.String() } -func TestReadStream(t *testing.T) { +func TestTransferReadStream(t *testing.T) { for tcNum, tc := range []struct { desc string closeBefore int diff --git a/usb/usb.go b/usb/usb.go index d33f258..da3f477 100644 --- a/usb/usb.go +++ b/usb/usb.go @@ -76,13 +76,13 @@ func (c *Context) ListDevices(each func(desc *Descriptor) bool) ([]*Device, erro return ret, reterr } -// OpenDeviceWithVidPid opens Device from specific VendorId and ProductId. +// OpenDeviceWithVIDPID opens Device from specific VendorId and ProductId. // If none is found, it returns nil and nil error. If there are multiple devices // with the same VID/PID, it will return one of them, picked arbitrarily. // If there were any errors during device list traversal, it is possible // it will return a non-nil device and non-nil error. A Device.Close() must // be called to release the device if the returned device wasn't nil. -func (c *Context) OpenDeviceWithVidPid(vid, pid ID) (*Device, error) { +func (c *Context) OpenDeviceWithVIDPID(vid, pid ID) (*Device, error) { var found bool devs, err := c.ListDevices(func(desc *Descriptor) bool { if found { diff --git a/usb/usb_test.go b/usb/usb_test.go index fb9943f..9631679 100644 --- a/usb/usb_test.go +++ b/usb/usb_test.go @@ -53,7 +53,7 @@ func TestListDevices(t *testing.T) { } } -func TestOpenDeviceWithVidPid(t *testing.T) { +func TestOpenDeviceWithVIDPID(t *testing.T) { _, done := newFakeLibusb() defer done() @@ -69,16 +69,16 @@ func TestOpenDeviceWithVidPid(t *testing.T) { } { c := NewContext() defer c.Close() - dev, err := c.OpenDeviceWithVidPid(d.vid, d.pid) + dev, err := c.OpenDeviceWithVIDPID(d.vid, d.pid) if (dev != nil) != d.exists { - t.Errorf("OpenDeviceWithVidPid(%s/%s): device != nil is %v, want %v", ID(d.vid), ID(d.pid), dev != nil, d.exists) + t.Errorf("OpenDeviceWithVIDPID(%s/%s): device != nil is %v, want %v", ID(d.vid), ID(d.pid), dev != nil, d.exists) } if err != nil { - t.Errorf("OpenDeviceWithVidPid(%s/%s): got error %v, want nil", ID(d.vid), ID(d.pid), err) + t.Errorf("OpenDeviceWithVIDPID(%s/%s): got error %v, want nil", ID(d.vid), ID(d.pid), err) } if dev != nil { if dev.Descriptor.Vendor != ID(d.vid) || dev.Descriptor.Product != ID(d.pid) { - t.Errorf("OpenDeviceWithVidPid(%s/%s): the device returned has VID/PID %s/%s, different from specified in the arguments", ID(d.vid), ID(d.pid), dev.Descriptor.Vendor, dev.Descriptor.Product) + t.Errorf("OpenDeviceWithVIDPID(%s/%s): the device returned has VID/PID %s/%s, different from specified in the arguments", ID(d.vid), ID(d.pid), dev.Descriptor.Vendor, dev.Descriptor.Product) } dev.Close() }