blob: 047fe5f29ef665fdb4841ddc98b2ec21cf4ca3a5 [file] [log] [blame] [edit]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/developer/shell/josh/lib/runtime.h"
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/memfs/memfs.h>
#include <filesystem>
#include <fstream>
#include <string>
#include <gtest/gtest.h>
#include "src/developer/shell/josh/lib/js_testing_utils.h"
#include "third_party/quickjs/quickjs.h"
namespace fs = std::filesystem;
namespace shell {
class RuntimeTest : public JsTest {
protected:
void SetUp() override {
JsTest::SetUp();
// Always enable STD libraries
if (!ctx_->InitStd()) {
ctx_->DumpError();
FAIL();
}
loop_ = std::make_unique<async::Loop>(&kAsyncLoopConfigNoAttachToCurrentThread);
ASSERT_EQ(loop_->StartThread(), ZX_OK);
ASSERT_EQ(ZX_OK, memfs_install_at(loop_->dispatcher(), "/test_tmp", &fs_));
// Make sure file creation is OK so memfs is running OK.
char tmpfs_test_file[] = "/test_tmp/runtime.test.XXXXXX";
ASSERT_NE(mkstemp(tmpfs_test_file), -1);
}
void TearDown() override {
// Synchronously clean up.
sync_completion_t unmounted;
memfs_free_filesystem(fs_, &unmounted);
sync_completion_wait(&unmounted, zx::duration::infinite().get());
fs_ = nullptr;
loop_->Shutdown();
JsTest::TearDown();
}
std::unique_ptr<async::Loop> loop_;
memfs_filesystem_t *fs_;
};
TEST_F(RuntimeTest, TestNonExistsStartupScriptsDir) {
// Going to add startup scripts under this path
std::string startup_path("/test_tmp/js_startup");
ASSERT_EQ(false, fs::is_directory(startup_path));
// Load startup scripts from a directory that doesn't exist
ASSERT_EQ(false, ctx_->InitStartups(startup_path));
}
TEST_F(RuntimeTest, TestEmptyStartupScriptsDir) {
// Going to add startup scripts under this path
std::string startup_path("/test_tmp/js_startup");
// Create a directory for startup scripts
ASSERT_EQ(true, fs::create_directory(startup_path));
ASSERT_EQ(true, fs::is_directory(startup_path));
// Load startup scripts from an empty directory
// load nothing when sequence.json doesn't exist
ASSERT_EQ(true, ctx_->InitStartups(startup_path));
}
TEST_F(RuntimeTest, TestStartupScripts) {
// Create a directory for startup scripts
std::string startup_path("/test_tmp/js_startup");
ASSERT_EQ(true, fs::create_directory(startup_path));
ASSERT_EQ(true, fs::is_directory(startup_path));
std::ofstream test_script;
#define WRITE_ORDER_FILE_JS(val) \
do { \
test_script << "let file = std.open('/test_tmp/js_startup/orders', 'a+');" << std::endl; \
test_script << "file.puts('" << val << ",');" << std::endl; \
test_script << "file.close();" << std::endl; \
test_script << "export { GetValue }" << std::endl; \
test_script.close(); \
} while (0)
// Create name.js which returns "value" when GetValue is called
#define WRITE_MODULE_JS(name, value) \
do { \
test_script.open(startup_path + "/" name ".js"); \
test_script << "function GetValue() { return " << value << "; }" << std::endl; \
WRITE_ORDER_FILE_JS(value); \
} while (0)
// Add startup scripts into the directory
WRITE_MODULE_JS("module3", 3); // module3.js
WRITE_MODULE_JS("Module4", 4); // module4.js
WRITE_MODULE_JS("module5", 5); // module5.js
WRITE_MODULE_JS("MODULE2", 2); // module2.js
WRITE_MODULE_JS("module1", 1); // module1.js
WRITE_MODULE_JS("_module6", 6); // module6.js
std::ofstream test_sequence_json;
test_sequence_json.open(startup_path + "/startup.json");
test_sequence_json << R"(
{
"startup": [
"module1.js",
"MODULE2.js",
"../js_startup/module3.js",
"Module4.js",
"_module6.js"
]
}
)" << std::endl;
test_sequence_json.close();
// Load startup scripts
ASSERT_EQ(true, ctx_->InitStartups(startup_path));
// Validate the results
ASSERT_EVAL(ctx_, R"(
// Make sure modules are loaded correctly
validations = [
[module1.GetValue, 1],
[MODULE2.GetValue, 2],
[module3.GetValue, 3],
[Module4.GetValue, 4],
[_module6.GetValue, 6],
];
for ([func, value] of validations) {
if (func() != value) {
throw `Module loaded incorrectly! Expecting ${value}, got ${func()}`;
}
}
// Expect startup scripts to run in the correct order
validation_string = "1,2,3,4,6,";
file = std.open('/test_tmp/js_startup/orders', 'r+');
read_string = file.readAsString();
if (read_string != validation_string) {
throw `Modules loaded in incorrect order! Expecting ${validation_string}, got ${read_string}`;
}
file.close();
)"));
loop_->RunUntilIdle();
}
} // namespace shell