Skip to content

Commit

Permalink
tests: add tests for execution stages
Browse files Browse the repository at this point in the history
  • Loading branch information
pdziepak committed Mar 3, 2017
1 parent 59b78e5 commit 58bc749
Show file tree
Hide file tree
Showing 3 changed files with 225 additions and 0 deletions.
3 changes: 3 additions & 0 deletions configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ def sanitize_vptr_flag(compiler):
'tests/perf/perf_fstream',
'tests/json_formatter_test',
'tests/dns_test',
'tests/execution_stage_test',
]

apps = [
Expand Down Expand Up @@ -450,6 +451,7 @@ def have_xen():
'tests/perf/perf_fstream': ['tests/perf/perf_fstream.cc'] + core,
'tests/json_formatter_test': ['tests/json_formatter_test.cc'] + core + http,
'tests/dns_test': ['tests/dns_test.cc'] + core + libnet,
'tests/execution_stage_test': ['tests/execution_stage_test.cc'] + core,
}

boost_tests = [
Expand All @@ -471,6 +473,7 @@ def have_xen():
'tests/scollectd_test',
'tests/json_formatter_test',
'tests/dns_test',
'tests/execution_stage_test',
]

for bt in boost_tests:
Expand Down
1 change: 1 addition & 0 deletions test.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
'rpc_test',
'connect_test',
'json_formatter_test',
'execution_stage_test',
]

other_tests = [
Expand Down
221 changes: 221 additions & 0 deletions tests/execution_stage_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
/*
* This file is open source software, licensed to you under the terms
* of the Apache License, Version 2.0 (the "License"). See the NOTICE file
* distributed with this work for additional information regarding copyright
* ownership. You may not use this file except in compliance with the License.
*
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*
* Copyright (C) 2017 ScyllaDB Ltd.
*/

#include <algorithm>
#include <random>
#include <vector>

#include "core/thread.hh"
#include "test-utils.hh"
#include "core/execution_stage.hh"

static std::random_device rd;

template<typename Function, typename Verify>
void test_simple_execution_stage(Function&& func, Verify&& verify) {
auto stage = seastar::make_execution_stage(std::forward<Function>(func));

std::vector<int> vs;
std::default_random_engine gen(rd());
std::uniform_int_distribution<> dist(0, 100'000);
std::generate_n(std::back_inserter(vs), 1'000, [&] { return dist(gen); });

std::vector<future<int>> fs;
for (auto v : vs) {
fs.emplace_back(stage(v));
}

for (auto i = 0u; i < fs.size(); i++) {
verify(vs[i], std::move(fs[i]));
}
}

SEASTAR_TEST_CASE(test_simple_stage_returning_int) {
return seastar::async([] {
test_simple_execution_stage([] (int x) {
if (x % 2) {
return x * 2;
} else {
throw x;
}
}, [] (int original, future<int> result) {
if (original % 2) {
BOOST_REQUIRE_EQUAL(original * 2, result.get0());
} else {
BOOST_REQUIRE_EXCEPTION(result.get0(), int, [&] (int v) { return original == v; });
}
});
});
}

SEASTAR_TEST_CASE(test_simple_stage_returning_future_int) {
return seastar::async([] {
test_simple_execution_stage([] (int x) {
if (x % 2) {
return make_ready_future<int>(x * 2);
} else {
return make_exception_future<int>(x);
}
}, [] (int original, future<int> result) {
if (original % 2) {
BOOST_REQUIRE_EQUAL(original * 2, result.get0());
} else {
BOOST_REQUIRE_EXCEPTION(result.get0(), int, [&] (int v) { return original == v; });
}
});
});
}

template<typename T>
void test_execution_stage_avoids_copy() {
auto stage = seastar::make_execution_stage([] (T obj) {
return std::move(obj);
});

auto f = stage(T());
T obj = f.get0();
(void)obj;
}

SEASTAR_TEST_CASE(test_stage_moves_when_cannot_copy) {
return seastar::async([] {
struct noncopyable_but_movable {
noncopyable_but_movable() = default;
noncopyable_but_movable(const noncopyable_but_movable&) = delete;
noncopyable_but_movable(noncopyable_but_movable&&) = default;
};

test_execution_stage_avoids_copy<noncopyable_but_movable>();
});
}

SEASTAR_TEST_CASE(test_stage_prefers_move_to_copy) {
return seastar::async([] {
struct copyable_and_movable {
copyable_and_movable() = default;
copyable_and_movable(const copyable_and_movable&) {
BOOST_FAIL("should not copy");
}
copyable_and_movable(copyable_and_movable&&) = default;
};

test_execution_stage_avoids_copy<copyable_and_movable>();
});
}

SEASTAR_TEST_CASE(test_rref_decays_to_value) {
return seastar::async([] {
auto stage = seastar::make_execution_stage([] (std::vector<int>&& vec) {
return vec.size();
});

std::vector<int> tmp;
std::vector<future<size_t>> fs;
for (auto i = 0; i < 100; i++) {
tmp.resize(i);
fs.emplace_back(stage(std::move(tmp)));
tmp = std::vector<int>();
}

for (auto i = 0; i < 100; i++) {
BOOST_REQUIRE_EQUAL(fs[i].get0(), i);
}
});
}

SEASTAR_TEST_CASE(test_lref_does_not_decay) {
return seastar::async([] {
auto stage = seastar::make_execution_stage([] (int& v) {
v++;
});

int value = 0;
std::vector<future<>> fs;
for (auto i = 0; i < 100; i++) {
//fs.emplace_back(stage(value)); // should fail to compile
fs.emplace_back(stage(seastar::ref(value)));
}

for (auto&& f : fs) {
f.get();
}
BOOST_REQUIRE_EQUAL(value, 100);
});
}

SEASTAR_TEST_CASE(test_explicit_reference_wrapper_is_not_unwrapped) {
return seastar::async([] {
auto stage = seastar::make_execution_stage([] (seastar::reference_wrapper<int> v) {
v.get()++;
});

int value = 0;
std::vector<future<>> fs;
for (auto i = 0; i < 100; i++) {
//fs.emplace_back(stage(value)); // should fail to compile
fs.emplace_back(stage(seastar::ref(value)));
}

for (auto&& f : fs) {
f.get();
}
BOOST_REQUIRE_EQUAL(value, 100);
});
}

SEASTAR_TEST_CASE(test_function_is_class_member) {
return seastar::async([] {
struct foo {
int value = -1;
int member(int x) {
return std::exchange(value, x);
}
};

auto stage = seastar::make_execution_stage(&foo::member);

foo object;
std::vector<future<int>> fs;
for (auto i = 0; i < 100; i++) {
fs.emplace_back(stage(&object, i));
}

for (auto i = 0; i < 100; i++) {
BOOST_REQUIRE_EQUAL(fs[i].get0(), i - 1);
}
BOOST_REQUIRE_EQUAL(object.value, 99);
});
}

SEASTAR_TEST_CASE(test_function_is_const_class_member) {
return seastar::async([] {
struct foo {
int value = 999;
int member() const {
return value;
}
};
auto stage = seastar::make_execution_stage(&foo::member);

const foo object;
BOOST_REQUIRE_EQUAL(stage(&object).get0(), 999);
});
}

0 comments on commit 58bc749

Please sign in to comment.