gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/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  		&Tbind{
   122  			Directory: 1,
   123  			SockType:  2,
   124  			SockName:  "name",
   125  			GID:       3,
   126  			UID:       4,
   127  			NewFID:    5,
   128  		},
   129  		&Rbind{
   130  			QID: QID{Type: 1},
   131  		},
   132  		&Tlconnect{
   133  			FID: 1,
   134  		},
   135  		&Rlconnect{},
   136  		&Tlcreate{
   137  			FID:         1,
   138  			Name:        "a",
   139  			OpenFlags:   2,
   140  			Permissions: 3,
   141  			GID:         4,
   142  		},
   143  		&Rlcreate{
   144  			Rlopen{QID: QID{Type: 1}},
   145  		},
   146  		&Tsymlink{
   147  			Directory: 1,
   148  			Name:      "a",
   149  			Target:    "b",
   150  			GID:       2,
   151  		},
   152  		&Rsymlink{
   153  			QID: QID{Type: 1},
   154  		},
   155  		&Tmknod{
   156  			Directory: 1,
   157  			Name:      "a",
   158  			Mode:      2,
   159  			Major:     3,
   160  			Minor:     4,
   161  			GID:       5,
   162  		},
   163  		&Rmknod{
   164  			QID: QID{Type: 1},
   165  		},
   166  		&Trename{
   167  			FID:       1,
   168  			Directory: 2,
   169  			Name:      "a",
   170  		},
   171  		&Rrename{},
   172  		&Treadlink{
   173  			FID: 1,
   174  		},
   175  		&Rreadlink{
   176  			Target: "a",
   177  		},
   178  		&Tgetattr{
   179  			FID:      1,
   180  			AttrMask: AttrMask{Mode: true},
   181  		},
   182  		&Rgetattr{
   183  			Valid: AttrMask{Mode: true},
   184  			QID:   QID{Type: 1},
   185  			Attr:  Attr{Mode: Write},
   186  		},
   187  		&Tsetattr{
   188  			FID:     1,
   189  			Valid:   SetAttrMask{Permissions: true},
   190  			SetAttr: SetAttr{Permissions: Write},
   191  		},
   192  		&Rsetattr{},
   193  		&Txattrwalk{
   194  			FID:    1,
   195  			NewFID: 2,
   196  			Name:   "a",
   197  		},
   198  		&Rxattrwalk{
   199  			Size: 1,
   200  		},
   201  		&Txattrcreate{
   202  			FID:      1,
   203  			Name:     "a",
   204  			AttrSize: 2,
   205  			Flags:    3,
   206  		},
   207  		&Rxattrcreate{},
   208  		&Tgetxattr{
   209  			FID:  1,
   210  			Name: "abc",
   211  			Size: 2,
   212  		},
   213  		&Rgetxattr{
   214  			Value: "xyz",
   215  		},
   216  		&Tsetxattr{
   217  			FID:   1,
   218  			Name:  "abc",
   219  			Value: "xyz",
   220  			Flags: 2,
   221  		},
   222  		&Rsetxattr{},
   223  		&Treaddir{
   224  			Directory:    1,
   225  			DirentOffset: 2,
   226  			Count:        3,
   227  		},
   228  		&Rreaddir{
   229  			// Count must be sufficient to encode a dirent.
   230  			Count:   0x1a,
   231  			Entries: []Dirent{{QID: QID{Type: 2}}},
   232  		},
   233  		&Tfsync{
   234  			FID: 1,
   235  		},
   236  		&Rfsync{},
   237  		&Tlink{
   238  			Directory: 1,
   239  			Target:    2,
   240  			Name:      "a",
   241  		},
   242  		&Rlink{},
   243  		&Tmkdir{
   244  			Directory:   1,
   245  			Name:        "a",
   246  			Permissions: 2,
   247  			GID:         3,
   248  		},
   249  		&Rmkdir{
   250  			QID: QID{Type: 1},
   251  		},
   252  		&Trenameat{
   253  			OldDirectory: 1,
   254  			OldName:      "a",
   255  			NewDirectory: 2,
   256  			NewName:      "b",
   257  		},
   258  		&Rrenameat{},
   259  		&Tunlinkat{
   260  			Directory: 1,
   261  			Name:      "a",
   262  			Flags:     2,
   263  		},
   264  		&Runlinkat{},
   265  		&Tversion{
   266  			MSize:   1,
   267  			Version: "a",
   268  		},
   269  		&Rversion{
   270  			MSize:   1,
   271  			Version: "a",
   272  		},
   273  		&Tauth{
   274  			AuthenticationFID: 1,
   275  			UserName:          "a",
   276  			AttachName:        "b",
   277  			UID:               2,
   278  		},
   279  		&Rauth{
   280  			QID: QID{Type: 1},
   281  		},
   282  		&Tattach{
   283  			FID:  1,
   284  			Auth: Tauth{AuthenticationFID: 2},
   285  		},
   286  		&Rattach{
   287  			QID: QID{Type: 1},
   288  		},
   289  		&Tflush{
   290  			OldTag: 1,
   291  		},
   292  		&Rflush{},
   293  		&Twalk{
   294  			FID:    1,
   295  			NewFID: 2,
   296  			Names:  []string{"a"},
   297  		},
   298  		&Rwalk{
   299  			QIDs: []QID{{Type: 1}},
   300  		},
   301  		&Tread{
   302  			FID:    1,
   303  			Offset: 2,
   304  			Count:  3,
   305  		},
   306  		&Rread{
   307  			Data: []byte{'a'},
   308  		},
   309  		&Twrite{
   310  			FID:    1,
   311  			Offset: 2,
   312  			Data:   []byte{'a'},
   313  		},
   314  		&Rwrite{
   315  			Count: 1,
   316  		},
   317  		&Tclunk{
   318  			FID: 1,
   319  		},
   320  		&Rclunk{},
   321  		&Tremove{
   322  			FID: 1,
   323  		},
   324  		&Rremove{},
   325  		&Tflushf{
   326  			FID: 1,
   327  		},
   328  		&Rflushf{},
   329  		&Twalkgetattr{
   330  			FID:    1,
   331  			NewFID: 2,
   332  			Names:  []string{"a"},
   333  		},
   334  		&Rwalkgetattr{
   335  			QIDs:  []QID{{Type: 1}},
   336  			Valid: AttrMask{Mode: true},
   337  			Attr:  Attr{Mode: Write},
   338  		},
   339  		&Tucreate{
   340  			Tlcreate: Tlcreate{
   341  				FID:         1,
   342  				Name:        "a",
   343  				OpenFlags:   2,
   344  				Permissions: 3,
   345  				GID:         4,
   346  			},
   347  			UID: 5,
   348  		},
   349  		&Rucreate{
   350  			Rlcreate{Rlopen{QID: QID{Type: 1}}},
   351  		},
   352  		&Tumkdir{
   353  			Tmkdir: Tmkdir{
   354  				Directory:   1,
   355  				Name:        "a",
   356  				Permissions: 2,
   357  				GID:         3,
   358  			},
   359  			UID: 4,
   360  		},
   361  		&Rumkdir{
   362  			Rmkdir{QID: QID{Type: 1}},
   363  		},
   364  		&Tusymlink{
   365  			Tsymlink: Tsymlink{
   366  				Directory: 1,
   367  				Name:      "a",
   368  				Target:    "b",
   369  				GID:       2,
   370  			},
   371  			UID: 3,
   372  		},
   373  		&Rusymlink{
   374  			Rsymlink{QID: QID{Type: 1}},
   375  		},
   376  		&Tumknod{
   377  			Tmknod: Tmknod{
   378  				Directory: 1,
   379  				Name:      "a",
   380  				Mode:      2,
   381  				Major:     3,
   382  				Minor:     4,
   383  				GID:       5,
   384  			},
   385  			UID: 6,
   386  		},
   387  		&Rumknod{
   388  			Rmknod{QID: QID{Type: 1}},
   389  		},
   390  		&Tsetattrclunk{
   391  			FID: 1,
   392  			Valid: SetAttrMask{
   393  				Permissions:        true,
   394  				UID:                true,
   395  				GID:                true,
   396  				Size:               true,
   397  				ATime:              true,
   398  				MTime:              true,
   399  				CTime:              true,
   400  				ATimeNotSystemTime: true,
   401  				MTimeNotSystemTime: true,
   402  			},
   403  			SetAttr: SetAttr{
   404  				Permissions:      1,
   405  				UID:              2,
   406  				GID:              3,
   407  				Size:             4,
   408  				ATimeSeconds:     5,
   409  				ATimeNanoSeconds: 6,
   410  				MTimeSeconds:     7,
   411  				MTimeNanoSeconds: 8,
   412  			},
   413  		},
   414  	}
   415  
   416  	for _, enc := range objs {
   417  		// Encode the original.
   418  		data := make([]byte, initialBufferLength)
   419  		buf := buffer{data: data[:0]}
   420  		enc.encode(&buf)
   421  
   422  		// Create a new object, same as the first.
   423  		enc2 := reflect.New(reflect.ValueOf(enc).Elem().Type()).Interface().(encoder)
   424  		buf2 := buffer{data: buf.data}
   425  
   426  		// To be fair, we need to add any payloads (directly).
   427  		if pl, ok := enc.(payloader); ok {
   428  			enc2.(payloader).SetPayload(pl.Payload())
   429  		}
   430  
   431  		// And any file payloads (directly).
   432  		if fl, ok := enc.(filer); ok {
   433  			enc2.(filer).SetFilePayload(fl.FilePayload())
   434  		}
   435  
   436  		// Mark sure it was okay.
   437  		enc2.decode(&buf2)
   438  		if buf2.isOverrun() {
   439  			t.Errorf("object %#v->%#v got overrun on decode", enc, enc2)
   440  			continue
   441  		}
   442  
   443  		// Check that they are equal.
   444  		if !reflect.DeepEqual(enc, enc2) {
   445  			t.Errorf("object %#v and %#v differ", enc, enc2)
   446  			continue
   447  		}
   448  	}
   449  }
   450  
   451  func TestMessageStrings(t *testing.T) {
   452  	for typ := range msgRegistry.factories {
   453  		entry := &msgRegistry.factories[typ]
   454  		if entry.create != nil {
   455  			name := fmt.Sprintf("%+v", typ)
   456  			t.Run(name, func(t *testing.T) {
   457  				defer func() { // Ensure no panic.
   458  					if r := recover(); r != nil {
   459  						t.Errorf("printing %s failed: %v", name, r)
   460  					}
   461  				}()
   462  				m := entry.create()
   463  				_ = fmt.Sprintf("%v", m)
   464  				err := ErrInvalidMsgType{MsgType(typ)}
   465  				_ = err.Error()
   466  			})
   467  		}
   468  	}
   469  }
   470  
   471  func TestRegisterDuplicate(t *testing.T) {
   472  	defer func() {
   473  		if r := recover(); r == nil {
   474  			// We expect a panic.
   475  			t.FailNow()
   476  		}
   477  	}()
   478  
   479  	// Register a duplicate.
   480  	msgRegistry.register(MsgRlerror, func() message { return &Rlerror{} })
   481  }
   482  
   483  func TestMsgCache(t *testing.T) {
   484  	// Cache starts empty.
   485  	if got, want := len(msgRegistry.factories[MsgRlerror].cache), 0; got != want {
   486  		t.Errorf("Wrong cache size, got: %d, want: %d", got, want)
   487  	}
   488  
   489  	// Message can be created with an empty cache.
   490  	msg, err := msgRegistry.get(0, MsgRlerror)
   491  	if err != nil {
   492  		t.Errorf("msgRegistry.get(): %v", err)
   493  	}
   494  	if got, want := len(msgRegistry.factories[MsgRlerror].cache), 0; got != want {
   495  		t.Errorf("Wrong cache size, got: %d, want: %d", got, want)
   496  	}
   497  
   498  	// Check that message is added to the cache when returned.
   499  	msgRegistry.put(msg)
   500  	if got, want := len(msgRegistry.factories[MsgRlerror].cache), 1; got != want {
   501  		t.Errorf("Wrong cache size, got: %d, want: %d", got, want)
   502  	}
   503  
   504  	// Check that returned message is reused.
   505  	if got, err := msgRegistry.get(0, MsgRlerror); err != nil {
   506  		t.Errorf("msgRegistry.get(): %v", err)
   507  	} else if msg != got {
   508  		t.Errorf("Message not reused, got: %d, want: %d", got, msg)
   509  	}
   510  
   511  	// Check that cache doesn't grow beyond max size.
   512  	for i := 0; i < maxCacheSize+1; i++ {
   513  		msgRegistry.put(&Rlerror{})
   514  	}
   515  	if got, want := len(msgRegistry.factories[MsgRlerror].cache), maxCacheSize; got != want {
   516  		t.Errorf("Wrong cache size, got: %d, want: %d", got, want)
   517  	}
   518  }