gobot.io/x/gobot/v2@v2.1.0/platforms/jetson/jetson_adaptor_test.go (about)

     1  package jetson
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strings"
     7  	"testing"
     8  
     9  	"runtime"
    10  	"strconv"
    11  	"sync"
    12  
    13  	"gobot.io/x/gobot/v2"
    14  	"gobot.io/x/gobot/v2/drivers/gpio"
    15  	"gobot.io/x/gobot/v2/drivers/i2c"
    16  	"gobot.io/x/gobot/v2/drivers/spi"
    17  	"gobot.io/x/gobot/v2/gobottest"
    18  	"gobot.io/x/gobot/v2/system"
    19  )
    20  
    21  // make sure that this Adaptor fulfills all the required interfaces
    22  var _ gobot.Adaptor = (*Adaptor)(nil)
    23  var _ gobot.DigitalPinnerProvider = (*Adaptor)(nil)
    24  var _ gobot.PWMPinnerProvider = (*Adaptor)(nil)
    25  var _ gpio.DigitalReader = (*Adaptor)(nil)
    26  var _ gpio.DigitalWriter = (*Adaptor)(nil)
    27  var _ i2c.Connector = (*Adaptor)(nil)
    28  var _ spi.Connector = (*Adaptor)(nil)
    29  
    30  func initTestAdaptorWithMockedFilesystem(mockPaths []string) (*Adaptor, *system.MockFilesystem) {
    31  	a := NewAdaptor()
    32  	fs := a.sys.UseMockFilesystem(mockPaths)
    33  	if err := a.Connect(); err != nil {
    34  		panic(err)
    35  	}
    36  	return a, fs
    37  }
    38  
    39  func TestNewAdaptor(t *testing.T) {
    40  	a := NewAdaptor()
    41  
    42  	gobottest.Assert(t, strings.HasPrefix(a.Name(), "JetsonNano"), true)
    43  
    44  	a.SetName("NewName")
    45  	gobottest.Assert(t, a.Name(), "NewName")
    46  }
    47  
    48  func TestFinalize(t *testing.T) {
    49  	mockPaths := []string{
    50  		"/sys/class/gpio/export",
    51  		"/sys/class/gpio/unexport",
    52  		"/dev/i2c-1",
    53  		"/dev/i2c-0",
    54  		"/dev/spidev0.0",
    55  		"/dev/spidev0.1",
    56  	}
    57  	a, _ := initTestAdaptorWithMockedFilesystem(mockPaths)
    58  
    59  	a.DigitalWrite("3", 1)
    60  
    61  	a.GetI2cConnection(0xff, 0)
    62  	gobottest.Assert(t, a.Finalize(), nil)
    63  }
    64  
    65  func TestPWMPinsConnect(t *testing.T) {
    66  	a := NewAdaptor()
    67  	gobottest.Assert(t, a.pwmPins, (map[string]gobot.PWMPinner)(nil))
    68  
    69  	err := a.PwmWrite("33", 1)
    70  	gobottest.Assert(t, err.Error(), "not connected")
    71  
    72  	err = a.Connect()
    73  	gobottest.Assert(t, err, nil)
    74  	gobottest.Refute(t, a.pwmPins, (map[string]gobot.PWMPinner)(nil))
    75  	gobottest.Assert(t, len(a.pwmPins), 0)
    76  }
    77  
    78  func TestPWMPinsReConnect(t *testing.T) {
    79  	// arrange
    80  	mockPaths := []string{
    81  		"/sys/class/pwm/pwmchip0/export",
    82  		"/sys/class/pwm/pwmchip0/unexport",
    83  		"/sys/class/pwm/pwmchip0/pwm2/duty_cycle",
    84  		"/sys/class/pwm/pwmchip0/pwm2/period",
    85  		"/sys/class/pwm/pwmchip0/pwm2/enable",
    86  	}
    87  	a, _ := initTestAdaptorWithMockedFilesystem(mockPaths)
    88  	gobottest.Assert(t, len(a.pwmPins), 0)
    89  	gobottest.Assert(t, a.PwmWrite("33", 1), nil)
    90  	gobottest.Assert(t, len(a.pwmPins), 1)
    91  	gobottest.Assert(t, a.Finalize(), nil)
    92  	// act
    93  	err := a.Connect()
    94  	// assert
    95  	gobottest.Assert(t, err, nil)
    96  	gobottest.Assert(t, len(a.pwmPins), 0)
    97  }
    98  
    99  func TestDigitalIO(t *testing.T) {
   100  	mockPaths := []string{
   101  		"/sys/class/gpio/export",
   102  		"/sys/class/gpio/unexport",
   103  		"/sys/class/gpio/gpio216/value",
   104  		"/sys/class/gpio/gpio216/direction",
   105  		"/sys/class/gpio/gpio14/value",
   106  		"/sys/class/gpio/gpio14/direction",
   107  	}
   108  	a, fs := initTestAdaptorWithMockedFilesystem(mockPaths)
   109  
   110  	err := a.DigitalWrite("7", 1)
   111  	gobottest.Assert(t, err, nil)
   112  	gobottest.Assert(t, fs.Files["/sys/class/gpio/gpio216/value"].Contents, "1")
   113  
   114  	err = a.DigitalWrite("13", 1)
   115  	gobottest.Assert(t, err, nil)
   116  	i, err := a.DigitalRead("13")
   117  	gobottest.Assert(t, err, nil)
   118  	gobottest.Assert(t, i, 1)
   119  
   120  	gobottest.Assert(t, a.DigitalWrite("notexist", 1), errors.New("'notexist' is not a valid id for a digital pin"))
   121  	gobottest.Assert(t, a.Finalize(), nil)
   122  }
   123  
   124  func TestDigitalPinConcurrency(t *testing.T) {
   125  	oldProcs := runtime.GOMAXPROCS(0)
   126  	runtime.GOMAXPROCS(8)
   127  	defer runtime.GOMAXPROCS(oldProcs)
   128  
   129  	for retry := 0; retry < 20; retry++ {
   130  
   131  		a := NewAdaptor()
   132  		var wg sync.WaitGroup
   133  
   134  		for i := 0; i < 20; i++ {
   135  			wg.Add(1)
   136  			pinAsString := strconv.Itoa(i)
   137  			go func(pin string) {
   138  				defer wg.Done()
   139  				a.DigitalPin(pin)
   140  			}(pinAsString)
   141  		}
   142  
   143  		wg.Wait()
   144  	}
   145  }
   146  
   147  func TestSpiDefaultValues(t *testing.T) {
   148  	a := NewAdaptor()
   149  
   150  	gobottest.Assert(t, a.SpiDefaultBusNumber(), 0)
   151  	gobottest.Assert(t, a.SpiDefaultChipNumber(), 0)
   152  	gobottest.Assert(t, a.SpiDefaultMode(), 0)
   153  	gobottest.Assert(t, a.SpiDefaultMaxSpeed(), int64(10000000))
   154  }
   155  
   156  func TestI2cDefaultBus(t *testing.T) {
   157  	a := NewAdaptor()
   158  	gobottest.Assert(t, a.DefaultI2cBus(), 1)
   159  }
   160  
   161  func TestI2cFinalizeWithErrors(t *testing.T) {
   162  	// arrange
   163  	a := NewAdaptor()
   164  	a.sys.UseMockSyscall()
   165  	fs := a.sys.UseMockFilesystem([]string{"/dev/i2c-1"})
   166  	gobottest.Assert(t, a.Connect(), nil)
   167  	con, err := a.GetI2cConnection(0xff, 1)
   168  	gobottest.Assert(t, err, nil)
   169  	_, err = con.Write([]byte{0xbf})
   170  	gobottest.Assert(t, err, nil)
   171  	fs.WithCloseError = true
   172  	// act
   173  	err = a.Finalize()
   174  	// assert
   175  	gobottest.Assert(t, strings.Contains(err.Error(), "close error"), true)
   176  }
   177  
   178  func Test_validateSpiBusNumber(t *testing.T) {
   179  	var tests = map[string]struct {
   180  		busNr   int
   181  		wantErr error
   182  	}{
   183  		"number_negative_error": {
   184  			busNr:   -1,
   185  			wantErr: fmt.Errorf("Bus number -1 out of range"),
   186  		},
   187  		"number_0_ok": {
   188  			busNr: 0,
   189  		},
   190  		"number_1_ok": {
   191  			busNr: 1,
   192  		},
   193  		"number_2_error": {
   194  			busNr:   2,
   195  			wantErr: fmt.Errorf("Bus number 2 out of range"),
   196  		},
   197  	}
   198  	for name, tc := range tests {
   199  		t.Run(name, func(t *testing.T) {
   200  			// arrange
   201  			a := NewAdaptor()
   202  			// act
   203  			err := a.validateSpiBusNumber(tc.busNr)
   204  			// assert
   205  			gobottest.Assert(t, err, tc.wantErr)
   206  		})
   207  	}
   208  }
   209  
   210  func Test_validateI2cBusNumber(t *testing.T) {
   211  	var tests = map[string]struct {
   212  		busNr   int
   213  		wantErr error
   214  	}{
   215  		"number_negative_error": {
   216  			busNr:   -1,
   217  			wantErr: fmt.Errorf("Bus number -1 out of range"),
   218  		},
   219  		"number_0_ok": {
   220  			busNr: 0,
   221  		},
   222  		"number_1_ok": {
   223  			busNr: 1,
   224  		},
   225  		"number_2_not_ok": {
   226  			busNr:   2,
   227  			wantErr: fmt.Errorf("Bus number 2 out of range"),
   228  		},
   229  	}
   230  	for name, tc := range tests {
   231  		t.Run(name, func(t *testing.T) {
   232  			// arrange
   233  			a := NewAdaptor()
   234  			// act
   235  			err := a.validateI2cBusNumber(tc.busNr)
   236  			// assert
   237  			gobottest.Assert(t, err, tc.wantErr)
   238  		})
   239  	}
   240  }