Skip to content

test: move WasmVm tests into wasm_vm_test. #275

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ cc_library(
"//bazel:crypto_system": [],
"//conditions:default": ["@boringssl//:crypto"],
}),
alwayslink = 1,
)

cc_library(
Expand Down
3 changes: 3 additions & 0 deletions src/exports.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@

namespace proxy_wasm {

thread_local ContextBase *current_context_;
thread_local uint32_t effective_context_id_ = 0;

// Any currently executing Wasm call context.
ContextBase *contextOrEffectiveContext() {
if (effective_context_id_ == 0) {
Expand Down
3 changes: 0 additions & 3 deletions src/wasm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,6 @@

namespace proxy_wasm {

thread_local ContextBase *current_context_;
thread_local uint32_t effective_context_id_ = 0;

namespace {

// Map from Wasm Key to the local Wasm instance.
Expand Down
16 changes: 15 additions & 1 deletion test/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ cc_test(
name = "runtime_test",
srcs = ["runtime_test.cc"],
data = [
"//test/test_data:abi_export.wasm",
"//test/test_data:callback.wasm",
"//test/test_data:clock.wasm",
"//test/test_data:infinite_loop.wasm",
Expand Down Expand Up @@ -133,6 +132,21 @@ cc_test(
],
)

cc_test(
name = "wasm_vm_test",
srcs = ["wasm_vm_test.cc"],
data = [
"//test/test_data:abi_export.wasm",
],
linkstatic = 1,
deps = [
":utility_lib",
"//:lib",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
)

cc_library(
name = "utility_lib",
testonly = True,
Expand Down
254 changes: 72 additions & 182 deletions test/runtime_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,9 @@

#include "gtest/gtest.h"

#include <fstream>
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include <thread>
#include <vector>

#include "include/proxy-wasm/context.h"
#include "include/proxy-wasm/wasm.h"
Expand All @@ -35,137 +31,26 @@ INSTANTIATE_TEST_SUITE_P(WasmEngines, TestVm, testing::ValuesIn(getWasmEngines()
return info.param;
});

TEST_P(TestVm, Basic) {
if (engine_ == "wamr") {
EXPECT_EQ(vm_->cloneable(), proxy_wasm::Cloneable::NotCloneable);
} else if (engine_ == "wasmtime" || engine_ == "v8") {
EXPECT_EQ(vm_->cloneable(), proxy_wasm::Cloneable::CompiledBytecode);
} else if (engine_ == "wavm") {
EXPECT_EQ(vm_->cloneable(), proxy_wasm::Cloneable::InstantiatedModule);
} else {
FAIL();
}
EXPECT_EQ(vm_->getEngineName(), engine_);
}

TEST_P(TestVm, Memory) {
auto source = readTestWasmFile("abi_export.wasm");
ASSERT_TRUE(vm_->load(source, {}, {}));
ASSERT_TRUE(vm_->link(""));

Word word;
ASSERT_TRUE(vm_->setWord(0x2000, Word(100)));
ASSERT_TRUE(vm_->getWord(0x2000, &word));
ASSERT_EQ(100, word.u64_);

uint32_t data[2] = {htowasm(static_cast<uint32_t>(-1)), htowasm(200)};
ASSERT_TRUE(vm_->setMemory(0x200, sizeof(int32_t) * 2, static_cast<void *>(data)));
ASSERT_TRUE(vm_->getWord(0x200, &word));
ASSERT_EQ(-1, static_cast<int32_t>(word.u64_));
ASSERT_TRUE(vm_->getWord(0x204, &word));
ASSERT_EQ(200, static_cast<int32_t>(word.u64_));
}

TEST_P(TestVm, Clone) {
if (vm_->cloneable() == proxy_wasm::Cloneable::NotCloneable) {
return;
}
auto source = readTestWasmFile("abi_export.wasm");
ASSERT_TRUE(vm_->load(source, {}, {}));
ASSERT_TRUE(vm_->link(""));
const auto address = 0x2000;
Word word;
{
auto clone = vm_->clone();
ASSERT_TRUE(clone != nullptr);
ASSERT_NE(vm_, clone);
if (clone->cloneable() != proxy_wasm::Cloneable::InstantiatedModule) {
ASSERT_TRUE(clone->link(""));
}

ASSERT_TRUE(clone->setWord(address, Word(100)));
ASSERT_TRUE(clone->getWord(address, &word));
ASSERT_EQ(100, word.u64_);
}

// check memory arrays are not overrapped
ASSERT_TRUE(vm_->getWord(address, &word));
ASSERT_NE(100, word.u64_);
}

#if defined(__linux__) && defined(__x86_64__)

TEST_P(TestVm, CloneUntilOutOfMemory) {
if (vm_->cloneable() == proxy_wasm::Cloneable::NotCloneable) {
return;
}
if (engine_ == "wavm") {
// TODO(PiotrSikora): Figure out why this fails on the CI.
return;
}

auto source = readTestWasmFile("abi_export.wasm");
ASSERT_TRUE(vm_->load(source, {}, {}));
ASSERT_TRUE(vm_->link(""));

size_t max_clones = 100000;
#if defined(__has_feature)
#if __has_feature(address_sanitizer)
max_clones = 1000;
#endif
#endif

std::vector<std::unique_ptr<WasmVm>> clones;
for (size_t i = 0; i < max_clones; i++) {
auto clone = vm_->clone();
if (clone == nullptr) {
break;
}
if (clone->cloneable() != proxy_wasm::Cloneable::InstantiatedModule) {
if (!clone->link("")) {
break;
}
}
// Prevent clone from droping out of scope and freeing memory.
clones.push_back(std::move(clone));
}

size_t min_clones = 1000;
#if defined(__has_feature)
#if __has_feature(thread_sanitizer)
min_clones = 100;
#endif
#endif
EXPECT_GE(clones.size(), min_clones);
}

#endif

class TestCounterContext : public TestContext {
public:
TestCounterContext(WasmBase *wasm) : TestContext(wasm) {}

void increment() { counter++; }
size_t getCount() { return counter; }

private:
size_t counter = 0;
};
TEST_P(TestVm, BadSignature) {
auto source = readTestWasmFile("clock.wasm");
ASSERT_FALSE(source.empty());
auto wasm = TestWasm(std::move(vm_));
ASSERT_TRUE(wasm.load(source, false));
ASSERT_TRUE(wasm.initialize());

class TestCounterWasm : public TestWasm {
public:
TestCounterWasm(std::unique_ptr<WasmVm> wasm_vm) : TestWasm(std::move(wasm_vm)) {}
WasmCallVoid<0> non_existent;
wasm.wasm_vm()->getFunction("non_existent", &non_existent);
EXPECT_TRUE(non_existent == nullptr);

ContextBase *createVmContext() override { return new TestCounterContext(this); };
};
WasmCallWord<2> bad_signature_run;
wasm.wasm_vm()->getFunction("run", &bad_signature_run);
EXPECT_TRUE(bad_signature_run == nullptr);

void callback() {
auto *context = dynamic_cast<TestCounterContext *>(contextOrEffectiveContext());
context->increment();
WasmCallVoid<0> run;
wasm.wasm_vm()->getFunction("run", &run);
ASSERT_TRUE(run != nullptr);
}

Word callback2(Word val) { return val + 100; }

TEST_P(TestVm, StraceLogLevel) {
if (engine_ == "wavm") {
// TODO(mathetake): strace is yet to be implemented for WAVM.
Expand Down Expand Up @@ -196,58 +81,6 @@ TEST_P(TestVm, StraceLogLevel) {
EXPECT_TRUE(host->isTraceLogged("[host<-vm] run return: void"));
}

TEST_P(TestVm, BadExportFunction) {
auto source = readTestWasmFile("clock.wasm");
ASSERT_FALSE(source.empty());
auto wasm = TestWasm(std::move(vm_));
ASSERT_TRUE(wasm.load(source, false));
ASSERT_TRUE(wasm.initialize());

WasmCallVoid<0> non_existent;
wasm.wasm_vm()->getFunction("non_existent", &non_existent);
EXPECT_TRUE(non_existent == nullptr);

WasmCallWord<2> bad_signature_run;
wasm.wasm_vm()->getFunction("run", &bad_signature_run);
EXPECT_TRUE(bad_signature_run == nullptr);

WasmCallVoid<0> run;
wasm.wasm_vm()->getFunction("run", &run);
ASSERT_TRUE(run != nullptr);
}

TEST_P(TestVm, Callback) {
auto source = readTestWasmFile("callback.wasm");
ASSERT_FALSE(source.empty());
auto wasm = TestCounterWasm(std::move(vm_));
ASSERT_TRUE(wasm.load(source, false));

wasm.wasm_vm()->registerCallback(
"env", "callback", &callback,
&ConvertFunctionWordToUint32<decltype(callback), callback>::convertFunctionWordToUint32);

wasm.wasm_vm()->registerCallback(
"env", "callback2", &callback2,
&ConvertFunctionWordToUint32<decltype(callback2), callback2>::convertFunctionWordToUint32);

ASSERT_TRUE(wasm.initialize());

WasmCallVoid<0> run;
wasm.wasm_vm()->getFunction("run", &run);
ASSERT_TRUE(run != nullptr);
for (auto i = 0; i < 5; i++) {
run(wasm.vm_context());
}
auto *context = dynamic_cast<TestCounterContext *>(wasm.vm_context());
EXPECT_EQ(context->getCount(), 5);

WasmCallWord<1> run2;
wasm.wasm_vm()->getFunction("run2", &run2);
ASSERT_TRUE(run2 != nullptr);
Word res = run2(wasm.vm_context(), Word{0});
EXPECT_EQ(res.u32(), 100100); // 10000 (global) + 100 (in callback)
}

TEST_P(TestVm, TerminateExecution) {
// TODO(chaoqin-li1123): implement execution termination for other runtime.
if (engine_ != "v8") {
Expand Down Expand Up @@ -329,5 +162,62 @@ TEST_P(TestVm, Trap2) {
}
}

class TestCounterContext : public TestContext {
public:
TestCounterContext(WasmBase *wasm) : TestContext(wasm) {}

void increment() { counter++; }
size_t getCount() { return counter; }

private:
size_t counter = 0;
};

class TestCounterWasm : public TestWasm {
public:
TestCounterWasm(std::unique_ptr<WasmVm> wasm_vm) : TestWasm(std::move(wasm_vm)) {}

ContextBase *createVmContext() override { return new TestCounterContext(this); };
};

void callback() {
auto *context = dynamic_cast<TestCounterContext *>(contextOrEffectiveContext());
context->increment();
}

Word callback2(Word val) { return val + 100; }

TEST_P(TestVm, Callback) {
auto source = readTestWasmFile("callback.wasm");
ASSERT_FALSE(source.empty());
auto wasm = TestCounterWasm(std::move(vm_));
ASSERT_TRUE(wasm.load(source, false));

wasm.wasm_vm()->registerCallback(
"env", "callback", &callback,
&ConvertFunctionWordToUint32<decltype(callback), callback>::convertFunctionWordToUint32);

wasm.wasm_vm()->registerCallback(
"env", "callback2", &callback2,
&ConvertFunctionWordToUint32<decltype(callback2), callback2>::convertFunctionWordToUint32);

ASSERT_TRUE(wasm.initialize());

WasmCallVoid<0> run;
wasm.wasm_vm()->getFunction("run", &run);
ASSERT_TRUE(run != nullptr);
for (auto i = 0; i < 5; i++) {
run(wasm.vm_context());
}
auto *context = dynamic_cast<TestCounterContext *>(wasm.vm_context());
EXPECT_EQ(context->getCount(), 5);

WasmCallWord<1> run2;
wasm.wasm_vm()->getFunction("run2", &run2);
ASSERT_TRUE(run2 != nullptr);
Word res = run2(wasm.vm_context(), Word{0});
EXPECT_EQ(res.u32(), 100100); // 10000 (global) + 100 (in callback)
}

} // namespace
} // namespace proxy_wasm
Loading