1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <errno.h> 6 #include <fcntl.h> 7 #include <pthread.h> 8 9 #include <set> 10 #include <string> 11 12 #include <gmock/gmock.h> 13 #include <ppapi/c/pp_errors.h> 14 #include <ppapi/c/pp_instance.h> 15 16 #include "fake_ppapi/fake_messaging_interface.h" 17 #include "fake_ppapi/fake_pepper_interface.h" 18 #include "nacl_io/ioctl.h" 19 #include "nacl_io/jsfs/js_fs.h" 20 #include "nacl_io/jsfs/js_fs_node.h" 21 #include "nacl_io/kernel_intercept.h" 22 #include "nacl_io/kernel_proxy.h" 23 #include "nacl_io/log.h" 24 #include "nacl_io/osdirent.h" 25 #include "nacl_io/osunistd.h" 26 #include "sdk_util/auto_lock.h" 27 #include "sdk_util/scoped_ref.h" 28 #include "sdk_util/simple_lock.h" 29 30 using namespace nacl_io; 31 using namespace sdk_util; 32 33 namespace { 34 35 class JsFsForTesting : public JsFs { 36 public: 37 JsFsForTesting(PepperInterface* ppapi) { 38 FsInitArgs args; 39 args.ppapi = ppapi; 40 Error error = Init(args); 41 EXPECT_EQ(0, error); 42 } 43 }; 44 45 class FakeMessagingInterfaceJsFs : public MessagingInterface { 46 public: 47 explicit FakeMessagingInterfaceJsFs(VarInterface* var_interface) 48 : var_interface_(var_interface), has_message_(false) { 49 pthread_cond_init(&cond_, NULL); 50 } 51 52 ~FakeMessagingInterfaceJsFs() { pthread_cond_destroy(&cond_); } 53 54 virtual void PostMessage(PP_Instance instance, PP_Var message) { 55 var_interface_->AddRef(message); 56 57 AUTO_LOCK(lock_); 58 ASSERT_FALSE(has_message_); 59 60 message_ = message; 61 has_message_ = true; 62 pthread_cond_signal(&cond_); 63 } 64 65 PP_Var WaitForMessage() { 66 AUTO_LOCK(lock_); 67 while (!has_message_) { 68 pthread_cond_wait(&cond_, lock_.mutex()); 69 } 70 71 has_message_ = false; 72 return message_; 73 } 74 75 private: 76 VarInterface* var_interface_; 77 SimpleLock lock_; 78 pthread_cond_t cond_; 79 PP_Var message_; 80 bool has_message_; 81 }; 82 83 class FakePepperInterfaceJsFs : public FakePepperInterface { 84 public: 85 FakePepperInterfaceJsFs() : messaging_interface_(GetVarInterface()) {} 86 87 virtual nacl_io::MessagingInterface* GetMessagingInterface() { 88 return &messaging_interface_; 89 } 90 91 private: 92 FakeMessagingInterfaceJsFs messaging_interface_; 93 }; 94 95 class JsFsTest : public ::testing::Test { 96 public: 97 void SetUp() { 98 ASSERT_EQ(0, ki_push_state_for_testing()); 99 ASSERT_EQ(0, ki_init_interface(&kp_, &ppapi_)); 100 fs_.reset(new JsFsForTesting(&ppapi_)); 101 102 js_thread_started_ = false; 103 } 104 105 void TearDown() { 106 if (js_thread_started_) 107 pthread_join(js_thread_, NULL); 108 109 for (RequestResponses::iterator it = request_responses_.begin(), 110 end = request_responses_.end(); 111 it != end; 112 ++it) { 113 ppapi_.GetVarInterface()->Release(it->request); 114 ppapi_.GetVarInterface()->Release(it->response); 115 } 116 117 118 ki_uninit(); 119 } 120 121 void StartJsThread() { 122 ASSERT_EQ(0, pthread_create(&js_thread_, NULL, JsThreadMainThunk, this)); 123 js_thread_started_ = true; 124 } 125 126 static void* JsThreadMainThunk(void* arg) { 127 static_cast<JsFsTest*>(arg)->JsThreadMain(); 128 return NULL; 129 } 130 131 PP_Var WaitForRequest() { 132 FakeMessagingInterfaceJsFs* messaging_if = 133 static_cast<FakeMessagingInterfaceJsFs*>( 134 ppapi_.GetMessagingInterface()); 135 return messaging_if->WaitForMessage(); 136 } 137 138 void JsThreadMain() { 139 for (RequestResponses::iterator it = request_responses_.begin(), 140 end = request_responses_.end(); 141 it != end; 142 ++it) { 143 PP_Var request = WaitForRequest(); 144 EXPECT_TRUE(VarsAreEqual(it->request, request)) 145 << "Vars are not equal: " << VarToString(it->request) 146 << " != " << VarToString(request); 147 ppapi_.GetVarInterface()->Release(request); 148 EXPECT_EQ(0, 149 fs_->Filesystem_Ioctl(NACL_IOC_HANDLEMESSAGE, &it->response)); 150 // Passed ownership of response_ to filesystem, so set this to undefined 151 // so it isn't double-released in TearDown(). 152 it->response = PP_MakeUndefined(); 153 } 154 } 155 156 void Expect(PP_Var request, PP_Var response) { 157 RequestResponse rr; 158 // Pass ownership of both vars from caller to callee. 159 rr.request = request; 160 rr.response = response; 161 request_responses_.push_back(rr); 162 } 163 164 bool CreateDict(PP_Var* out_var) { 165 *out_var = ppapi_.GetVarDictionaryInterface()->Create(); 166 return out_var->type == PP_VARTYPE_DICTIONARY; 167 } 168 169 bool SetDictKeyValue(PP_Var* var, const char* key, int32_t value) { 170 return SetDictKeyValue(var, key, PP_MakeInt32(value)); 171 } 172 173 bool SetDictKeyValue(PP_Var* var, const char* key, size_t value) { 174 return SetDictKeyValue(var, key, PP_MakeInt32(static_cast<size_t>(value))); 175 } 176 177 bool SetDictKeyValue(PP_Var* var, const char* key, int64_t value) { 178 VarArrayInterface* array_if = ppapi_.GetVarArrayInterface(); 179 PP_Var value_var = array_if->Create(); 180 return array_if->Set(value_var, 0, PP_MakeInt32(value >> 32)) && 181 array_if->Set(value_var, 1, PP_MakeInt32(value & 0xffffffff)) && 182 SetDictKeyValue(var, key, value_var); 183 } 184 185 bool SetDictKeyValue(PP_Var* var, const char* key, const char* value) { 186 VarInterface* var_if = ppapi_.GetVarInterface(); 187 PP_Var value_var = var_if->VarFromUtf8(value, strlen(value)); 188 return SetDictKeyValue(var, key, value_var); 189 } 190 191 bool SetDictKeyValue(PP_Var* var, const char* key, PP_Var value_var) { 192 VarDictionaryInterface* dict_if = ppapi_.GetVarDictionaryInterface(); 193 VarInterface* var_if = ppapi_.GetVarInterface(); 194 PP_Var key_var = var_if->VarFromUtf8(key, strlen(key)); 195 PP_Bool result = dict_if->Set(*var, key_var, value_var); 196 var_if->Release(key_var); 197 var_if->Release(value_var); 198 return result == PP_TRUE; 199 } 200 201 bool CreateArray(PP_Var* out_var) { 202 *out_var = ppapi_.GetVarArrayInterface()->Create(); 203 return out_var->type == PP_VARTYPE_ARRAY; 204 } 205 206 bool SetArrayValue(PP_Var* var, uint32_t i, int32_t value) { 207 return SetArrayValue(var, i, PP_MakeInt32(value)); 208 } 209 210 bool SetArrayValue(PP_Var* var, uint32_t i, const char* value) { 211 VarInterface* var_if = ppapi_.GetVarInterface(); 212 PP_Var value_var = var_if->VarFromUtf8(value, strlen(value)); 213 return SetArrayValue(var, i, value_var); 214 } 215 216 bool SetArrayValue(PP_Var* var, uint32_t i, int64_t value) { 217 VarArrayInterface* array_if = ppapi_.GetVarArrayInterface(); 218 PP_Var value_var = array_if->Create(); 219 return array_if->Set(value_var, 0, PP_MakeInt32(value >> 32)) && 220 array_if->Set(value_var, 1, PP_MakeInt32(value & 0xffffffff)) && 221 SetArrayValue(var, i, value_var); 222 } 223 224 bool SetArrayValue(PP_Var* var, uint32_t i, PP_Var value_var) { 225 VarArrayInterface* array_if = ppapi_.GetVarArrayInterface(); 226 VarInterface* var_if = ppapi_.GetVarInterface(); 227 PP_Bool result = array_if->Set(*var, i, value_var); 228 var_if->Release(value_var); 229 return result == PP_TRUE; 230 } 231 232 std::string VarToString(PP_Var var) { 233 VarDictionaryInterface* dict_if = ppapi_.GetVarDictionaryInterface(); 234 VarArrayInterface* array_if = ppapi_.GetVarArrayInterface(); 235 VarInterface* var_if = ppapi_.GetVarInterface(); 236 VarArrayBufferInterface* array_buffer_if = 237 ppapi_.GetVarArrayBufferInterface(); 238 239 switch (var.type) { 240 case PP_VARTYPE_UNDEFINED: 241 return "undefined"; 242 case PP_VARTYPE_NULL: 243 return "null"; 244 case PP_VARTYPE_BOOL: 245 return var.value.as_bool ? "true" : "false"; 246 case PP_VARTYPE_INT32: { 247 char buffer[32]; 248 snprintf(buffer, 32, "%d", var.value.as_int); 249 return buffer; 250 } 251 case PP_VARTYPE_DOUBLE: { 252 char buffer[32]; 253 snprintf(buffer, 32, "%g", var.value.as_double); 254 return buffer; 255 } 256 case PP_VARTYPE_STRING: { 257 uint32_t var_len; 258 const char* var_str = var_if->VarToUtf8(var, &var_len); 259 std::string result("\""); 260 result += std::string(var_str, var_len); 261 result += "\""; 262 return result; 263 } 264 case PP_VARTYPE_ARRAY: { 265 std::string result("["); 266 uint32_t var_len = array_if->GetLength(var); 267 268 for (uint32_t i = 0; i < var_len; ++i) { 269 PP_Var var_item = array_if->Get(var, i); 270 result += VarToString(var_item); 271 var_if->Release(var_item); 272 if (i != var_len - 1) 273 result += ", "; 274 } 275 result += "]"; 276 return result; 277 } 278 case PP_VARTYPE_DICTIONARY: { 279 std::string result("{"); 280 PP_Var var_keys = dict_if->GetKeys(var); 281 uint32_t var_len = array_if->GetLength(var_keys); 282 283 for (uint32_t i = 0; i < var_len; ++i) { 284 PP_Var key = array_if->Get(var_keys, i); 285 result += VarToString(key); 286 result += ": "; 287 PP_Var var_value = dict_if->Get(var, key); 288 result += VarToString(var_value); 289 var_if->Release(key); 290 var_if->Release(var_value); 291 if (i != var_len - 1) 292 result += ", "; 293 } 294 result += "}"; 295 var_if->Release(var_keys); 296 return result; 297 } 298 case PP_VARTYPE_ARRAY_BUFFER: { 299 uint32_t var_len; 300 if (!array_buffer_if->ByteLength(var, &var_len)) { 301 LOG_ERROR("Unable to get byte length of var."); 302 return "undefined"; 303 } 304 305 std::string result("new Uint8Array(["); 306 307 void* var_ptr = array_buffer_if->Map(var); 308 for (uint32_t i = 0; i < var_len; ++i) { 309 char buffer[8]; 310 snprintf(buffer, 8, "%d", static_cast<uint8_t*>(var_ptr)[i]); 311 result += buffer; 312 if (i != var_len - 1) 313 result += ", "; 314 } 315 result += "])"; 316 array_buffer_if->Unmap(var); 317 return result; 318 } 319 320 default: 321 ADD_FAILURE() << "Unexpected var type: " << var.type; 322 return "undefined"; 323 } 324 } 325 326 bool VarsAreEqual(PP_Var expected, PP_Var var) { 327 if (expected.type != var.type) 328 return false; 329 330 VarDictionaryInterface* dict_if = ppapi_.GetVarDictionaryInterface(); 331 VarArrayInterface* array_if = ppapi_.GetVarArrayInterface(); 332 VarInterface* var_if = ppapi_.GetVarInterface(); 333 VarArrayBufferInterface* array_buffer_if = 334 ppapi_.GetVarArrayBufferInterface(); 335 336 switch (var.type) { 337 case PP_VARTYPE_UNDEFINED: 338 case PP_VARTYPE_NULL: 339 return true; 340 case PP_VARTYPE_BOOL: 341 return expected.value.as_bool == var.value.as_bool; 342 case PP_VARTYPE_INT32: 343 return expected.value.as_int == var.value.as_int; 344 case PP_VARTYPE_DOUBLE: 345 return expected.value.as_double == var.value.as_double; 346 case PP_VARTYPE_STRING: { 347 uint32_t var_len; 348 uint32_t expected_len; 349 const char* var_str = var_if->VarToUtf8(var, &var_len); 350 const char* expected_str = var_if->VarToUtf8(expected, &expected_len); 351 352 if (expected_len != var_len) 353 return false; 354 355 return memcmp(expected_str, var_str, var_len) == 0; 356 } 357 case PP_VARTYPE_ARRAY: { 358 uint32_t var_len = array_if->GetLength(var); 359 uint32_t expected_len = array_if->GetLength(expected); 360 361 if (expected_len != var_len) 362 return false; 363 364 for (uint32_t i = 0; i < var_len; ++i) { 365 PP_Var var_item = array_if->Get(var, i); 366 PP_Var expected_item = array_if->Get(expected, i); 367 bool equal = VarsAreEqual(expected_item, var_item); 368 var_if->Release(var_item); 369 var_if->Release(expected_item); 370 371 if (!equal) 372 return false; 373 } 374 375 return true; 376 } 377 case PP_VARTYPE_DICTIONARY: { 378 PP_Var var_keys = dict_if->GetKeys(var); 379 PP_Var expected_keys = dict_if->GetKeys(expected); 380 381 uint32_t var_len = array_if->GetLength(var_keys); 382 uint32_t expected_len = array_if->GetLength(expected_keys); 383 384 bool result = true; 385 386 if (expected_len == var_len) { 387 for (uint32_t i = 0; i < var_len; ++i) { 388 PP_Var key = array_if->Get(var_keys, i); 389 PP_Var var_value = dict_if->Get(var, key); 390 PP_Var expected_value = dict_if->Get(expected, key); 391 bool equal = VarsAreEqual(expected_value, var_value); 392 var_if->Release(key); 393 var_if->Release(var_value); 394 var_if->Release(expected_value); 395 396 if (!equal) { 397 result = false; 398 break; 399 } 400 } 401 } else { 402 result = false; 403 } 404 405 var_if->Release(var_keys); 406 var_if->Release(expected_keys); 407 return result; 408 } 409 case PP_VARTYPE_ARRAY_BUFFER: { 410 uint32_t var_len; 411 if (!array_buffer_if->ByteLength(var, &var_len)) 412 return false; 413 414 uint32_t expected_len; 415 if (!array_buffer_if->ByteLength(expected, &expected_len)) 416 return false; 417 418 if (expected_len != var_len) 419 return false; 420 421 void* var_ptr = array_buffer_if->Map(var); 422 void* expected_ptr = array_buffer_if->Map(expected); 423 bool equal = memcmp(var_ptr, expected_ptr, var_len) == 0; 424 array_buffer_if->Unmap(var); 425 array_buffer_if->Unmap(expected); 426 427 return equal; 428 } 429 430 default: 431 ADD_FAILURE() << "Unexpected var type: " << var.type; 432 return false; 433 } 434 } 435 436 PP_Var CreateDummyArrayBuffer(uint32_t length) { 437 VarArrayBufferInterface* array_buffer_if = 438 ppapi_.GetVarArrayBufferInterface(); 439 PP_Var var = array_buffer_if->Create(length); 440 uint8_t* data = static_cast<uint8_t*>(array_buffer_if->Map(var)); 441 FillDummyBuffer(data, length); 442 array_buffer_if->Unmap(var); 443 return var; 444 } 445 446 void FillDummyBuffer(uint8_t* buf, size_t buf_len) { 447 for (uint32_t i = 0; i < buf_len; ++i) { 448 buf[i] = i & 255; 449 } 450 } 451 452 bool EqualsDummyArrayBuffer(uint8_t* buf, size_t buf_len) { 453 for (uint32_t i = 0; i < buf_len; ++i) { 454 if (buf[i] != (i & 255)) { 455 LOG_ERROR("Byte %d of ArrayBuffer doesn't match: %d != %d.", 456 i, 457 buf[i], 458 i & 255); 459 return false; 460 } 461 } 462 return true; 463 } 464 465 protected: 466 FakePepperInterfaceJsFs ppapi_; 467 ScopedRef<JsFsForTesting> fs_; 468 KernelProxy kp_; 469 pthread_t js_thread_; 470 bool js_thread_started_; 471 472 struct RequestResponse { 473 PP_Var request; 474 PP_Var response; 475 }; 476 477 typedef std::vector<RequestResponse> RequestResponses; 478 RequestResponses request_responses_; 479 }; 480 481 class JsFsNodeTest : public JsFsTest { 482 public: 483 static const int fd; 484 485 virtual void SetUp() { 486 JsFsTest::SetUp(); 487 488 PP_Var expected; 489 ASSERT_EQ(true, CreateDict(&expected)); 490 ASSERT_EQ(true, SetDictKeyValue(&expected, "id", 1)); 491 ASSERT_EQ(true, SetDictKeyValue(&expected, "cmd", "open")); 492 ASSERT_EQ(true, SetDictKeyValue(&expected, "path", "/foo")); 493 ASSERT_EQ(true, SetDictKeyValue(&expected, "oflag", O_RDONLY)); 494 495 PP_Var response; 496 ASSERT_EQ(true, CreateDict(&response)); 497 ASSERT_EQ(true, SetDictKeyValue(&response, "id", 1)); 498 ASSERT_EQ(true, SetDictKeyValue(&response, "error", 0)); 499 ASSERT_EQ(true, SetDictKeyValue(&response, "fd", fd)); 500 501 Expect(expected, response); 502 } 503 504 virtual void TearDown() { 505 JsFsTest::TearDown(); 506 } 507 508 void OpenNode() { 509 EXPECT_EQ(0, fs_->Open(Path("/foo"), O_RDONLY, &node_)); 510 EXPECT_EQ(fd, sdk_util::static_scoped_ref_cast<JsFsNode>(node_)->fd()); 511 } 512 513 protected: 514 ScopedNode node_; 515 }; 516 517 const int JsFsNodeTest::fd = 123; 518 519 } // namespace 520 521 TEST_F(JsFsTest, Access) { 522 int a_mode = R_OK | W_OK | X_OK; 523 524 PP_Var expected; 525 ASSERT_EQ(true, CreateDict(&expected)); 526 ASSERT_EQ(true, SetDictKeyValue(&expected, "id", 1)); 527 ASSERT_EQ(true, SetDictKeyValue(&expected, "cmd", "access")); 528 ASSERT_EQ(true, SetDictKeyValue(&expected, "path", "/foo")); 529 ASSERT_EQ(true, SetDictKeyValue(&expected, "amode", a_mode)); 530 531 PP_Var response; 532 ASSERT_EQ(true, CreateDict(&response)); 533 ASSERT_EQ(true, SetDictKeyValue(&response, "id", 1)); 534 ASSERT_EQ(true, SetDictKeyValue(&response, "error", 0)); 535 536 Expect(expected, response); 537 StartJsThread(); 538 539 EXPECT_EQ(0, fs_->Access(Path("/foo"), a_mode)); 540 } 541 542 TEST_F(JsFsTest, Open) { 543 PP_Var expected; 544 ASSERT_EQ(true, CreateDict(&expected)); 545 ASSERT_EQ(true, SetDictKeyValue(&expected, "id", 1)); 546 ASSERT_EQ(true, SetDictKeyValue(&expected, "cmd", "open")); 547 ASSERT_EQ(true, SetDictKeyValue(&expected, "path", "/foo")); 548 ASSERT_EQ(true, SetDictKeyValue(&expected, "oflag", O_RDONLY)); 549 550 PP_Var response; 551 ASSERT_EQ(true, CreateDict(&response)); 552 ASSERT_EQ(true, SetDictKeyValue(&response, "id", 1)); 553 ASSERT_EQ(true, SetDictKeyValue(&response, "error", 0)); 554 ASSERT_EQ(true, SetDictKeyValue(&response, "fd", 123)); 555 556 Expect(expected, response); 557 StartJsThread(); 558 559 ScopedNode node; 560 EXPECT_EQ(0, fs_->Open(Path("/foo"), O_RDONLY, &node)); 561 EXPECT_EQ(123, sdk_util::static_scoped_ref_cast<JsFsNode>(node)->fd()); 562 } 563 564 TEST_F(JsFsTest, Unlink) { 565 PP_Var expected; 566 ASSERT_EQ(true, CreateDict(&expected)); 567 ASSERT_EQ(true, SetDictKeyValue(&expected, "id", 1)); 568 ASSERT_EQ(true, SetDictKeyValue(&expected, "cmd", "unlink")); 569 ASSERT_EQ(true, SetDictKeyValue(&expected, "path", "/foo")); 570 571 PP_Var response; 572 ASSERT_EQ(true, CreateDict(&response)); 573 ASSERT_EQ(true, SetDictKeyValue(&response, "id", 1)); 574 ASSERT_EQ(true, SetDictKeyValue(&response, "error", 0)); 575 576 Expect(expected, response); 577 StartJsThread(); 578 579 EXPECT_EQ(0, fs_->Unlink(Path("/foo"))); 580 } 581 582 TEST_F(JsFsTest, Mkdir) { 583 PP_Var expected; 584 ASSERT_EQ(true, CreateDict(&expected)); 585 ASSERT_EQ(true, SetDictKeyValue(&expected, "id", 1)); 586 ASSERT_EQ(true, SetDictKeyValue(&expected, "cmd", "mkdir")); 587 ASSERT_EQ(true, SetDictKeyValue(&expected, "path", "/foo")); 588 ASSERT_EQ(true, SetDictKeyValue(&expected, "mode", 0644)); 589 590 PP_Var response; 591 ASSERT_EQ(true, CreateDict(&response)); 592 ASSERT_EQ(true, SetDictKeyValue(&response, "id", 1)); 593 ASSERT_EQ(true, SetDictKeyValue(&response, "error", 0)); 594 595 Expect(expected, response); 596 StartJsThread(); 597 598 EXPECT_EQ(0, fs_->Mkdir(Path("/foo"), 0644)); 599 } 600 601 TEST_F(JsFsTest, Rmdir) { 602 PP_Var expected; 603 ASSERT_EQ(true, CreateDict(&expected)); 604 ASSERT_EQ(true, SetDictKeyValue(&expected, "id", 1)); 605 ASSERT_EQ(true, SetDictKeyValue(&expected, "cmd", "rmdir")); 606 ASSERT_EQ(true, SetDictKeyValue(&expected, "path", "/foo")); 607 608 PP_Var response; 609 ASSERT_EQ(true, CreateDict(&response)); 610 ASSERT_EQ(true, SetDictKeyValue(&response, "id", 1)); 611 ASSERT_EQ(true, SetDictKeyValue(&response, "error", 0)); 612 613 Expect(expected, response); 614 StartJsThread(); 615 616 EXPECT_EQ(0, fs_->Rmdir(Path("/foo"))); 617 } 618 619 TEST_F(JsFsTest, Remove) { 620 PP_Var expected; 621 ASSERT_EQ(true, CreateDict(&expected)); 622 ASSERT_EQ(true, SetDictKeyValue(&expected, "id", 1)); 623 ASSERT_EQ(true, SetDictKeyValue(&expected, "cmd", "remove")); 624 ASSERT_EQ(true, SetDictKeyValue(&expected, "path", "/foo")); 625 626 PP_Var response; 627 ASSERT_EQ(true, CreateDict(&response)); 628 ASSERT_EQ(true, SetDictKeyValue(&response, "id", 1)); 629 ASSERT_EQ(true, SetDictKeyValue(&response, "error", 0)); 630 631 Expect(expected, response); 632 StartJsThread(); 633 634 EXPECT_EQ(0, fs_->Remove(Path("/foo"))); 635 } 636 637 TEST_F(JsFsTest, Rename) { 638 PP_Var expected; 639 ASSERT_EQ(true, CreateDict(&expected)); 640 ASSERT_EQ(true, SetDictKeyValue(&expected, "id", 1)); 641 ASSERT_EQ(true, SetDictKeyValue(&expected, "cmd", "rename")); 642 ASSERT_EQ(true, SetDictKeyValue(&expected, "old", "/foo")); 643 ASSERT_EQ(true, SetDictKeyValue(&expected, "new", "/bar")); 644 645 PP_Var response; 646 ASSERT_EQ(true, CreateDict(&response)); 647 ASSERT_EQ(true, SetDictKeyValue(&response, "id", 1)); 648 ASSERT_EQ(true, SetDictKeyValue(&response, "error", 0)); 649 650 Expect(expected, response); 651 StartJsThread(); 652 653 EXPECT_EQ(0, fs_->Rename(Path("/foo"), Path("/bar"))); 654 } 655 656 TEST_F(JsFsNodeTest, GetStat) { 657 PP_Var expected; 658 ASSERT_EQ(true, CreateDict(&expected)); 659 ASSERT_EQ(true, SetDictKeyValue(&expected, "id", 2)); 660 ASSERT_EQ(true, SetDictKeyValue(&expected, "cmd", "fstat")); 661 ASSERT_EQ(true, SetDictKeyValue(&expected, "fildes", fd)); 662 663 PP_Var response; 664 ASSERT_EQ(true, CreateDict(&response)); 665 ASSERT_EQ(true, SetDictKeyValue(&response, "id", 2)); 666 ASSERT_EQ(true, SetDictKeyValue(&response, "error", 0)); 667 ASSERT_EQ(true, SetDictKeyValue(&response, "st_ino", (int64_t) 1)); 668 ASSERT_EQ(true, SetDictKeyValue(&response, "st_mode", 2)); 669 ASSERT_EQ(true, SetDictKeyValue(&response, "st_nlink", 3)); 670 ASSERT_EQ(true, SetDictKeyValue(&response, "st_uid", 4)); 671 ASSERT_EQ(true, SetDictKeyValue(&response, "st_gid", 5)); 672 ASSERT_EQ(true, SetDictKeyValue(&response, "st_rdev", (int64_t) 6)); 673 ASSERT_EQ(true, SetDictKeyValue(&response, "st_size", (int64_t) 7)); 674 ASSERT_EQ(true, SetDictKeyValue(&response, "st_blksize", 8)); 675 ASSERT_EQ(true, SetDictKeyValue(&response, "st_blocks", 9)); 676 ASSERT_EQ(true, SetDictKeyValue(&response, "st_atime", (int64_t) 10)); 677 ASSERT_EQ(true, SetDictKeyValue(&response, "st_mtime", (int64_t) 11)); 678 ASSERT_EQ(true, SetDictKeyValue(&response, "st_ctime", (int64_t) 12)); 679 680 Expect(expected, response); 681 StartJsThread(); 682 OpenNode(); 683 684 struct stat statbuf; 685 EXPECT_EQ(0, node_->GetStat(&statbuf)); 686 EXPECT_EQ(fs_->dev(), statbuf.st_dev); 687 EXPECT_EQ(1, statbuf.st_ino); 688 EXPECT_EQ(2, statbuf.st_mode); 689 EXPECT_EQ(3, statbuf.st_nlink); 690 EXPECT_EQ(4, statbuf.st_uid); 691 EXPECT_EQ(5, statbuf.st_gid); 692 EXPECT_EQ(6, statbuf.st_rdev); 693 EXPECT_EQ(7, statbuf.st_size); 694 EXPECT_EQ(8, statbuf.st_blksize); 695 EXPECT_EQ(9, statbuf.st_blocks); 696 EXPECT_EQ(10, statbuf.st_atime); 697 EXPECT_EQ(11, statbuf.st_mtime); 698 EXPECT_EQ(12, statbuf.st_ctime); 699 } 700 701 TEST_F(JsFsNodeTest, FSync) { 702 PP_Var expected; 703 ASSERT_EQ(true, CreateDict(&expected)); 704 ASSERT_EQ(true, SetDictKeyValue(&expected, "id", 2)); 705 ASSERT_EQ(true, SetDictKeyValue(&expected, "cmd", "fsync")); 706 ASSERT_EQ(true, SetDictKeyValue(&expected, "fildes", fd)); 707 708 PP_Var response; 709 ASSERT_EQ(true, CreateDict(&response)); 710 ASSERT_EQ(true, SetDictKeyValue(&response, "id", 2)); 711 ASSERT_EQ(true, SetDictKeyValue(&response, "error", 0)); 712 713 Expect(expected, response); 714 StartJsThread(); 715 OpenNode(); 716 717 EXPECT_EQ(0, node_->FSync()); 718 } 719 720 TEST_F(JsFsNodeTest, FTruncate) { 721 PP_Var expected; 722 ASSERT_EQ(true, CreateDict(&expected)); 723 ASSERT_EQ(true, SetDictKeyValue(&expected, "id", 2)); 724 ASSERT_EQ(true, SetDictKeyValue(&expected, "cmd", "ftruncate")); 725 ASSERT_EQ(true, SetDictKeyValue(&expected, "fildes", fd)); 726 ASSERT_EQ(true, SetDictKeyValue(&expected, "length", 0)); 727 728 PP_Var response; 729 ASSERT_EQ(true, CreateDict(&response)); 730 ASSERT_EQ(true, SetDictKeyValue(&response, "id", 2)); 731 ASSERT_EQ(true, SetDictKeyValue(&response, "error", 0)); 732 733 Expect(expected, response); 734 StartJsThread(); 735 OpenNode(); 736 737 EXPECT_EQ(0, node_->FTruncate(0)); 738 } 739 740 TEST_F(JsFsNodeTest, Read) { 741 const size_t kReadLength = 100; 742 743 PP_Var expected; 744 ASSERT_EQ(true, CreateDict(&expected)); 745 ASSERT_EQ(true, SetDictKeyValue(&expected, "id", 2)); 746 ASSERT_EQ(true, SetDictKeyValue(&expected, "cmd", "pread")); 747 ASSERT_EQ(true, SetDictKeyValue(&expected, "fildes", fd)); 748 ASSERT_EQ(true, 749 SetDictKeyValue(&expected, "nbyte", static_cast<int>(kReadLength))); 750 ASSERT_EQ(true, SetDictKeyValue(&expected, "offset", 200)); 751 752 PP_Var response; 753 ASSERT_EQ(true, CreateDict(&response)); 754 ASSERT_EQ(true, SetDictKeyValue(&response, "id", 2)); 755 ASSERT_EQ(true, SetDictKeyValue(&response, "error", 0)); 756 ASSERT_EQ( 757 true, 758 SetDictKeyValue(&response, "buf", CreateDummyArrayBuffer(kReadLength))); 759 760 Expect(expected, response); 761 StartJsThread(); 762 OpenNode(); 763 764 HandleAttr attr; 765 attr.offs = 200; 766 uint8_t buf[kReadLength]; 767 int bytes_read; 768 EXPECT_EQ(0, node_->Read(attr, buf, kReadLength, &bytes_read)); 769 EXPECT_EQ(kReadLength, bytes_read); 770 EXPECT_TRUE(EqualsDummyArrayBuffer(buf, kReadLength)); 771 } 772 773 TEST_F(JsFsNodeTest, Write) { 774 const size_t kWriteLength = 100; 775 776 PP_Var expected; 777 ASSERT_EQ(true, CreateDict(&expected)); 778 ASSERT_EQ(true, SetDictKeyValue(&expected, "id", 2)); 779 ASSERT_EQ(true, SetDictKeyValue(&expected, "cmd", "pwrite")); 780 ASSERT_EQ(true, SetDictKeyValue(&expected, "fildes", fd)); 781 ASSERT_EQ( 782 true, 783 SetDictKeyValue(&expected, "buf", CreateDummyArrayBuffer(kWriteLength))); 784 ASSERT_EQ( 785 true, 786 SetDictKeyValue(&expected, "nbyte", static_cast<int>(kWriteLength))); 787 ASSERT_EQ(true, SetDictKeyValue(&expected, "offset", 200)); 788 789 PP_Var response; 790 ASSERT_EQ(true, CreateDict(&response)); 791 ASSERT_EQ(true, SetDictKeyValue(&response, "id", 2)); 792 ASSERT_EQ(true, SetDictKeyValue(&response, "error", 0)); 793 ASSERT_EQ(true, SetDictKeyValue(&response, "nwrote", kWriteLength)); 794 795 Expect(expected, response); 796 StartJsThread(); 797 OpenNode(); 798 799 HandleAttr attr; 800 attr.offs = 200; 801 802 uint8_t buf[kWriteLength]; 803 FillDummyBuffer(buf, kWriteLength); 804 805 int bytes_written; 806 EXPECT_EQ(0, node_->Write(attr, buf, kWriteLength, &bytes_written)); 807 EXPECT_EQ(kWriteLength, bytes_written); 808 } 809 810 TEST_F(JsFsNodeTest, GetDents) { 811 PP_Var expected; 812 ASSERT_EQ(true, CreateDict(&expected)); 813 ASSERT_EQ(true, SetDictKeyValue(&expected, "id", 2)); 814 ASSERT_EQ(true, SetDictKeyValue(&expected, "cmd", "getdents")); 815 ASSERT_EQ(true, SetDictKeyValue(&expected, "fildes", fd)); 816 ASSERT_EQ(true, SetDictKeyValue(&expected, "offs", 0)); 817 ASSERT_EQ(true, SetDictKeyValue(&expected, "count", 2)); 818 819 PP_Var entry0; 820 ASSERT_EQ(true, CreateDict(&entry0)); 821 ASSERT_EQ(true, SetDictKeyValue(&entry0, "d_ino", 2)); 822 ASSERT_EQ(true, SetDictKeyValue(&entry0, "d_name", ".")); 823 PP_Var entry1; 824 ASSERT_EQ(true, CreateDict(&entry1)); 825 ASSERT_EQ(true, SetDictKeyValue(&entry1, "d_ino", 3)); 826 ASSERT_EQ(true, SetDictKeyValue(&entry1, "d_name", "..")); 827 PP_Var array; 828 ASSERT_EQ(true, CreateArray(&array)); 829 ASSERT_EQ(true, SetArrayValue(&array, 0, entry0)); 830 ASSERT_EQ(true, SetArrayValue(&array, 1, entry1)); 831 PP_Var response; 832 ASSERT_EQ(true, CreateDict(&response)); 833 ASSERT_EQ(true, SetDictKeyValue(&response, "id", 2)); 834 ASSERT_EQ(true, SetDictKeyValue(&response, "error", 0)); 835 ASSERT_EQ(true, SetDictKeyValue(&response, "dirents", array)); 836 837 Expect(expected, response); 838 StartJsThread(); 839 OpenNode(); 840 841 dirent buf[2]; 842 int bytes_written; 843 EXPECT_EQ(0, node_->GetDents(0, buf, sizeof(dirent) * 2, &bytes_written)); 844 EXPECT_EQ(sizeof(dirent) * 2, bytes_written); 845 EXPECT_EQ(2, buf[0].d_ino); 846 EXPECT_EQ(sizeof(dirent), buf[0].d_off); 847 EXPECT_EQ(sizeof(dirent), buf[0].d_reclen); 848 EXPECT_STREQ(".", buf[0].d_name); 849 EXPECT_EQ(3, buf[1].d_ino); 850 EXPECT_EQ(sizeof(dirent), buf[1].d_off); 851 EXPECT_EQ(sizeof(dirent), buf[1].d_reclen); 852 EXPECT_STREQ("..", buf[1].d_name); 853 } 854