go-hep.org/x/hep@v0.38.1/xrootd/xrdproto/xrdproto_test.go (about)

     1  // Copyright ©2018 The go-hep Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package xrdproto // import "go-hep.org/x/hep/xrootd/xrdproto"
     6  
     7  import (
     8  	"bytes"
     9  	"crypto/rand"
    10  	"encoding/binary"
    11  	"fmt"
    12  	"io"
    13  	"reflect"
    14  	"testing"
    15  	"time"
    16  
    17  	"go-hep.org/x/hep/xrootd/internal/xrdenc"
    18  )
    19  
    20  func TestReadRequest(t *testing.T) {
    21  	header := make([]byte, RequestHeaderLength+16+4)
    22  	data := make([]byte, 10)
    23  	_, _ = rand.Read(data)
    24  	binary.BigEndian.PutUint32(header[RequestHeaderLength+16:], 10)
    25  
    26  	for _, tc := range []struct {
    27  		name string
    28  		data []byte
    29  		want []byte
    30  		err  error
    31  	}{
    32  		{
    33  			name: "EOF",
    34  			err:  io.EOF,
    35  			data: []byte{},
    36  		},
    37  		{
    38  			name: "Without data",
    39  			data: make([]byte, RequestHeaderLength+16+4),
    40  			want: make([]byte, RequestHeaderLength+16+4),
    41  		},
    42  		{
    43  			name: "With data",
    44  			data: append(header, data...),
    45  			want: append(header, data...),
    46  		},
    47  		{
    48  			name: "Header with non-zero length but without data",
    49  			err:  io.EOF,
    50  			data: header,
    51  		},
    52  	} {
    53  		t.Run(tc.name, func(t *testing.T) {
    54  			reader := bytes.NewBuffer(tc.data)
    55  			got, err := ReadRequest(reader)
    56  			if err != tc.err {
    57  				t.Errorf("error doesn't match:\ngot = %v\nwant = %v", err, tc.err)
    58  			}
    59  			if !reflect.DeepEqual(got, tc.want) {
    60  				t.Errorf("data doesn't match:\ngot = %v\nwant = %v", got, tc.want)
    61  			}
    62  			if reader.Len() != 0 {
    63  				t.Errorf("reader was not read to the end: %v", reader.Bytes())
    64  			}
    65  		})
    66  	}
    67  }
    68  
    69  func TestReadResponse(t *testing.T) {
    70  	header := make([]byte, RequestHeaderLength+16+4)
    71  	data := make([]byte, 10)
    72  	_, _ = rand.Read(data)
    73  	binary.BigEndian.PutUint32(header[RequestHeaderLength+16:], 10)
    74  
    75  	for _, tc := range []struct {
    76  		name       string
    77  		data       []byte
    78  		wantHeader ResponseHeader
    79  		wantData   []byte
    80  		err        error
    81  	}{
    82  		{
    83  			name: "EOF",
    84  			err:  io.EOF,
    85  			data: []byte{},
    86  		},
    87  		{
    88  			name:       "Without data",
    89  			data:       []byte{1, 2, 0, 0, 0, 0, 0, 0},
    90  			wantHeader: ResponseHeader{StreamID: StreamID{1, 2}},
    91  		},
    92  		{
    93  			name:       "With data",
    94  			data:       []byte{1, 2, 0, 0, 0, 0, 0, 5, 1, 2, 3, 4, 5},
    95  			wantHeader: ResponseHeader{StreamID: StreamID{1, 2}, DataLength: 5},
    96  			wantData:   []byte{1, 2, 3, 4, 5},
    97  		},
    98  		{
    99  			name:       "Header with non-zero length but without data",
   100  			err:        io.EOF,
   101  			data:       []byte{1, 2, 0, 0, 0, 0, 0, 5},
   102  			wantHeader: ResponseHeader{StreamID: StreamID{1, 2}, DataLength: 5},
   103  		},
   104  	} {
   105  		t.Run(tc.name, func(t *testing.T) {
   106  			reader := bytes.NewBuffer(tc.data)
   107  			gotHeader, gotData, err := ReadResponse(reader)
   108  			if err != tc.err {
   109  				t.Errorf("error doesn't match:\ngot = %v\nwant = %v", err, tc.err)
   110  			}
   111  			if !reflect.DeepEqual(gotHeader, tc.wantHeader) {
   112  				t.Errorf("header doesn't match:\ngot = %v\nwant = %v", gotHeader, tc.wantHeader)
   113  			}
   114  			if !reflect.DeepEqual(gotData, tc.wantData) {
   115  				t.Errorf("data doesn't match:\ngot = %v\nwant = %v", gotData, tc.wantData)
   116  			}
   117  			if reader.Len() != 0 {
   118  				t.Errorf("reader was not read to the end: %v", reader.Bytes())
   119  			}
   120  		})
   121  	}
   122  }
   123  
   124  func TestWriteResponse(t *testing.T) {
   125  	header := make([]byte, RequestHeaderLength+16+4)
   126  	data := make([]byte, 10)
   127  	_, _ = rand.Read(data)
   128  	binary.BigEndian.PutUint32(header[RequestHeaderLength+16:], 10)
   129  
   130  	for _, tc := range []struct {
   131  		name     string
   132  		wantData []byte
   133  		header   ResponseHeader
   134  		err      error
   135  		streamID StreamID
   136  		status   ResponseStatus
   137  		resp     Marshaler
   138  	}{
   139  		{
   140  			name:     "With data",
   141  			wantData: []byte{1, 2, 15, 163, 0, 0, 0, 5, 0, 0, 0, 12, 0},
   142  			status:   Error,
   143  			streamID: StreamID{1, 2},
   144  			resp:     &ServerError{Code: 12},
   145  		},
   146  		{
   147  			name:     "Without data",
   148  			wantData: []byte{1, 2, 0, 0, 0, 0, 0, 0},
   149  			status:   Ok,
   150  			streamID: StreamID{1, 2},
   151  		},
   152  	} {
   153  		t.Run(tc.name, func(t *testing.T) {
   154  			var writer bytes.Buffer
   155  			err := WriteResponse(&writer, tc.streamID, tc.status, tc.resp)
   156  			if err != tc.err {
   157  				t.Errorf("error doesn't match:\ngot = %v\nwant = %v", err, tc.err)
   158  			}
   159  			if !reflect.DeepEqual(writer.Bytes(), tc.wantData) {
   160  				t.Errorf("data doesn't match:\ngot = %v\nwant = %v", writer.Bytes(), tc.wantData)
   161  			}
   162  		})
   163  	}
   164  }
   165  
   166  func TestWaitResponse(t *testing.T) {
   167  	for _, want := range []WaitResponse{
   168  		{Duration: 0},
   169  		{Duration: 42 * time.Second},
   170  		{Duration: 42 * time.Hour},
   171  	} {
   172  		t.Run("", func(t *testing.T) {
   173  			var (
   174  				err error
   175  				w   = new(xrdenc.WBuffer)
   176  				got WaitResponse
   177  			)
   178  
   179  			err = want.MarshalXrd(w)
   180  			if err != nil {
   181  				t.Fatalf("could not marshal response: %v", err)
   182  			}
   183  
   184  			r := xrdenc.NewRBuffer(w.Bytes())
   185  			err = got.UnmarshalXrd(r)
   186  			if err != nil {
   187  				t.Fatalf("could not unmarshal response: %v", err)
   188  			}
   189  
   190  			if !reflect.DeepEqual(got, want) {
   191  				t.Fatalf("round trip failed\ngot = %#v\nwant= %#v\n", got, want)
   192  			}
   193  		})
   194  	}
   195  }
   196  
   197  func TestServerError(t *testing.T) {
   198  	for _, want := range []ServerError{
   199  		{Code: IOError, Message: ""},
   200  		{Code: NotAuthorized, Message: "not authorized"},
   201  		{Code: NotFound, Message: "not\nfound"},
   202  	} {
   203  		t.Run("", func(t *testing.T) {
   204  			var (
   205  				err error
   206  				w   = new(xrdenc.WBuffer)
   207  				got ServerError
   208  			)
   209  
   210  			err = want.MarshalXrd(w)
   211  			if err != nil {
   212  				t.Fatalf("could not marshal server error: %v", err)
   213  			}
   214  
   215  			r := xrdenc.NewRBuffer(w.Bytes())
   216  			err = got.UnmarshalXrd(r)
   217  			if err != nil {
   218  				t.Fatalf("could not unmarshal server error: %v", err)
   219  			}
   220  
   221  			if !reflect.DeepEqual(got, want) {
   222  				t.Fatalf("round trip failed\ngot = %#v\nwant= %#v\n", got, want)
   223  			}
   224  
   225  			if got, want := got.Error(), want.Error(); got != want {
   226  				t.Fatalf("error messages differ: got=%q, want=%q", got, want)
   227  			}
   228  		})
   229  	}
   230  }
   231  
   232  func TestRequestHeader(t *testing.T) {
   233  	for _, want := range []RequestHeader{
   234  		{StreamID: StreamID{1, 2}, RequestID: 2},
   235  	} {
   236  		t.Run("", func(t *testing.T) {
   237  			var (
   238  				err error
   239  				w   = new(xrdenc.WBuffer)
   240  				got RequestHeader
   241  			)
   242  
   243  			err = want.MarshalXrd(w)
   244  			if err != nil {
   245  				t.Fatalf("could not marshal: %v", err)
   246  			}
   247  
   248  			r := xrdenc.NewRBuffer(w.Bytes())
   249  			err = got.UnmarshalXrd(r)
   250  			if err != nil {
   251  				t.Fatalf("could not unmarshal: %v", err)
   252  			}
   253  
   254  			if !reflect.DeepEqual(got, want) {
   255  				t.Fatalf("round trip failed\ngot = %#v\nwant= %#v\n", got, want)
   256  			}
   257  		})
   258  	}
   259  }
   260  
   261  func TestResponseHeaderError(t *testing.T) {
   262  	get := func(err error) string {
   263  		if err != nil {
   264  			return err.Error()
   265  		}
   266  		return ""
   267  	}
   268  
   269  	for _, tc := range []struct {
   270  		hdr  ResponseHeader
   271  		data []byte
   272  		err  error
   273  	}{
   274  		{
   275  			hdr:  ResponseHeader{Status: Ok},
   276  			data: nil,
   277  			err:  nil,
   278  		},
   279  		{
   280  			hdr:  ResponseHeader{Status: OkSoFar},
   281  			data: nil,
   282  			err:  nil,
   283  		},
   284  		{
   285  			hdr: ResponseHeader{Status: Error},
   286  			data: func() []byte {
   287  				w := new(xrdenc.WBuffer)
   288  				err := ServerError{Code: IOError, Message: "boo"}.MarshalXrd(w)
   289  				if err != nil {
   290  					t.Fatal(err)
   291  				}
   292  				return w.Bytes()
   293  			}(),
   294  			err: ServerError{Code: IOError, Message: "boo"},
   295  		},
   296  		{
   297  			hdr:  ResponseHeader{Status: Error},
   298  			data: []byte{1, 2, 3},
   299  			err:  fmt.Errorf("xrootd: invalid ResponseHeader error: %w", io.ErrShortBuffer),
   300  		},
   301  		{
   302  			hdr:  ResponseHeader{Status: Error},
   303  			data: []byte{1, 2, 3, 4},
   304  			err:  fmt.Errorf("xrootd: error occurred during unmarshaling of a server error: xrootd: missing error message in server response"),
   305  		},
   306  	} {
   307  		t.Run("", func(t *testing.T) {
   308  			err := tc.hdr.Error(tc.data)
   309  			if get(err) != get(tc.err) {
   310  				t.Fatalf("got=%#v, want=%#v", err, tc.err)
   311  			}
   312  		})
   313  	}
   314  }
   315  
   316  func TestSecurityOverride(t *testing.T) {
   317  	for _, want := range []SecurityOverride{
   318  		{RequestIndex: 1, RequestLevel: SignNone},
   319  		{RequestIndex: 2, RequestLevel: SignLikely},
   320  		{RequestIndex: 3, RequestLevel: SignNeeded},
   321  	} {
   322  		t.Run("", func(t *testing.T) {
   323  			var (
   324  				err error
   325  				w   = new(xrdenc.WBuffer)
   326  				got SecurityOverride
   327  			)
   328  
   329  			err = want.MarshalXrd(w)
   330  			if err != nil {
   331  				t.Fatalf("could not marshal: %v", err)
   332  			}
   333  
   334  			r := xrdenc.NewRBuffer(w.Bytes())
   335  			err = got.UnmarshalXrd(r)
   336  			if err != nil {
   337  				t.Fatalf("could not unmarshal: %v", err)
   338  			}
   339  
   340  			if !reflect.DeepEqual(got, want) {
   341  				t.Fatalf("round trip failed\ngot = %#v\nwant= %#v\n", got, want)
   342  			}
   343  		})
   344  	}
   345  }
   346  
   347  func TestOpaque(t *testing.T) {
   348  	for _, tc := range []struct {
   349  		path string
   350  		want string
   351  	}{
   352  		{"hello", "hello"},
   353  		{"hello?", ""},
   354  		{"hello?boo", "boo"},
   355  		{"?boo", "boo"},
   356  	} {
   357  		t.Run(tc.path, func(t *testing.T) {
   358  			got := Opaque(tc.path)
   359  			if got != tc.want {
   360  				t.Fatalf("got=%q, want=%q", got, tc.want)
   361  			}
   362  		})
   363  	}
   364  }
   365  
   366  func TestSetOpaque(t *testing.T) {
   367  	for _, tc := range []struct {
   368  		path string
   369  		opaq string
   370  		want string
   371  	}{
   372  		{"", "v", "?v"},
   373  		{"hello", "v", "hello?v"},
   374  		{"hello?", "v", "hello?v"},
   375  		{"hello?boo", "v", "hello?v"},
   376  		{"?boo", "v", "?v"},
   377  		{"hello?boo?", "v", "hello?boo?v"},
   378  		{"hello?boo?bar", "v", "hello?boo?v"},
   379  		{"hello?boo=value?bar=33", "v", "hello?boo=value?v"},
   380  	} {
   381  		t.Run(tc.path, func(t *testing.T) {
   382  			got := tc.path
   383  			SetOpaque(&got, tc.opaq)
   384  			if got != tc.want {
   385  				t.Fatalf("got=%q, want=%q", got, tc.want)
   386  			}
   387  		})
   388  	}
   389  }