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, 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 
    543 TEST_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 
    561 TEST_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 
    580 TEST_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 
    598 TEST_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 
    616 TEST_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 
    635 TEST_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 
    680 TEST_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 
    699 TEST_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 
    719 TEST_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 
    752 TEST_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 
    789 TEST_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