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 }