js_fs_test.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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, 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
542TEST_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
564TEST_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
582TEST_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
601TEST_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
619TEST_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
637TEST_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
656TEST_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
701TEST_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
720TEST_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
740TEST_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
773TEST_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
810TEST_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