github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/p9/messages_test.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package p9
    16  
    17  import (
    18  	"fmt"
    19  	"reflect"
    20  	"testing"
    21  )
    22  
    23  func TestEncodeDecode(t *testing.T) {
    24  	objs := []encoder{
    25  		&QID{
    26  			Type:    1,
    27  			Version: 2,
    28  			Path:    3,
    29  		},
    30  		&FSStat{
    31  			Type:            1,
    32  			BlockSize:       2,
    33  			Blocks:          3,
    34  			BlocksFree:      4,
    35  			BlocksAvailable: 5,
    36  			Files:           6,
    37  			FilesFree:       7,
    38  			FSID:            8,
    39  			NameLength:      9,
    40  		},
    41  		&AttrMask{
    42  			Mode:        true,
    43  			NLink:       true,
    44  			UID:         true,
    45  			GID:         true,
    46  			RDev:        true,
    47  			ATime:       true,
    48  			MTime:       true,
    49  			CTime:       true,
    50  			INo:         true,
    51  			Size:        true,
    52  			Blocks:      true,
    53  			BTime:       true,
    54  			Gen:         true,
    55  			DataVersion: true,
    56  		},
    57  		&Attr{
    58  			Mode:             Exec,
    59  			UID:              2,
    60  			GID:              3,
    61  			NLink:            4,
    62  			RDev:             5,
    63  			Size:             6,
    64  			BlockSize:        7,
    65  			Blocks:           8,
    66  			ATimeSeconds:     9,
    67  			ATimeNanoSeconds: 10,
    68  			MTimeSeconds:     11,
    69  			MTimeNanoSeconds: 12,
    70  			CTimeSeconds:     13,
    71  			CTimeNanoSeconds: 14,
    72  			BTimeSeconds:     15,
    73  			BTimeNanoSeconds: 16,
    74  			Gen:              17,
    75  			DataVersion:      18,
    76  		},
    77  		&SetAttrMask{
    78  			Permissions:        true,
    79  			UID:                true,
    80  			GID:                true,
    81  			Size:               true,
    82  			ATime:              true,
    83  			MTime:              true,
    84  			CTime:              true,
    85  			ATimeNotSystemTime: true,
    86  			MTimeNotSystemTime: true,
    87  		},
    88  		&SetAttr{
    89  			Permissions:      1,
    90  			UID:              2,
    91  			GID:              3,
    92  			Size:             4,
    93  			ATimeSeconds:     5,
    94  			ATimeNanoSeconds: 6,
    95  			MTimeSeconds:     7,
    96  			MTimeNanoSeconds: 8,
    97  		},
    98  		&Dirent{
    99  			QID:    QID{Type: 1},
   100  			Offset: 2,
   101  			Type:   3,
   102  			Name:   "a",
   103  		},
   104  		&Rlerror{
   105  			Error: 1,
   106  		},
   107  		&Tstatfs{
   108  			FID: 1,
   109  		},
   110  		&Rstatfs{
   111  			FSStat: FSStat{Type: 1},
   112  		},
   113  		&Tlopen{
   114  			FID:   1,
   115  			Flags: WriteOnly,
   116  		},
   117  		&Rlopen{
   118  			QID:    QID{Type: 1},
   119  			IoUnit: 2,
   120  		},
   121  		&Tlconnect{
   122  			FID: 1,
   123  		},
   124  		&Rlconnect{},
   125  		&Tlcreate{
   126  			FID:         1,
   127  			Name:        "a",
   128  			OpenFlags:   2,
   129  			Permissions: 3,
   130  			GID:         4,
   131  		},
   132  		&Rlcreate{
   133  			Rlopen{QID: QID{Type: 1}},
   134  		},
   135  		&Tsymlink{
   136  			Directory: 1,
   137  			Name:      "a",
   138  			Target:    "b",
   139  			GID:       2,
   140  		},
   141  		&Rsymlink{
   142  			QID: QID{Type: 1},
   143  		},
   144  		&Tmknod{
   145  			Directory: 1,
   146  			Name:      "a",
   147  			Mode:      2,
   148  			Major:     3,
   149  			Minor:     4,
   150  			GID:       5,
   151  		},
   152  		&Rmknod{
   153  			QID: QID{Type: 1},
   154  		},
   155  		&Trename{
   156  			FID:       1,
   157  			Directory: 2,
   158  			Name:      "a",
   159  		},
   160  		&Rrename{},
   161  		&Treadlink{
   162  			FID: 1,
   163  		},
   164  		&Rreadlink{
   165  			Target: "a",
   166  		},
   167  		&Tgetattr{
   168  			FID:      1,
   169  			AttrMask: AttrMask{Mode: true},
   170  		},
   171  		&Rgetattr{
   172  			Valid: AttrMask{Mode: true},
   173  			QID:   QID{Type: 1},
   174  			Attr:  Attr{Mode: Write},
   175  		},
   176  		&Tsetattr{
   177  			FID:     1,
   178  			Valid:   SetAttrMask{Permissions: true},
   179  			SetAttr: SetAttr{Permissions: Write},
   180  		},
   181  		&Rsetattr{},
   182  		&Txattrwalk{
   183  			FID:    1,
   184  			NewFID: 2,
   185  			Name:   "a",
   186  		},
   187  		&Rxattrwalk{
   188  			Size: 1,
   189  		},
   190  		&Txattrcreate{
   191  			FID:      1,
   192  			Name:     "a",
   193  			AttrSize: 2,
   194  			Flags:    3,
   195  		},
   196  		&Rxattrcreate{},
   197  		&Tgetxattr{
   198  			FID:  1,
   199  			Name: "abc",
   200  			Size: 2,
   201  		},
   202  		&Rgetxattr{
   203  			Value: "xyz",
   204  		},
   205  		&Tsetxattr{
   206  			FID:   1,
   207  			Name:  "abc",
   208  			Value: "xyz",
   209  			Flags: 2,
   210  		},
   211  		&Rsetxattr{},
   212  		&Treaddir{
   213  			Directory: 1,
   214  			Offset:    2,
   215  			Count:     3,
   216  		},
   217  		&Rreaddir{
   218  			// Count must be sufficient to encode a dirent.
   219  			Count:   0x1a,
   220  			Entries: []Dirent{{QID: QID{Type: 2}}},
   221  		},
   222  		&Tfsync{
   223  			FID: 1,
   224  		},
   225  		&Rfsync{},
   226  		&Tlink{
   227  			Directory: 1,
   228  			Target:    2,
   229  			Name:      "a",
   230  		},
   231  		&Rlink{},
   232  		&Tmkdir{
   233  			Directory:   1,
   234  			Name:        "a",
   235  			Permissions: 2,
   236  			GID:         3,
   237  		},
   238  		&Rmkdir{
   239  			QID: QID{Type: 1},
   240  		},
   241  		&Trenameat{
   242  			OldDirectory: 1,
   243  			OldName:      "a",
   244  			NewDirectory: 2,
   245  			NewName:      "b",
   246  		},
   247  		&Rrenameat{},
   248  		&Tunlinkat{
   249  			Directory: 1,
   250  			Name:      "a",
   251  			Flags:     2,
   252  		},
   253  		&Runlinkat{},
   254  		&Tversion{
   255  			MSize:   1,
   256  			Version: "a",
   257  		},
   258  		&Rversion{
   259  			MSize:   1,
   260  			Version: "a",
   261  		},
   262  		&Tauth{
   263  			AuthenticationFID: 1,
   264  			UserName:          "a",
   265  			AttachName:        "b",
   266  			UID:               2,
   267  		},
   268  		&Rauth{
   269  			QID: QID{Type: 1},
   270  		},
   271  		&Tattach{
   272  			FID:  1,
   273  			Auth: Tauth{AuthenticationFID: 2},
   274  		},
   275  		&Rattach{
   276  			QID: QID{Type: 1},
   277  		},
   278  		&Tflush{
   279  			OldTag: 1,
   280  		},
   281  		&Rflush{},
   282  		&Twalk{
   283  			FID:    1,
   284  			NewFID: 2,
   285  			Names:  []string{"a"},
   286  		},
   287  		&Rwalk{
   288  			QIDs: []QID{{Type: 1}},
   289  		},
   290  		&Tread{
   291  			FID:    1,
   292  			Offset: 2,
   293  			Count:  3,
   294  		},
   295  		&Rread{
   296  			Data: []byte{'a'},
   297  		},
   298  		&Twrite{
   299  			FID:    1,
   300  			Offset: 2,
   301  			Data:   []byte{'a'},
   302  		},
   303  		&Rwrite{
   304  			Count: 1,
   305  		},
   306  		&Tclunk{
   307  			FID: 1,
   308  		},
   309  		&Rclunk{},
   310  		&Tremove{
   311  			FID: 1,
   312  		},
   313  		&Rremove{},
   314  		&Tflushf{
   315  			FID: 1,
   316  		},
   317  		&Rflushf{},
   318  		&Twalkgetattr{
   319  			FID:    1,
   320  			NewFID: 2,
   321  			Names:  []string{"a"},
   322  		},
   323  		&Rwalkgetattr{
   324  			QIDs:  []QID{{Type: 1}},
   325  			Valid: AttrMask{Mode: true},
   326  			Attr:  Attr{Mode: Write},
   327  		},
   328  		&Tucreate{
   329  			Tlcreate: Tlcreate{
   330  				FID:         1,
   331  				Name:        "a",
   332  				OpenFlags:   2,
   333  				Permissions: 3,
   334  				GID:         4,
   335  			},
   336  			UID: 5,
   337  		},
   338  		&Rucreate{
   339  			Rlcreate{Rlopen{QID: QID{Type: 1}}},
   340  		},
   341  		&Tumkdir{
   342  			Tmkdir: Tmkdir{
   343  				Directory:   1,
   344  				Name:        "a",
   345  				Permissions: 2,
   346  				GID:         3,
   347  			},
   348  			UID: 4,
   349  		},
   350  		&Rumkdir{
   351  			Rmkdir{QID: QID{Type: 1}},
   352  		},
   353  		&Tusymlink{
   354  			Tsymlink: Tsymlink{
   355  				Directory: 1,
   356  				Name:      "a",
   357  				Target:    "b",
   358  				GID:       2,
   359  			},
   360  			UID: 3,
   361  		},
   362  		&Rusymlink{
   363  			Rsymlink{QID: QID{Type: 1}},
   364  		},
   365  		&Tumknod{
   366  			Tmknod: Tmknod{
   367  				Directory: 1,
   368  				Name:      "a",
   369  				Mode:      2,
   370  				Major:     3,
   371  				Minor:     4,
   372  				GID:       5,
   373  			},
   374  			UID: 6,
   375  		},
   376  		&Rumknod{
   377  			Rmknod{QID: QID{Type: 1}},
   378  		},
   379  		&Tsetattrclunk{
   380  			FID: 1,
   381  			Valid: SetAttrMask{
   382  				Permissions:        true,
   383  				UID:                true,
   384  				GID:                true,
   385  				Size:               true,
   386  				ATime:              true,
   387  				MTime:              true,
   388  				CTime:              true,
   389  				ATimeNotSystemTime: true,
   390  				MTimeNotSystemTime: true,
   391  			},
   392  			SetAttr: SetAttr{
   393  				Permissions:      1,
   394  				UID:              2,
   395  				GID:              3,
   396  				Size:             4,
   397  				ATimeSeconds:     5,
   398  				ATimeNanoSeconds: 6,
   399  				MTimeSeconds:     7,
   400  				MTimeNanoSeconds: 8,
   401  			},
   402  		},
   403  	}
   404  
   405  	for _, enc := range objs {
   406  		// Encode the original.
   407  		data := make([]byte, initialBufferLength)
   408  		buf := buffer{data: data[:0]}
   409  		enc.encode(&buf)
   410  
   411  		// Create a new object, same as the first.
   412  		enc2 := reflect.New(reflect.ValueOf(enc).Elem().Type()).Interface().(encoder)
   413  		buf2 := buffer{data: buf.data}
   414  
   415  		// To be fair, we need to add any payloads (directly).
   416  		if pl, ok := enc.(payloader); ok {
   417  			enc2.(payloader).SetPayload(pl.Payload())
   418  		}
   419  
   420  		// And any file payloads (directly).
   421  		if fl, ok := enc.(filer); ok {
   422  			enc2.(filer).SetFilePayload(fl.FilePayload())
   423  		}
   424  
   425  		// Mark sure it was okay.
   426  		enc2.decode(&buf2)
   427  		if buf2.isOverrun() {
   428  			t.Errorf("object %#v->%#v got overrun on decode", enc, enc2)
   429  			continue
   430  		}
   431  
   432  		// Check that they are equal.
   433  		if !reflect.DeepEqual(enc, enc2) {
   434  			t.Errorf("object %#v and %#v differ", enc, enc2)
   435  			continue
   436  		}
   437  	}
   438  }
   439  
   440  func TestMessageStrings(t *testing.T) {
   441  	for typ := range msgRegistry.factories {
   442  		entry := &msgRegistry.factories[typ]
   443  		if entry.create != nil {
   444  			name := fmt.Sprintf("%+v", typ)
   445  			t.Run(name, func(t *testing.T) {
   446  				defer func() { // Ensure no panic.
   447  					if r := recover(); r != nil {
   448  						t.Errorf("printing %s failed: %v", name, r)
   449  					}
   450  				}()
   451  				m := entry.create()
   452  				_ = fmt.Sprintf("%v", m)
   453  				err := ErrInvalidMsgType{MsgType(typ)}
   454  				_ = err.Error()
   455  			})
   456  		}
   457  	}
   458  }
   459  
   460  func TestRegisterDuplicate(t *testing.T) {
   461  	defer func() {
   462  		if r := recover(); r == nil {
   463  			// We expect a panic.
   464  			t.FailNow()
   465  		}
   466  	}()
   467  
   468  	// Register a duplicate.
   469  	msgRegistry.register(MsgRlerror, func() message { return &Rlerror{} })
   470  }
   471  
   472  func TestMsgCache(t *testing.T) {
   473  	// Cache starts empty.
   474  	if got, want := len(msgRegistry.factories[MsgRlerror].cache), 0; got != want {
   475  		t.Errorf("Wrong cache size, got: %d, want: %d", got, want)
   476  	}
   477  
   478  	// Message can be created with an empty cache.
   479  	msg, err := msgRegistry.get(0, MsgRlerror)
   480  	if err != nil {
   481  		t.Errorf("msgRegistry.get(): %v", err)
   482  	}
   483  	if got, want := len(msgRegistry.factories[MsgRlerror].cache), 0; got != want {
   484  		t.Errorf("Wrong cache size, got: %d, want: %d", got, want)
   485  	}
   486  
   487  	// Check that message is added to the cache when returned.
   488  	msgRegistry.put(msg)
   489  	if got, want := len(msgRegistry.factories[MsgRlerror].cache), 1; got != want {
   490  		t.Errorf("Wrong cache size, got: %d, want: %d", got, want)
   491  	}
   492  
   493  	// Check that returned message is reused.
   494  	if got, err := msgRegistry.get(0, MsgRlerror); err != nil {
   495  		t.Errorf("msgRegistry.get(): %v", err)
   496  	} else if msg != got {
   497  		t.Errorf("Message not reused, got: %d, want: %d", got, msg)
   498  	}
   499  
   500  	// Check that cache doesn't grow beyond max size.
   501  	for i := 0; i < maxCacheSize+1; i++ {
   502  		msgRegistry.put(&Rlerror{})
   503  	}
   504  	if got, want := len(msgRegistry.factories[MsgRlerror].cache), maxCacheSize; got != want {
   505  		t.Errorf("Wrong cache size, got: %d, want: %d", got, want)
   506  	}
   507  }