github.com/simpleiot/simpleiot@v0.18.3/client/cobs-wrapper_test.go (about)

     1  package client
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"reflect"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/dim13/cobs"
    11  	"github.com/simpleiot/simpleiot/test"
    12  )
    13  
    14  func TestCobs(t *testing.T) {
    15  	// we expect COBS encoding to work as detailed here:
    16  	// https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing
    17  	testCases := []struct {
    18  		dec, enc []byte
    19  	}{
    20  		{[]byte{0x0}, []byte{0x1, 0x1, 0x0}},
    21  		{[]byte{0x0, 0x0}, []byte{0x1, 0x1, 0x1, 0x0}},
    22  		{[]byte{0x0, 0x11, 0x0}, []byte{0x1, 0x2, 0x11, 0x1, 0x0}},
    23  		{[]byte{0x11, 0x22, 0x00, 0x33}, []byte{0x3, 0x11, 0x22, 0x2, 0x33, 0x00}},
    24  		{[]byte{0x11, 0x22, 0x33, 0x44}, []byte{0x5, 0x11, 0x22, 0x33, 0x44, 0x00}},
    25  		{[]byte{0x11, 0x00, 0x00, 0x00}, []byte{0x2, 0x11, 0x1, 0x1, 0x1, 0x00}},
    26  	}
    27  
    28  	for _, tc := range testCases {
    29  		e := cobs.Encode(tc.dec)
    30  
    31  		fmt.Printf("Encoding %v -> %v\n", test.HexDump(tc.dec), test.HexDump(e))
    32  
    33  		if !bytes.Equal(tc.enc, e) {
    34  			t.Fatalf("enc failed for %v, got: %v, exp: %v",
    35  				test.HexDump(tc.dec), test.HexDump(e), test.HexDump(tc.enc))
    36  		}
    37  
    38  		c, err := cobsDecodeInplace(e)
    39  
    40  		if err != nil {
    41  			t.Fatal("Error decoding: ", err)
    42  		}
    43  
    44  		e = e[:c]
    45  
    46  		if !bytes.Equal(tc.dec, e) {
    47  			t.Fatalf("Decode failed: %v -> %v",
    48  				test.HexDump(tc.dec), test.HexDump(e))
    49  		}
    50  	}
    51  }
    52  
    53  func TestCobsLong(t *testing.T) {
    54  	b := make([]byte, 300)
    55  	for i := range b {
    56  		b[i] = 5
    57  	}
    58  
    59  	e := cobs.Encode(b)
    60  
    61  	c, err := cobsDecodeInplace(e)
    62  	if err != nil {
    63  		t.Fatal("Error decoding: ", err)
    64  	}
    65  
    66  	e = e[:c]
    67  
    68  	if !bytes.Equal(b, e) {
    69  		t.Fatalf("Decode failed: %v", test.HexDump(e))
    70  	}
    71  }
    72  
    73  func TestCobsRead(t *testing.T) {
    74  	d := []byte{1, 2, 3, 0, 4, 5, 6}
    75  
    76  	a, b := test.NewIoSim()
    77  
    78  	cw := NewCobsWrapper(b, 500)
    79  
    80  	_, _ = a.Write(append([]byte{0}, cobs.Encode(d)...))
    81  
    82  	buf := make([]byte, 500)
    83  
    84  	chBuf := make(chan struct{})
    85  
    86  	go func() {
    87  		c, err := cw.Read(buf)
    88  		if err != nil {
    89  			fmt.Println("Error reading cw: ", err)
    90  		}
    91  		buf = buf[0:c]
    92  		chBuf <- struct{}{}
    93  	}()
    94  
    95  	select {
    96  	case <-chBuf:
    97  		// all is well
    98  	case <-time.After(time.Second):
    99  		t.Fatal("Timeout waiting for data")
   100  	}
   101  
   102  	if !reflect.DeepEqual(buf, d) {
   103  		t.Fatal("Read data does not match")
   104  	}
   105  }
   106  
   107  func TestCobsReadNoLeadingNull(t *testing.T) {
   108  	d := []byte{1, 2, 3, 0, 4, 5, 6}
   109  
   110  	a, b := test.NewIoSim()
   111  
   112  	cw := NewCobsWrapper(b, 500)
   113  
   114  	_, _ = a.Write(cobs.Encode(d))
   115  
   116  	buf := make([]byte, 500)
   117  
   118  	chBuf := make(chan struct{})
   119  
   120  	go func() {
   121  		c, err := cw.Read(buf)
   122  		if err != nil {
   123  			fmt.Println("Error reading cw: ", err)
   124  		}
   125  		buf = buf[0:c]
   126  		chBuf <- struct{}{}
   127  	}()
   128  
   129  	select {
   130  	case <-chBuf:
   131  		// all is well
   132  	case <-time.After(time.Second):
   133  		t.Fatal("Timeout waiting for data")
   134  	}
   135  
   136  	if !reflect.DeepEqual(buf, d) {
   137  		t.Fatal("Read data does not match")
   138  	}
   139  }
   140  
   141  func TestCobsWrite(t *testing.T) {
   142  	d := []byte{1, 2, 3, 0, 4, 5, 6}
   143  
   144  	a, b := test.NewIoSim()
   145  
   146  	cw := NewCobsWrapper(b, 500)
   147  
   148  	_, err := cw.Write(d)
   149  	if err != nil {
   150  		t.Fatal("Error write: ", err)
   151  	}
   152  
   153  	buf := make([]byte, 500)
   154  
   155  	chBuf := make(chan struct{})
   156  
   157  	go func() {
   158  		c, err := a.Read(buf)
   159  		if err != nil {
   160  			fmt.Println("Error reading cw: ", err)
   161  		}
   162  		buf = buf[0:c]
   163  		chBuf <- struct{}{}
   164  	}()
   165  
   166  	select {
   167  	case <-chBuf:
   168  		// all is well
   169  	case <-time.After(time.Second):
   170  		t.Fatal("Timeout waiting for data")
   171  	}
   172  
   173  	if buf[0] != 0 {
   174  		t.Fatal("COBS encoded packet must start with 0")
   175  	}
   176  
   177  	if !reflect.DeepEqual(cobs.Decode(buf[1:]), d) {
   178  		t.Fatal("cw.Write, buf is not same")
   179  	}
   180  }
   181  
   182  func TestCobsWrapperPartialPacket(t *testing.T) {
   183  	d := []byte{1, 2, 3, 0, 4, 5, 6}
   184  
   185  	a, b := test.NewIoSim()
   186  
   187  	cw := NewCobsWrapper(b, 500)
   188  
   189  	de := cobs.Encode(d)
   190  
   191  	// write part of packet
   192  	_, _ = a.Write(de[0:4])
   193  
   194  	// start reader
   195  	readData := make(chan []byte)
   196  	errCh := make(chan error)
   197  
   198  	go func() {
   199  		buf := make([]byte, 500)
   200  		c, err := cw.Read(buf)
   201  		if err != nil {
   202  			errCh <- err
   203  		}
   204  		buf = buf[0:c]
   205  		readData <- buf
   206  	}()
   207  
   208  	// should time out as we don't have entire packet to decode yet
   209  	select {
   210  	case <-readData:
   211  		t.Fatal("should not have read data yet")
   212  	case err := <-errCh:
   213  		t.Fatal("Read failed when it should have blocked: ", err)
   214  	case <-time.After(time.Millisecond * 10):
   215  		// all is well
   216  	}
   217  
   218  	// write the rest of the packet
   219  	_, _ = a.Write(de[4:])
   220  
   221  	// now look for packet
   222  	select {
   223  	case ret := <-readData:
   224  		if !reflect.DeepEqual(ret, d) {
   225  			t.Fatal("Read data does not match")
   226  		}
   227  	case err := <-errCh:
   228  		t.Fatal("Read failed: ", err)
   229  	case <-time.After(time.Millisecond * 10):
   230  		t.Fatal("Timeout reading packet")
   231  	}
   232  }
   233  
   234  func TestCobsMultipleLeadingNull(t *testing.T) {
   235  	d := []byte{1, 2, 3, 0, 4, 5, 6}
   236  	a, b := test.NewIoSim()
   237  
   238  	cw := NewCobsWrapper(b, 500)
   239  
   240  	_, _ = a.Write(append([]byte{0, 0, 0, 0}, cobs.Encode(d)...))
   241  
   242  	buf := make([]byte, 500)
   243  
   244  	chBuf := make(chan struct{})
   245  
   246  	go func() {
   247  		c, err := cw.Read(buf)
   248  		if err != nil {
   249  			fmt.Println("Error reading cw: ", err)
   250  		}
   251  		buf = buf[0:c]
   252  		chBuf <- struct{}{}
   253  	}()
   254  
   255  	select {
   256  	case <-chBuf:
   257  		// all is well
   258  	case <-time.After(time.Second):
   259  		t.Fatal("Timeout waiting for data")
   260  	}
   261  
   262  	if !reflect.DeepEqual(buf, d) {
   263  		t.Fatal("Read data does not match")
   264  	}
   265  }
   266  
   267  func TestCobsPartialThenNew(t *testing.T) {
   268  	d := []byte{1, 2, 3, 0, 4, 5, 6}
   269  	a, b := test.NewIoSim()
   270  
   271  	cw := NewCobsWrapper(b, 500)
   272  
   273  	de := append([]byte{0}, cobs.Encode(d)...)
   274  
   275  	// write partial packet
   276  	_, _ = a.Write(de[0:4])
   277  
   278  	// then start new packet
   279  	_, _ = a.Write(de)
   280  
   281  	buf := make([]byte, 500)
   282  	c, err := cw.Read(buf)
   283  	if err == nil {
   284  		dump := buf[:c]
   285  		t.Fatal("should have gotten an error reading partial packet, data: ", test.HexDump(dump))
   286  	}
   287  
   288  	c, err = cw.Read(buf)
   289  	if err != nil {
   290  		t.Fatal("got error reading full packet: ", err)
   291  	}
   292  	buf = buf[0:c]
   293  
   294  	if !reflect.DeepEqual(buf, d) {
   295  		t.Fatalf("Read data does not match, exp: %v, got: %v", test.HexDump(d), test.HexDump(buf))
   296  	}
   297  }
   298  
   299  func TestCobsWriteTwoThenRead(t *testing.T) {
   300  	d := []byte{1, 2, 3, 0, 4, 5, 6}
   301  	a, b := test.NewIoSim()
   302  
   303  	cw := NewCobsWrapper(b, 500)
   304  
   305  	de := cobs.Encode(d)
   306  
   307  	// write two packets
   308  	_, _ = a.Write(append(de, de...))
   309  
   310  	for i := 2; i < 2; i++ {
   311  		buf := make([]byte, 500)
   312  		c, err := cw.Read(buf)
   313  		if err != nil {
   314  			t.Fatal("got error reading full packet: ", i, err)
   315  		}
   316  		buf = buf[0:c]
   317  
   318  		if !reflect.DeepEqual(buf, d) {
   319  			t.Fatal("Read data does not match, iter: ", i)
   320  		}
   321  	}
   322  }