Home | History | Annotate | Download | only in nacl_io_test
      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