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 30using namespace nacl_io; 31using namespace sdk_util; 32 33namespace { 34 35class 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 45class 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 83class 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 95class 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 481class 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 517const int JsFsNodeTest::fd = 123; 518 519} // namespace 520 521TEST_F(JsFsTest, Open) { 522 PP_Var expected; 523 ASSERT_EQ(true, CreateDict(&expected)); 524 ASSERT_EQ(true, SetDictKeyValue(&expected, "id", 1)); 525 ASSERT_EQ(true, SetDictKeyValue(&expected, "cmd", "open")); 526 ASSERT_EQ(true, SetDictKeyValue(&expected, "path", "/foo")); 527 ASSERT_EQ(true, SetDictKeyValue(&expected, "oflag", O_RDONLY)); 528 529 PP_Var response; 530 ASSERT_EQ(true, CreateDict(&response)); 531 ASSERT_EQ(true, SetDictKeyValue(&response, "id", 1)); 532 ASSERT_EQ(true, SetDictKeyValue(&response, "error", 0)); 533 ASSERT_EQ(true, SetDictKeyValue(&response, "fd", 123)); 534 535 Expect(expected, response); 536 StartJsThread(); 537 538 ScopedNode node; 539 EXPECT_EQ(0, fs_->Open(Path("/foo"), O_RDONLY, &node)); 540 EXPECT_EQ(123, sdk_util::static_scoped_ref_cast<JsFsNode>(node)->fd()); 541} 542 543TEST_F(JsFsTest, Unlink) { 544 PP_Var expected; 545 ASSERT_EQ(true, CreateDict(&expected)); 546 ASSERT_EQ(true, SetDictKeyValue(&expected, "id", 1)); 547 ASSERT_EQ(true, SetDictKeyValue(&expected, "cmd", "unlink")); 548 ASSERT_EQ(true, SetDictKeyValue(&expected, "path", "/foo")); 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 555 Expect(expected, response); 556 StartJsThread(); 557 558 EXPECT_EQ(0, fs_->Unlink(Path("/foo"))); 559} 560 561TEST_F(JsFsTest, Mkdir) { 562 PP_Var expected; 563 ASSERT_EQ(true, CreateDict(&expected)); 564 ASSERT_EQ(true, SetDictKeyValue(&expected, "id", 1)); 565 ASSERT_EQ(true, SetDictKeyValue(&expected, "cmd", "mkdir")); 566 ASSERT_EQ(true, SetDictKeyValue(&expected, "path", "/foo")); 567 ASSERT_EQ(true, SetDictKeyValue(&expected, "mode", 0644)); 568 569 PP_Var response; 570 ASSERT_EQ(true, CreateDict(&response)); 571 ASSERT_EQ(true, SetDictKeyValue(&response, "id", 1)); 572 ASSERT_EQ(true, SetDictKeyValue(&response, "error", 0)); 573 574 Expect(expected, response); 575 StartJsThread(); 576 577 EXPECT_EQ(0, fs_->Mkdir(Path("/foo"), 0644)); 578} 579 580TEST_F(JsFsTest, Rmdir) { 581 PP_Var expected; 582 ASSERT_EQ(true, CreateDict(&expected)); 583 ASSERT_EQ(true, SetDictKeyValue(&expected, "id", 1)); 584 ASSERT_EQ(true, SetDictKeyValue(&expected, "cmd", "rmdir")); 585 ASSERT_EQ(true, SetDictKeyValue(&expected, "path", "/foo")); 586 587 PP_Var response; 588 ASSERT_EQ(true, CreateDict(&response)); 589 ASSERT_EQ(true, SetDictKeyValue(&response, "id", 1)); 590 ASSERT_EQ(true, SetDictKeyValue(&response, "error", 0)); 591 592 Expect(expected, response); 593 StartJsThread(); 594 595 EXPECT_EQ(0, fs_->Rmdir(Path("/foo"))); 596} 597 598TEST_F(JsFsTest, Remove) { 599 PP_Var expected; 600 ASSERT_EQ(true, CreateDict(&expected)); 601 ASSERT_EQ(true, SetDictKeyValue(&expected, "id", 1)); 602 ASSERT_EQ(true, SetDictKeyValue(&expected, "cmd", "remove")); 603 ASSERT_EQ(true, SetDictKeyValue(&expected, "path", "/foo")); 604 605 PP_Var response; 606 ASSERT_EQ(true, CreateDict(&response)); 607 ASSERT_EQ(true, SetDictKeyValue(&response, "id", 1)); 608 ASSERT_EQ(true, SetDictKeyValue(&response, "error", 0)); 609 610 Expect(expected, response); 611 StartJsThread(); 612 613 EXPECT_EQ(0, fs_->Remove(Path("/foo"))); 614} 615 616TEST_F(JsFsTest, Rename) { 617 PP_Var expected; 618 ASSERT_EQ(true, CreateDict(&expected)); 619 ASSERT_EQ(true, SetDictKeyValue(&expected, "id", 1)); 620 ASSERT_EQ(true, SetDictKeyValue(&expected, "cmd", "rename")); 621 ASSERT_EQ(true, SetDictKeyValue(&expected, "old", "/foo")); 622 ASSERT_EQ(true, SetDictKeyValue(&expected, "new", "/bar")); 623 624 PP_Var response; 625 ASSERT_EQ(true, CreateDict(&response)); 626 ASSERT_EQ(true, SetDictKeyValue(&response, "id", 1)); 627 ASSERT_EQ(true, SetDictKeyValue(&response, "error", 0)); 628 629 Expect(expected, response); 630 StartJsThread(); 631 632 EXPECT_EQ(0, fs_->Rename(Path("/foo"), Path("/bar"))); 633} 634 635TEST_F(JsFsNodeTest, GetStat) { 636 PP_Var expected; 637 ASSERT_EQ(true, CreateDict(&expected)); 638 ASSERT_EQ(true, SetDictKeyValue(&expected, "id", 2)); 639 ASSERT_EQ(true, SetDictKeyValue(&expected, "cmd", "fstat")); 640 ASSERT_EQ(true, SetDictKeyValue(&expected, "fildes", fd)); 641 642 PP_Var response; 643 ASSERT_EQ(true, CreateDict(&response)); 644 ASSERT_EQ(true, SetDictKeyValue(&response, "id", 2)); 645 ASSERT_EQ(true, SetDictKeyValue(&response, "error", 0)); 646 ASSERT_EQ(true, SetDictKeyValue(&response, "st_ino", (int64_t) 1)); 647 ASSERT_EQ(true, SetDictKeyValue(&response, "st_mode", 2)); 648 ASSERT_EQ(true, SetDictKeyValue(&response, "st_nlink", 3)); 649 ASSERT_EQ(true, SetDictKeyValue(&response, "st_uid", 4)); 650 ASSERT_EQ(true, SetDictKeyValue(&response, "st_gid", 5)); 651 ASSERT_EQ(true, SetDictKeyValue(&response, "st_rdev", (int64_t) 6)); 652 ASSERT_EQ(true, SetDictKeyValue(&response, "st_size", (int64_t) 7)); 653 ASSERT_EQ(true, SetDictKeyValue(&response, "st_blksize", 8)); 654 ASSERT_EQ(true, SetDictKeyValue(&response, "st_blocks", 9)); 655 ASSERT_EQ(true, SetDictKeyValue(&response, "st_atime", (int64_t) 10)); 656 ASSERT_EQ(true, SetDictKeyValue(&response, "st_mtime", (int64_t) 11)); 657 ASSERT_EQ(true, SetDictKeyValue(&response, "st_ctime", (int64_t) 12)); 658 659 Expect(expected, response); 660 StartJsThread(); 661 OpenNode(); 662 663 struct stat statbuf; 664 EXPECT_EQ(0, node_->GetStat(&statbuf)); 665 EXPECT_EQ(fs_->dev(), statbuf.st_dev); 666 EXPECT_EQ(1, statbuf.st_ino); 667 EXPECT_EQ(2, statbuf.st_mode); 668 EXPECT_EQ(3, statbuf.st_nlink); 669 EXPECT_EQ(4, statbuf.st_uid); 670 EXPECT_EQ(5, statbuf.st_gid); 671 EXPECT_EQ(6, statbuf.st_rdev); 672 EXPECT_EQ(7, statbuf.st_size); 673 EXPECT_EQ(8, statbuf.st_blksize); 674 EXPECT_EQ(9, statbuf.st_blocks); 675 EXPECT_EQ(10, statbuf.st_atime); 676 EXPECT_EQ(11, statbuf.st_mtime); 677 EXPECT_EQ(12, statbuf.st_ctime); 678} 679 680TEST_F(JsFsNodeTest, FSync) { 681 PP_Var expected; 682 ASSERT_EQ(true, CreateDict(&expected)); 683 ASSERT_EQ(true, SetDictKeyValue(&expected, "id", 2)); 684 ASSERT_EQ(true, SetDictKeyValue(&expected, "cmd", "fsync")); 685 ASSERT_EQ(true, SetDictKeyValue(&expected, "fildes", fd)); 686 687 PP_Var response; 688 ASSERT_EQ(true, CreateDict(&response)); 689 ASSERT_EQ(true, SetDictKeyValue(&response, "id", 2)); 690 ASSERT_EQ(true, SetDictKeyValue(&response, "error", 0)); 691 692 Expect(expected, response); 693 StartJsThread(); 694 OpenNode(); 695 696 EXPECT_EQ(0, node_->FSync()); 697} 698 699TEST_F(JsFsNodeTest, FTruncate) { 700 PP_Var expected; 701 ASSERT_EQ(true, CreateDict(&expected)); 702 ASSERT_EQ(true, SetDictKeyValue(&expected, "id", 2)); 703 ASSERT_EQ(true, SetDictKeyValue(&expected, "cmd", "ftruncate")); 704 ASSERT_EQ(true, SetDictKeyValue(&expected, "fildes", fd)); 705 ASSERT_EQ(true, SetDictKeyValue(&expected, "length", 0)); 706 707 PP_Var response; 708 ASSERT_EQ(true, CreateDict(&response)); 709 ASSERT_EQ(true, SetDictKeyValue(&response, "id", 2)); 710 ASSERT_EQ(true, SetDictKeyValue(&response, "error", 0)); 711 712 Expect(expected, response); 713 StartJsThread(); 714 OpenNode(); 715 716 EXPECT_EQ(0, node_->FTruncate(0)); 717} 718 719TEST_F(JsFsNodeTest, Read) { 720 const size_t kReadLength = 100; 721 722 PP_Var expected; 723 ASSERT_EQ(true, CreateDict(&expected)); 724 ASSERT_EQ(true, SetDictKeyValue(&expected, "id", 2)); 725 ASSERT_EQ(true, SetDictKeyValue(&expected, "cmd", "pread")); 726 ASSERT_EQ(true, SetDictKeyValue(&expected, "fildes", fd)); 727 ASSERT_EQ(true, 728 SetDictKeyValue(&expected, "nbyte", static_cast<int>(kReadLength))); 729 ASSERT_EQ(true, SetDictKeyValue(&expected, "offset", 200)); 730 731 PP_Var response; 732 ASSERT_EQ(true, CreateDict(&response)); 733 ASSERT_EQ(true, SetDictKeyValue(&response, "id", 2)); 734 ASSERT_EQ(true, SetDictKeyValue(&response, "error", 0)); 735 ASSERT_EQ( 736 true, 737 SetDictKeyValue(&response, "buf", CreateDummyArrayBuffer(kReadLength))); 738 739 Expect(expected, response); 740 StartJsThread(); 741 OpenNode(); 742 743 HandleAttr attr; 744 attr.offs = 200; 745 uint8_t buf[kReadLength]; 746 int bytes_read; 747 EXPECT_EQ(0, node_->Read(attr, buf, kReadLength, &bytes_read)); 748 EXPECT_EQ(kReadLength, bytes_read); 749 EXPECT_TRUE(EqualsDummyArrayBuffer(buf, kReadLength)); 750} 751 752TEST_F(JsFsNodeTest, Write) { 753 const size_t kWriteLength = 100; 754 755 PP_Var expected; 756 ASSERT_EQ(true, CreateDict(&expected)); 757 ASSERT_EQ(true, SetDictKeyValue(&expected, "id", 2)); 758 ASSERT_EQ(true, SetDictKeyValue(&expected, "cmd", "pwrite")); 759 ASSERT_EQ(true, SetDictKeyValue(&expected, "fildes", fd)); 760 ASSERT_EQ( 761 true, 762 SetDictKeyValue(&expected, "buf", CreateDummyArrayBuffer(kWriteLength))); 763 ASSERT_EQ( 764 true, 765 SetDictKeyValue(&expected, "nbyte", static_cast<int>(kWriteLength))); 766 ASSERT_EQ(true, SetDictKeyValue(&expected, "offset", 200)); 767 768 PP_Var response; 769 ASSERT_EQ(true, CreateDict(&response)); 770 ASSERT_EQ(true, SetDictKeyValue(&response, "id", 2)); 771 ASSERT_EQ(true, SetDictKeyValue(&response, "error", 0)); 772 ASSERT_EQ(true, SetDictKeyValue(&response, "nwrote", kWriteLength)); 773 774 Expect(expected, response); 775 StartJsThread(); 776 OpenNode(); 777 778 HandleAttr attr; 779 attr.offs = 200; 780 781 uint8_t buf[kWriteLength]; 782 FillDummyBuffer(buf, kWriteLength); 783 784 int bytes_written; 785 EXPECT_EQ(0, node_->Write(attr, buf, kWriteLength, &bytes_written)); 786 EXPECT_EQ(kWriteLength, bytes_written); 787} 788 789TEST_F(JsFsNodeTest, GetDents) { 790 PP_Var expected; 791 ASSERT_EQ(true, CreateDict(&expected)); 792 ASSERT_EQ(true, SetDictKeyValue(&expected, "id", 2)); 793 ASSERT_EQ(true, SetDictKeyValue(&expected, "cmd", "getdents")); 794 ASSERT_EQ(true, SetDictKeyValue(&expected, "fildes", fd)); 795 ASSERT_EQ(true, SetDictKeyValue(&expected, "offs", 0)); 796 ASSERT_EQ(true, SetDictKeyValue(&expected, "count", 2)); 797 798 PP_Var entry0; 799 ASSERT_EQ(true, CreateDict(&entry0)); 800 ASSERT_EQ(true, SetDictKeyValue(&entry0, "d_ino", 2)); 801 ASSERT_EQ(true, SetDictKeyValue(&entry0, "d_name", ".")); 802 PP_Var entry1; 803 ASSERT_EQ(true, CreateDict(&entry1)); 804 ASSERT_EQ(true, SetDictKeyValue(&entry1, "d_ino", 3)); 805 ASSERT_EQ(true, SetDictKeyValue(&entry1, "d_name", "..")); 806 PP_Var array; 807 ASSERT_EQ(true, CreateArray(&array)); 808 ASSERT_EQ(true, SetArrayValue(&array, 0, entry0)); 809 ASSERT_EQ(true, SetArrayValue(&array, 1, entry1)); 810 PP_Var response; 811 ASSERT_EQ(true, CreateDict(&response)); 812 ASSERT_EQ(true, SetDictKeyValue(&response, "id", 2)); 813 ASSERT_EQ(true, SetDictKeyValue(&response, "error", 0)); 814 ASSERT_EQ(true, SetDictKeyValue(&response, "dirents", array)); 815 816 Expect(expected, response); 817 StartJsThread(); 818 OpenNode(); 819 820 dirent buf[2]; 821 int bytes_written; 822 EXPECT_EQ(0, node_->GetDents(0, buf, sizeof(dirent) * 2, &bytes_written)); 823 EXPECT_EQ(sizeof(dirent) * 2, bytes_written); 824 EXPECT_EQ(2, buf[0].d_ino); 825 EXPECT_EQ(sizeof(dirent), buf[0].d_off); 826 EXPECT_EQ(sizeof(dirent), buf[0].d_reclen); 827 EXPECT_STREQ(".", buf[0].d_name); 828 EXPECT_EQ(3, buf[1].d_ino); 829 EXPECT_EQ(sizeof(dirent), buf[1].d_off); 830 EXPECT_EQ(sizeof(dirent), buf[1].d_reclen); 831 EXPECT_STREQ("..", buf[1].d_name); 832} 833