diff options
author | Jon Bratseth <bratseth@yahoo-inc.com> | 2016-06-15 23:09:44 +0200 |
---|---|---|
committer | Jon Bratseth <bratseth@yahoo-inc.com> | 2016-06-15 23:09:44 +0200 |
commit | 72231250ed81e10d66bfe70701e64fa5fe50f712 (patch) | |
tree | 2728bba1131a6f6e5bdf95afec7d7ff9358dac50 /staging_vespalib/src/tests |
Publish
Diffstat (limited to 'staging_vespalib/src/tests')
141 files changed, 6044 insertions, 0 deletions
diff --git a/staging_vespalib/src/tests/.gitignore b/staging_vespalib/src/tests/.gitignore new file mode 100644 index 00000000000..c473b24b98a --- /dev/null +++ b/staging_vespalib/src/tests/.gitignore @@ -0,0 +1,4 @@ +.depend +Makefile +testrunner +*_test diff --git a/staging_vespalib/src/tests/array/.gitignore b/staging_vespalib/src/tests/array/.gitignore new file mode 100644 index 00000000000..154e6464c50 --- /dev/null +++ b/staging_vespalib/src/tests/array/.gitignore @@ -0,0 +1,5 @@ +/sort_benchmark +/allocinarray_benchmark +staging_vespalib_allocinarray_test_app +staging_vespalib_allocinarray_benchmark_app +staging_vespalib_sort_benchmark_app diff --git a/staging_vespalib/src/tests/array/CMakeLists.txt b/staging_vespalib/src/tests/array/CMakeLists.txt new file mode 100644 index 00000000000..7b9841d474a --- /dev/null +++ b/staging_vespalib/src/tests/array/CMakeLists.txt @@ -0,0 +1,22 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(staging_vespalib_allocinarray_test_app + SOURCES + allocinarray_test.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_allocinarray_test_app COMMAND staging_vespalib_allocinarray_test_app) +vespa_add_executable(staging_vespalib_sort_benchmark_app + SOURCES + sort_benchmark.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_sort_benchmark_app COMMAND staging_vespalib_sort_benchmark_app BENCHMARK) +vespa_add_executable(staging_vespalib_allocinarray_benchmark_app + SOURCES + allocinarray_benchmark.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_allocinarray_benchmark_app COMMAND staging_vespalib_allocinarray_benchmark_app BENCHMARK) diff --git a/staging_vespalib/src/tests/array/DESC b/staging_vespalib/src/tests/array/DESC new file mode 100644 index 00000000000..59c59c2c50a --- /dev/null +++ b/staging_vespalib/src/tests/array/DESC @@ -0,0 +1 @@ +Array test. Take a look at array_test.cpp for details. diff --git a/staging_vespalib/src/tests/array/FILES b/staging_vespalib/src/tests/array/FILES new file mode 100644 index 00000000000..fa3825f832f --- /dev/null +++ b/staging_vespalib/src/tests/array/FILES @@ -0,0 +1 @@ +array_test.cpp diff --git a/staging_vespalib/src/tests/array/allocinarray_benchmark.cpp b/staging_vespalib/src/tests/array/allocinarray_benchmark.cpp new file mode 100644 index 00000000000..9f365ff937c --- /dev/null +++ b/staging_vespalib/src/tests/array/allocinarray_benchmark.cpp @@ -0,0 +1,124 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/fastos/fastos.h> +#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/util/rusage.h> +#include <vespa/vespalib/util/optimized.h> +#include <vespa/vespalib/util/allocinarray.h> +#include <vespa/log/log.h> +LOG_SETUP("allocinarray_benchmark"); + +using namespace vespalib; + +class Test : public TestApp +{ +public: +private: + void benchmarkTree(size_t count); + void benchmarkTreeInArray(size_t count); + int Main(); +}; + +template <typename T> +class TreeNode +{ +public: + typedef TreeNode * P; + TreeNode(const T & p) :_left(NULL), _right(NULL), _payLoad(p) { } + ~TreeNode() { + if (_left) { + delete _left; + } + if (_right) { + delete _right; + } + } + P left() { return _left; } + P right() { return _right; } + void left(P l) { _left = l; } + void right(P l) { _right = l; } +private: + P _left; + P _right; + T _payLoad; +}; + +template <typename T> +class RefTreeNode +{ +public: + typedef uint32_t P; + RefTreeNode(const T & p) :_left(-1), _right(-1), _payLoad(p) { } + P left() { return _left; } + P right() { return _right; } + void left(P l) { _left = l; } + void right(P l) { _right = l; } +private: + P _left; + P _right; + T _payLoad; +}; + +typedef TreeNode<long> N; +typedef RefTreeNode<long> R; +typedef AllocInArray<R, vespalib::Array<R, MMapAlloc> > Store; + +void populate(Store & store, uint32_t parent, size_t depth) +{ + if (depth > 0) { + store[parent].left(store.alloc(R(0))); + populate(store, store[parent].left(), depth-1); + store[parent].right(store.alloc(R(1))); + populate(store, store[parent].right(), depth-1); + } +} + +void populate(N * parent, size_t depth) +{ + if (depth > 0) { + parent->left(new N(0)); + populate(parent->left(), depth-1); + parent->right(new N(1)); + populate(parent->right(), depth-1); + } +} + +void Test::benchmarkTree(size_t count) +{ + N root(0); + size_t depth = Optimized::msbIdx(count); + populate(&root, depth); +} + +void Test::benchmarkTreeInArray(size_t count) +{ + Store store; + store.alloc(R(0)); + size_t depth = Optimized::msbIdx(count); + populate(store, 0, depth); +} + +int +Test::Main() +{ + std::string type("direct"); + size_t count = 1000000; + if (_argc > 1) { + type = _argv[1]; + } + if (_argc > 2) { + count = strtol(_argv[2], NULL, 0); + } + TEST_INIT("allocinarray_benchmark"); + fastos::TimeStamp start(fastos::ClockSystem::now()); + if (type == "direct") { + benchmarkTree(count); + } else { + benchmarkTreeInArray(count); + } + LOG(info, "rusage = {\n%s\n}", vespalib::RUsage::createSelf(start).toString().c_str()); + ASSERT_EQUAL(0, kill(0, SIGPROF)); + TEST_DONE(); +} + +TEST_APPHOOK(Test); + diff --git a/staging_vespalib/src/tests/array/allocinarray_test.cpp b/staging_vespalib/src/tests/array/allocinarray_test.cpp new file mode 100644 index 00000000000..3a40a71f288 --- /dev/null +++ b/staging_vespalib/src/tests/array/allocinarray_test.cpp @@ -0,0 +1,75 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/fastos/fastos.h> +#include <vespa/log/log.h> +#include <vespa/vespalib/util/array.h> +#include <vespa/vespalib/util/allocinarray.h> +#include <vespa/vespalib/stllike/string.h> +#include <vespa/vespalib/testkit/testapp.h> +#include <deque> + +LOG_SETUP("array_test"); + +using namespace vespalib; + +class Test : public TestApp +{ +public: + int Main(); +private: + template <typename T, typename V> + void testAllocInArray(); +}; + +int +Test::Main() +{ + TEST_INIT("allocinarray_test"); + + testAllocInArray<int64_t, vespalib::Array<int64_t> >(); + testAllocInArray<int64_t, vespalib::Array<int64_t, vespalib::DefaultAlloc> >(); + testAllocInArray<int64_t, std::vector<int64_t> >(); + testAllocInArray<int64_t, std::deque<int64_t> >(); + + TEST_DONE(); +} + +template <typename T, typename V> +void Test::testAllocInArray() +{ + typedef AllocInArray<T, V> AA; + AA alloc; + EXPECT_EQUAL(0ul, alloc.size()); + EXPECT_EQUAL(0ul, alloc.alloc(1)); + EXPECT_EQUAL(1ul, alloc.size()); + EXPECT_EQUAL(1, alloc[0]); + alloc.free(0); + EXPECT_EQUAL(0ul, alloc.size()); + alloc.free(0); + EXPECT_EQUAL(0ul, alloc.size()); + alloc.free(1); + EXPECT_EQUAL(0ul, alloc.size()); + + alloc.alloc(7); + alloc.alloc(17); + alloc.alloc(-17); + EXPECT_EQUAL(3ul, alloc.size()); + EXPECT_EQUAL(7, alloc[0]); + EXPECT_EQUAL(17, alloc[1]); + EXPECT_EQUAL(-17, alloc[2]); + alloc[1] = 99; + EXPECT_EQUAL(99, alloc[1]); + alloc.free(1); + EXPECT_EQUAL(2ul, alloc.size()); + EXPECT_EQUAL(7, alloc[0]); + EXPECT_EQUAL(-17, alloc[2]); + EXPECT_EQUAL(1ul, alloc.alloc(103)); + EXPECT_EQUAL(3ul, alloc.size()); + EXPECT_EQUAL(7, alloc[0]); + EXPECT_EQUAL(103, alloc[1]); + EXPECT_EQUAL(-17, alloc[2]); + + alloc.clear(); + EXPECT_EQUAL(0ul, alloc.size()); +} + +TEST_APPHOOK(Test) diff --git a/staging_vespalib/src/tests/array/sort_benchmark.cpp b/staging_vespalib/src/tests/array/sort_benchmark.cpp new file mode 100644 index 00000000000..bb304f92d58 --- /dev/null +++ b/staging_vespalib/src/tests/array/sort_benchmark.cpp @@ -0,0 +1,182 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/fastos/fastos.h> +#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/util/rusage.h> +#include <vespa/vespalib/util/array.h> +#include <vespa/log/log.h> +LOG_SETUP("sort_benchmark"); + +using namespace vespalib; + +class Test : public TestApp +{ +public: +private: + template<typename T> + vespalib::Array<T> create(size_t count); + template<typename T> + void sortDirect(size_t count); + template<typename T> + void sortInDirect(size_t count); + int Main(); +}; + +template<size_t N> +class TT +{ +public: + TT(uint64_t v) : _v(v) { } + bool operator < (const TT & rhs) const { return _v < rhs._v; } +private: + uint64_t _v; + uint8_t _payLoad[N - sizeof(uint64_t)]; +}; + +template <typename T> +class I +{ +public: + I(const T * p) : _p(p) { } + bool operator < (const I & rhs) const { return *_p < *rhs._p; } +private: + const T * _p; +}; + +template<typename T> +vespalib::Array<T> +Test::create(size_t count) +{ + vespalib::Array<T> v; + v.reserve(count); + srand(0); + for (size_t i(0); i < count; i++) { + v.push_back(rand()); + } + return v; +} + +template<typename T> +void Test::sortDirect(size_t count) +{ + vespalib::Array<T> v(create<T>(count)); + LOG(info, "Running sortDirect with %ld count and payload of %ld", v.size(), sizeof(T)); + for (size_t j=0; j < 10; j++) { + vespalib::Array<T> t(v); + std::sort(t.begin(), t.end()); + } +} + +template<typename T> +void Test::sortInDirect(size_t count) +{ + vespalib::Array<T> k(create<T>(count)); + LOG(info, "Running sortInDirect with %ld count and payload of %ld", k.size(), sizeof(T)); + vespalib::Array< I<T> > v; + v.reserve(k.size()); + for (size_t i(0), m(k.size()); i < m; i++) { + v.push_back(&k[i]); + } + for (size_t j=0; j < 10; j++) { + vespalib::Array< I<T> > t(v); + std::sort(t.begin(), t.end()); + } +} + +int +Test::Main() +{ + std::string type("sortdirect"); + size_t count = 1000000; + size_t payLoad = 0; + if (_argc > 1) { + type = _argv[1]; + } + if (_argc > 2) { + count = strtol(_argv[2], NULL, 0); + } + if (_argc > 3) { + payLoad = strtol(_argv[3], NULL, 0); + } + TEST_INIT("sort_benchmark"); + fastos::TimeStamp start(fastos::ClockSystem::now()); + if (payLoad < 8) { + typedef TT<8> T; + if (type == "sortdirect") { + sortDirect<T>(count); + } else if (type == "sortindirect") { + sortInDirect<T>(count); + } else { + LOG(warning, "type '%s' is unknown", type.c_str()); + } + } else if (payLoad < 16) { + typedef TT<16> T; + if (type == "sortdirect") { + sortDirect<T>(count); + } else if (type == "sortindirect") { + sortInDirect<T>(count); + } else { + LOG(warning, "type '%s' is unknown", type.c_str()); + } + } else if (payLoad < 32) { + typedef TT<32> T; + if (type == "sortdirect") { + sortDirect<T>(count); + } else if (type == "sortindirect") { + sortInDirect<T>(count); + } else { + LOG(warning, "type '%s' is unknown", type.c_str()); + } + } else if (payLoad < 64) { + typedef TT<64> T; + if (type == "sortdirect") { + sortDirect<T>(count); + } else if (type == "sortindirect") { + sortInDirect<T>(count); + } else { + LOG(warning, "type '%s' is unknown", type.c_str()); + } + } else if (payLoad < 128) { + typedef TT<128> T; + if (type == "sortdirect") { + sortDirect<T>(count); + } else if (type == "sortindirect") { + sortInDirect<T>(count); + } else { + LOG(warning, "type '%s' is unknown", type.c_str()); + } + } else if (payLoad < 256) { + typedef TT<256> T; + if (type == "sortdirect") { + sortDirect<T>(count); + } else if (type == "sortindirect") { + sortInDirect<T>(count); + } else { + LOG(warning, "type '%s' is unknown", type.c_str()); + } + } else if (payLoad < 512) { + typedef TT<512> T; + if (type == "sortdirect") { + sortDirect<T>(count); + } else if (type == "sortindirect") { + sortInDirect<T>(count); + } else { + LOG(warning, "type '%s' is unknown", type.c_str()); + } + } else { + typedef TT<1024> T; + LOG(info, "Payload %ld is too big to make any sense. Using %ld.", payLoad, sizeof(T)); + if (type == "sortdirect") { + sortDirect<T>(count); + } else if (type == "sortindirect") { + sortInDirect<T>(count); + } else { + LOG(warning, "type '%s' is unknown", type.c_str()); + } + } + LOG(info, "rusage = {\n%s\n}", vespalib::RUsage::createSelf(start).toString().c_str()); + ASSERT_EQUAL(0, kill(0, SIGPROF)); + TEST_DONE(); +} + +TEST_APPHOOK(Test); + diff --git a/staging_vespalib/src/tests/benchmark/.gitignore b/staging_vespalib/src/tests/benchmark/.gitignore new file mode 100644 index 00000000000..789e52c1370 --- /dev/null +++ b/staging_vespalib/src/tests/benchmark/.gitignore @@ -0,0 +1,4 @@ +.depend +Makefile +benchmark_test +staging_vespalib_benchmark_test_app diff --git a/staging_vespalib/src/tests/benchmark/CMakeLists.txt b/staging_vespalib/src/tests/benchmark/CMakeLists.txt new file mode 100644 index 00000000000..be8ea976c1d --- /dev/null +++ b/staging_vespalib/src/tests/benchmark/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(staging_vespalib_benchmark_test_app + SOURCES + benchmark.cpp + testbase.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_benchmark_test NO_VALGRIND COMMAND sh benchmark_test.sh BENCHMARK) diff --git a/staging_vespalib/src/tests/benchmark/DESC b/staging_vespalib/src/tests/benchmark/DESC new file mode 100644 index 00000000000..cc3b175dace --- /dev/null +++ b/staging_vespalib/src/tests/benchmark/DESC @@ -0,0 +1 @@ +This is so far a test to show benchmarks of different programming techniques. diff --git a/staging_vespalib/src/tests/benchmark/FILES b/staging_vespalib/src/tests/benchmark/FILES new file mode 100644 index 00000000000..30525d50897 --- /dev/null +++ b/staging_vespalib/src/tests/benchmark/FILES @@ -0,0 +1 @@ +benchmark.cpp diff --git a/staging_vespalib/src/tests/benchmark/benchmark.cpp b/staging_vespalib/src/tests/benchmark/benchmark.cpp new file mode 100644 index 00000000000..1c4c5a59c63 --- /dev/null +++ b/staging_vespalib/src/tests/benchmark/benchmark.cpp @@ -0,0 +1,30 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/fastos/fastos.h> +#include <vespa/log/log.h> +LOG_SETUP("benchmark_test"); +#include <vespa/vespalib/testkit/testapp.h> +#include "testbase.h" + +using namespace vespalib; + +TEST_SETUP(Test) + +int +Test::Main() +{ + TEST_INIT("benchmark_test"); + + if (_argc > 1) { + size_t concurrency(1); + size_t numRuns(1000); + if (_argc > 2) { + numRuns = strtoul(_argv[2], NULL, 0); + if (_argc > 3) { + concurrency = strtoul(_argv[3], NULL, 0); + } + } + Benchmark::run(_argv[1], numRuns, concurrency); + } + + TEST_DONE(); +} diff --git a/staging_vespalib/src/tests/benchmark/benchmark_test.sh b/staging_vespalib/src/tests/benchmark/benchmark_test.sh new file mode 100755 index 00000000000..ce0a56ee545 --- /dev/null +++ b/staging_vespalib/src/tests/benchmark/benchmark_test.sh @@ -0,0 +1,19 @@ +#!/bin/bash +TIME=time + +$TIME ./staging_vespalib_benchmark_test_app vespalib::ParamByReferenceVectorInt 200000 1 +$TIME ./staging_vespalib_benchmark_test_app vespalib::ParamByValueVectorInt 4000 1 +$TIME ./staging_vespalib_benchmark_test_app vespalib::ParamByReferenceVectorString 30000 1 +$TIME ./staging_vespalib_benchmark_test_app vespalib::ParamByValueVectorString 40 1 +$TIME ./staging_vespalib_benchmark_test_app vespalib::ReturnByReferenceVectorString 10 1 +$TIME ./staging_vespalib_benchmark_test_app vespalib::ReturnByValueVectorString 10 1 +$TIME ./staging_vespalib_benchmark_test_app vespalib::ReturnByValueMultiVectorString 10 1 +$TIME ./staging_vespalib_benchmark_test_app vespalib::ClockSystem 1000 1 +$TIME ./staging_vespalib_benchmark_test_app vespalib::ClockGToD 1000 1 +$TIME ./staging_vespalib_benchmark_test_app vespalib::ClockGToD 20000 1 +$TIME./staging_vespalib_benchmark_test_app vespalib::ClockREALTIME 1000 1 +$TIME ./staging_vespalib_benchmark_test_app vespalib::ClockMONOTONIC 1000 1 +$TIME ./staging_vespalib_benchmark_test_app vespalib::ClockMONOTONIC_RAW 1000 1 +$TIME ./staging_vespalib_benchmark_test_app vespalib::ClockPROCESS_CPUTIME_ID 2500 1 +$TIME ./staging_vespalib_benchmark_test_app vespalib::ClockTHREAD_CPUTIME_ID 2500 1 +$TIME ./staging_vespalib_benchmark_test_app vespalib::CreateVespalibString 20000 1 diff --git a/staging_vespalib/src/tests/benchmark/testbase.cpp b/staging_vespalib/src/tests/benchmark/testbase.cpp new file mode 100644 index 00000000000..9ac20638218 --- /dev/null +++ b/staging_vespalib/src/tests/benchmark/testbase.cpp @@ -0,0 +1,278 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/fastos/fastos.h> +//#include <linux/time.h> +#include <vespa/log/log.h> +#include <vespa/fastos/timestamp.h> +#include "testbase.h" + +LOG_SETUP(".testbase"); + +namespace vespalib { + +IMPLEMENT_IDENTIFIABLE_ABSTRACT_NS(vespalib, Benchmark, Identifiable); + +IMPLEMENT_BENCHMARK(ParamByReferenceVectorInt, Benchmark); +IMPLEMENT_BENCHMARK(ParamByValueVectorInt, Benchmark); +IMPLEMENT_BENCHMARK(ParamByReferenceVectorString, Benchmark); +IMPLEMENT_BENCHMARK(ParamByValueVectorString, Benchmark); +IMPLEMENT_BENCHMARK(ReturnByReferenceVectorString, Benchmark); +IMPLEMENT_BENCHMARK(ReturnByValueVectorString, Benchmark); +IMPLEMENT_BENCHMARK(ReturnByValueMultiVectorString, Benchmark); +IMPLEMENT_BENCHMARK(ClockSystem, Benchmark); +IMPLEMENT_BENCHMARK(ClockREALTIME, Benchmark); +IMPLEMENT_BENCHMARK(ClockMONOTONIC, Benchmark); +IMPLEMENT_BENCHMARK(ClockMONOTONIC_RAW, Benchmark); +IMPLEMENT_BENCHMARK(ClockPROCESS_CPUTIME_ID, Benchmark); +IMPLEMENT_BENCHMARK(ClockTHREAD_CPUTIME_ID, Benchmark); +IMPLEMENT_BENCHMARK(CreateVespalibString, Benchmark); + +void Benchmark::run(const char *name, size_t numRuns, size_t concurrency) +{ + const Identifiable::RuntimeClass * cInfo = Identifiable::classFromName(name); + if (cInfo) { + std::unique_ptr<Benchmark> test(static_cast<Benchmark *>(cInfo->create())); + test->run(numRuns, concurrency); + } else { + LOG(warning, "Could not find any test with the name %s", name); + } +} +void Benchmark::run(size_t numRuns, size_t concurrency) +{ + LOG(info, "Starting benchmark %s with %ld threads and %ld rep", getClass().name(), concurrency, numRuns); + for (size_t i(0); i < numRuns; i++) { + onRun(); + } + LOG(info, "Stopping benchmark %s", getClass().name()); +} + +size_t ParamByReferenceVectorInt::callByReference(const Vector & values) const +{ + return values.size(); +} + +size_t ParamByReferenceVectorInt::onRun() +{ + Vector values(1000); + size_t sum(0); + for (size_t i=0; i < 1000; i++) { + sum += callByReference(values); + } + return sum; +} + +size_t ParamByValueVectorInt::callByValue(Vector values) const +{ + return values.size(); +} + +size_t ParamByValueVectorInt::onRun() +{ + Vector values(1000); + size_t sum(0); + for (size_t i=0; i < 1000; i++) { + sum += callByValue(values); + } + return sum; +} + +size_t ParamByReferenceVectorString::callByReference(const Vector & values) const +{ + return values.size(); +} + +size_t ParamByReferenceVectorString::onRun() +{ + Vector values(1000, "This is a simple string copy test"); + size_t sum(0); + for (size_t i=0; i < 1000; i++) { + sum += callByReference(values); + } + return sum; +} + +size_t ParamByValueVectorString::callByValue(Vector values) const +{ + return values.size(); +} + +size_t ParamByValueVectorString::onRun() +{ + Vector values(1000, "This is a simple string copy test"); + size_t sum(0); + for (size_t i=0; i < 1000; i++) { + sum += callByValue(values); + } + return sum; +} + +const ReturnByReferenceVectorString::Vector & ReturnByReferenceVectorString::returnByReference(Vector & param) const +{ + Vector values(1000, "return by value"); + param.swap(values); + return param; +} + +size_t ReturnByReferenceVectorString::onRun() +{ + size_t sum(0); + for (size_t i=0; i < 1000; i++) { + Vector values; + sum += returnByReference(values).size(); + } + return sum; +} + +ReturnByValueVectorString::Vector ReturnByValueVectorString::returnByValue() const +{ + Vector values; + if (rand() % 7) { + Vector tmp(1000, "return by value"); + values.swap(tmp); + } else { + Vector tmp(1000, "Return by value"); + values.swap(tmp); + } + return values; +} + +size_t ReturnByValueVectorString::onRun() +{ + size_t sum(0); + for (size_t i=0; i < 1000; i++) { + sum += returnByValue().size(); + } + return sum; +} + +ReturnByValueMultiVectorString::Vector ReturnByValueMultiVectorString::returnByValue() const +{ + if (rand() % 7) { + Vector values(1000, "return by value"); + return values; + } else { + Vector values(1000, "Return by value"); + return values; + } +} + +size_t ReturnByValueMultiVectorString::onRun() +{ + size_t sum(0); + for (size_t i=0; i < 1000; i++) { + sum += returnByValue().size(); + } + return sum; +} + +size_t ClockSystem::onRun() +{ + fastos::TimeStamp start(fastos::ClockSystem::now()); + fastos::TimeStamp end(start); + for (size_t i=0; i < 1000; i++) { + end = fastos::ClockSystem::now(); + } + return (start - end).ns(); +} + +size_t ClockREALTIME::onRun() +{ + struct timespec ts; + int foo = clock_gettime(CLOCK_REALTIME, &ts); + assert(foo == 0); + (void) foo; + fastos::TimeStamp start(ts.tv_sec*1000L*1000L*1000L + ts.tv_nsec); + fastos::TimeStamp end(start); + for (size_t i=0; i < 1000; i++) { + clock_gettime(CLOCK_REALTIME, &ts); + end = ts.tv_sec*1000L*1000L*1000L + ts.tv_nsec; + } + return (start - end).ns(); +} + +size_t ClockMONOTONIC::onRun() +{ + struct timespec ts; + int foo = clock_gettime(CLOCK_MONOTONIC, &ts); + assert(foo == 0); + (void) foo; + fastos::TimeStamp start(ts.tv_sec*1000L*1000L*1000L + ts.tv_nsec); + fastos::TimeStamp end(start); + for (size_t i=0; i < 1000; i++) { + clock_gettime(CLOCK_MONOTONIC, &ts); + end = ts.tv_sec*1000L*1000L*1000L + ts.tv_nsec; + } + return (start - end).ns(); +} + +ClockMONOTONIC_RAW::ClockMONOTONIC_RAW() +{ +#ifndef CLOCK_MONOTONIC_RAW + LOG(warning, "CLOCK_MONOTONIC_RAW is not defined, using CLOCK_MONOTONIC instead."); +#endif +} + +#ifndef CLOCK_MONOTONIC_RAW + #define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC +#endif + +size_t ClockMONOTONIC_RAW::onRun() +{ + struct timespec ts; + int foo = clock_gettime(CLOCK_MONOTONIC_RAW, &ts); + assert(foo == 0); + (void) foo; + fastos::TimeStamp start(ts.tv_sec*1000L*1000L*1000L + ts.tv_nsec); + fastos::TimeStamp end(start); + for (size_t i=0; i < 1000; i++) { + clock_gettime(CLOCK_MONOTONIC_RAW, &ts); + end = ts.tv_sec*1000L*1000L*1000L + ts.tv_nsec; + } + return (start - end).ns(); +} + +size_t ClockPROCESS_CPUTIME_ID::onRun() +{ + struct timespec ts; + int foo = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts); + assert(foo == 0); + (void) foo; + fastos::TimeStamp start(ts.tv_sec*1000L*1000L*1000L + ts.tv_nsec); + fastos::TimeStamp end(start); + for (size_t i=0; i < 1000; i++) { + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts); + end = ts.tv_sec*1000L*1000L*1000L + ts.tv_nsec; + } + return (start - end).ns(); +} + +size_t ClockTHREAD_CPUTIME_ID::onRun() +{ + struct timespec ts; + int foo = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts); + assert(foo == 0); + (void) foo; + fastos::TimeStamp start(ts.tv_sec*1000L*1000L*1000L + ts.tv_nsec); + fastos::TimeStamp end(start); + for (size_t i=0; i < 1000; i++) { + clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts); + end = ts.tv_sec*1000L*1000L*1000L + ts.tv_nsec; + } + return (start - end).ns(); +} + +size_t CreateVespalibString::onRun() +{ + size_t sum(0); + const char * text1("Dette er en passe"); + const char * text2(" kort streng som passer paa stacken"); + char text[100]; + strcpy(text, text1); + strcat(text, text2); + for (size_t i=0; i < 1000; i++) { + string s(text); + sum += s.size(); + } + return sum; +} + +} diff --git a/staging_vespalib/src/tests/benchmark/testbase.h b/staging_vespalib/src/tests/benchmark/testbase.h new file mode 100644 index 00000000000..45b0e30019e --- /dev/null +++ b/staging_vespalib/src/tests/benchmark/testbase.h @@ -0,0 +1,169 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#pragma once + +#include <vespa/vespalib/objects/identifiable.h> +#include <vector> +#include <string> + +#define BENCHMARK_BASE_CID(n) (0x1000000 + n) + +#define CID_vespalib_Benchmark BENCHMARK_BASE_CID(0) +#define CID_vespalib_ParamByReferenceVectorInt BENCHMARK_BASE_CID(1) +#define CID_vespalib_ParamByReferenceVectorString BENCHMARK_BASE_CID(2) +#define CID_vespalib_ParamByValueVectorInt BENCHMARK_BASE_CID(3) +#define CID_vespalib_ParamByValueVectorString BENCHMARK_BASE_CID(4) +#define CID_vespalib_ReturnByReferenceVectorString BENCHMARK_BASE_CID(5) +#define CID_vespalib_ReturnByValueVectorString BENCHMARK_BASE_CID(6) +#define CID_vespalib_ReturnByValueMultiVectorString BENCHMARK_BASE_CID(7) +#define CID_vespalib_ClockSystem BENCHMARK_BASE_CID(8) +#define CID_vespalib_ClockREALTIME BENCHMARK_BASE_CID(10) +#define CID_vespalib_ClockMONOTONIC BENCHMARK_BASE_CID(11) +#define CID_vespalib_ClockMONOTONIC_RAW BENCHMARK_BASE_CID(12) +#define CID_vespalib_ClockPROCESS_CPUTIME_ID BENCHMARK_BASE_CID(13) +#define CID_vespalib_ClockTHREAD_CPUTIME_ID BENCHMARK_BASE_CID(14) +#define CID_vespalib_CreateVespalibString BENCHMARK_BASE_CID(15) + +#define DECLARE_BENCHMARK(a) DECLARE_IDENTIFIABLE_NS(vespalib, a) +#define IMPLEMENT_BENCHMARK(a, d) IMPLEMENT_IDENTIFIABLE_NS(vespalib, a, d) + +namespace vespalib { + +class Benchmark : public Identifiable +{ +public: + DECLARE_IDENTIFIABLE_ABSTRACT_NS(vespalib, Benchmark); + void run(size_t numRuns, size_t concurrency=1); + static void run(const char * testName, size_t numRuns, size_t concurrency); +private: + virtual size_t onRun() = 0; +}; + +class ParamByReferenceVectorInt : public Benchmark +{ +public: + DECLARE_BENCHMARK(ParamByReferenceVectorInt); +private: + typedef std::vector<int> Vector; + size_t callByReference(const Vector & values) const __attribute__((noinline)); + virtual size_t onRun(); +}; + +class ParamByValueVectorInt : public Benchmark +{ +public: + DECLARE_BENCHMARK(ParamByValueVectorInt); +private: + typedef std::vector<int> Vector; + size_t callByValue(Vector values) const __attribute__((noinline)); + virtual size_t onRun(); +}; + +class ParamByReferenceVectorString : public Benchmark +{ +public: + DECLARE_BENCHMARK(ParamByReferenceVectorString); +private: + typedef std::vector<std::string> Vector; + size_t callByReference(const Vector & values) const __attribute__((noinline)); + virtual size_t onRun(); +}; + +class ParamByValueVectorString : public Benchmark +{ +public: + DECLARE_BENCHMARK(ParamByValueVectorString); +private: + typedef std::vector<std::string> Vector; + size_t callByValue(Vector values) const __attribute__((noinline)); + virtual size_t onRun(); +}; + +class ReturnByReferenceVectorString : public Benchmark +{ +public: + DECLARE_BENCHMARK(ReturnByReferenceVectorString); +private: + typedef std::vector<std::string> Vector; + const Vector & returnByReference(Vector & values) const __attribute__((noinline)); + virtual size_t onRun(); +}; + +class ReturnByValueVectorString : public Benchmark +{ +public: + DECLARE_BENCHMARK(ReturnByValueVectorString); +private: + typedef std::vector<std::string> Vector; + Vector returnByValue() const __attribute__((noinline)); + virtual size_t onRun(); +}; + +class ReturnByValueMultiVectorString : public Benchmark +{ +public: + DECLARE_BENCHMARK(ReturnByValueMultiVectorString); +private: + typedef std::vector<std::string> Vector; + Vector returnByValue() const __attribute__((noinline)); + virtual size_t onRun(); +}; + +class CreateVespalibString : public Benchmark +{ +public: + DECLARE_BENCHMARK(CreateVespalibString); +private: + virtual size_t onRun(); +}; + +class ClockSystem : public Benchmark +{ +public: + DECLARE_BENCHMARK(ClockSystem); +private: + virtual size_t onRun(); +}; + +class ClockREALTIME : public Benchmark +{ +public: + DECLARE_BENCHMARK(ClockREALTIME); +private: + virtual size_t onRun(); +}; + +class ClockMONOTONIC : public Benchmark +{ +public: + DECLARE_BENCHMARK(ClockMONOTONIC); +private: + virtual size_t onRun(); +}; + +class ClockMONOTONIC_RAW : public Benchmark +{ +public: + DECLARE_BENCHMARK(ClockMONOTONIC_RAW); + ClockMONOTONIC_RAW(); +private: + virtual size_t onRun(); +}; + +class ClockPROCESS_CPUTIME_ID : public Benchmark +{ +public: + DECLARE_BENCHMARK(ClockPROCESS_CPUTIME_ID); +private: + virtual size_t onRun(); +}; + +class ClockTHREAD_CPUTIME_ID : public Benchmark +{ +public: + DECLARE_BENCHMARK(ClockTHREAD_CPUTIME_ID); +private: + virtual size_t onRun(); +}; + +} + diff --git a/staging_vespalib/src/tests/bits/.gitignore b/staging_vespalib/src/tests/bits/.gitignore new file mode 100644 index 00000000000..82481fe3c30 --- /dev/null +++ b/staging_vespalib/src/tests/bits/.gitignore @@ -0,0 +1,4 @@ +.depend +Makefile +bits_test +staging_vespalib_bits_test_app diff --git a/staging_vespalib/src/tests/bits/CMakeLists.txt b/staging_vespalib/src/tests/bits/CMakeLists.txt new file mode 100644 index 00000000000..693b6cbb6cc --- /dev/null +++ b/staging_vespalib/src/tests/bits/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(staging_vespalib_bits_test_app + SOURCES + bits_test.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_bits_test_app COMMAND staging_vespalib_bits_test_app) diff --git a/staging_vespalib/src/tests/bits/DESC b/staging_vespalib/src/tests/bits/DESC new file mode 100644 index 00000000000..2ea242366ff --- /dev/null +++ b/staging_vespalib/src/tests/bits/DESC @@ -0,0 +1 @@ +bit manipultaion test. Take a look at bits.cpp for details. diff --git a/staging_vespalib/src/tests/bits/FILES b/staging_vespalib/src/tests/bits/FILES new file mode 100644 index 00000000000..95ad604b592 --- /dev/null +++ b/staging_vespalib/src/tests/bits/FILES @@ -0,0 +1 @@ +bits.cpp diff --git a/staging_vespalib/src/tests/bits/bits_test.cpp b/staging_vespalib/src/tests/bits/bits_test.cpp new file mode 100644 index 00000000000..83e60f0f214 --- /dev/null +++ b/staging_vespalib/src/tests/bits/bits_test.cpp @@ -0,0 +1,58 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/fastos/fastos.h> +#include <vespa/log/log.h> +LOG_SETUP("bits_test"); +#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/util/bits.h> +#include <boost/crc.hpp> + +using namespace vespalib; + +class Test : public TestApp +{ +public: + int Main(); + template <typename T> + void testFixed(const T * v, size_t sz); + void testBuffer(); +}; + +int +Test::Main() +{ + TEST_INIT("bits_test"); + uint8_t u8[5] = { 0, 1, 127, 135, 255 }; + testFixed(u8, sizeof(u8)/sizeof(u8[0])); + uint16_t u16[5] = { 0, 1, 127, 135, 255 }; + testFixed(u16, sizeof(u16)/sizeof(u16[0])); + uint32_t u32[5] = { 0, 1, 127, 135, 255 }; + testFixed(u32, sizeof(u32)/sizeof(u32[0])); + uint64_t u64[5] = { 0, 1, 127, 135, 255 }; + testFixed(u64, sizeof(u64)/sizeof(u64[0])); + testBuffer(); + TEST_DONE(); +} + +template <typename T> +void Test::testFixed(const T * v, size_t sz) +{ + EXPECT_EQUAL(0u, Bits::reverse(static_cast<T>(0))); + EXPECT_EQUAL(1ul << (sizeof(T)*8 - 1), Bits::reverse(static_cast<T>(1))); + EXPECT_EQUAL(static_cast<T>(-1), Bits::reverse(static_cast<T>(-1))); + for (size_t i(0); i < sz; i++) { + EXPECT_EQUAL(Bits::reverse(v[i]), boost::detail::reflector<sizeof(T)*8>::reflect(v[i])); + EXPECT_EQUAL(Bits::reverse(Bits::reverse(v[i])), v[i]); + } +} + +void Test::testBuffer() +{ + uint64_t a(0x0102040810204080ul); + uint64_t b(a); + Bits::reverse(&a, sizeof(a)); + EXPECT_EQUAL(a, Bits::reverse(b)); + Bits::reverse(&a, sizeof(a)); + EXPECT_EQUAL(a, b); +} + +TEST_APPHOOK(Test) diff --git a/staging_vespalib/src/tests/clock/.gitignore b/staging_vespalib/src/tests/clock/.gitignore new file mode 100644 index 00000000000..1826ba1563b --- /dev/null +++ b/staging_vespalib/src/tests/clock/.gitignore @@ -0,0 +1,4 @@ +.depend +Makefile +clock_test +staging_vespalib_clock_test_app diff --git a/staging_vespalib/src/tests/clock/CMakeLists.txt b/staging_vespalib/src/tests/clock/CMakeLists.txt new file mode 100644 index 00000000000..8717a6411ab --- /dev/null +++ b/staging_vespalib/src/tests/clock/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(staging_vespalib_clock_test_app + SOURCES + clock_test.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_clock_test_app COMMAND staging_vespalib_clock_test_app) diff --git a/staging_vespalib/src/tests/clock/DESC b/staging_vespalib/src/tests/clock/DESC new file mode 100644 index 00000000000..061f9af2d0a --- /dev/null +++ b/staging_vespalib/src/tests/clock/DESC @@ -0,0 +1 @@ +Unit tests for the clock. diff --git a/staging_vespalib/src/tests/clock/FILES b/staging_vespalib/src/tests/clock/FILES new file mode 100644 index 00000000000..c0a2e8e47ea --- /dev/null +++ b/staging_vespalib/src/tests/clock/FILES @@ -0,0 +1 @@ +clock.cpp diff --git a/staging_vespalib/src/tests/clock/clock_test.cpp b/staging_vespalib/src/tests/clock/clock_test.cpp new file mode 100644 index 00000000000..f7f15dd3d24 --- /dev/null +++ b/staging_vespalib/src/tests/clock/clock_test.cpp @@ -0,0 +1,38 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/fastos/fastos.h> +#include <vespa/log/log.h> +LOG_SETUP("sharedptr_test"); +#include <vespa/vespalib/util/clock.h> +#include <vespa/vespalib/testkit/testapp.h> + +using vespalib::Clock; +using fastos::TimeStamp; + +class Test : public vespalib::TestApp +{ +public: + int Main(); +}; + + +int +Test::Main() +{ + TEST_INIT("clock_test"); + + Clock clock(0.050); + FastOS_ThreadPool pool(0x10000); + ASSERT_TRUE(pool.NewThread(&clock, NULL) != NULL); + uint64_t start = clock.getTimeNS(); + FastOS_Thread::Sleep(5000); + uint64_t stop = clock.getTimeNS(); + EXPECT_TRUE(stop > start); + FastOS_Thread::Sleep(6000); + clock.stop(); + uint64_t stop2 = clock.getTimeNS(); + EXPECT_TRUE(stop2 > stop); + EXPECT_TRUE((stop2 - stop)/TimeStamp::MICRO > 1000); + TEST_DONE(); +} + +TEST_APPHOOK(Test) diff --git a/staging_vespalib/src/tests/cpu/.gitignore b/staging_vespalib/src/tests/cpu/.gitignore new file mode 100644 index 00000000000..eea6ced9753 --- /dev/null +++ b/staging_vespalib/src/tests/cpu/.gitignore @@ -0,0 +1,4 @@ +.depend +Makefile +cpu_test +staging_vespalib_cpu_test_app diff --git a/staging_vespalib/src/tests/cpu/CMakeLists.txt b/staging_vespalib/src/tests/cpu/CMakeLists.txt new file mode 100644 index 00000000000..13bc4014d85 --- /dev/null +++ b/staging_vespalib/src/tests/cpu/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(staging_vespalib_cpu_test_app + SOURCES + cpu_test.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_cpu_test_app COMMAND staging_vespalib_cpu_test_app) diff --git a/staging_vespalib/src/tests/cpu/DESC b/staging_vespalib/src/tests/cpu/DESC new file mode 100644 index 00000000000..19de1b44450 --- /dev/null +++ b/staging_vespalib/src/tests/cpu/DESC @@ -0,0 +1 @@ +cpu special instructions test. Take a look at cpu.cpp for details. diff --git a/staging_vespalib/src/tests/cpu/FILES b/staging_vespalib/src/tests/cpu/FILES new file mode 100644 index 00000000000..6abb996b510 --- /dev/null +++ b/staging_vespalib/src/tests/cpu/FILES @@ -0,0 +1 @@ +cpu.cpp diff --git a/staging_vespalib/src/tests/cpu/cpu_test.cpp b/staging_vespalib/src/tests/cpu/cpu_test.cpp new file mode 100644 index 00000000000..56f109e47a4 --- /dev/null +++ b/staging_vespalib/src/tests/cpu/cpu_test.cpp @@ -0,0 +1,33 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/fastos/fastos.h> +#include <vespa/log/log.h> +LOG_SETUP("cpu_test"); +#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/util/cpu.h> + +using namespace vespalib; + +class Test : public vespalib::TestApp +{ +public: + int Main(); +}; + +int Test::Main() +{ + TEST_INIT("cpu_test"); + + const X86CpuInfo & cpu = X86CpuInfo::cpuInfo(); + EXPECT_TRUE(cpu.hasMMX()); + EXPECT_TRUE(cpu.hasSSE()); + EXPECT_TRUE(cpu.hasSSE2()); + EXPECT_TRUE(cpu.hasSSE3()); + EXPECT_TRUE(cpu.hasCX16()); + + X86CpuInfo::print(stdout); + + TEST_FLUSH(); + TEST_DONE(); +} + +TEST_APPHOOK(Test) diff --git a/staging_vespalib/src/tests/crc/.gitignore b/staging_vespalib/src/tests/crc/.gitignore new file mode 100644 index 00000000000..448fa141b03 --- /dev/null +++ b/staging_vespalib/src/tests/crc/.gitignore @@ -0,0 +1,4 @@ +.depend +Makefile +crc_test +staging_vespalib_crc_test_app diff --git a/staging_vespalib/src/tests/crc/CMakeLists.txt b/staging_vespalib/src/tests/crc/CMakeLists.txt new file mode 100644 index 00000000000..cc8e828d0d4 --- /dev/null +++ b/staging_vespalib/src/tests/crc/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(staging_vespalib_crc_test_app + SOURCES + crc_test.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_crc_test_app COMMAND staging_vespalib_crc_test_app boost) diff --git a/staging_vespalib/src/tests/crc/DESC b/staging_vespalib/src/tests/crc/DESC new file mode 100644 index 00000000000..587969f7773 --- /dev/null +++ b/staging_vespalib/src/tests/crc/DESC @@ -0,0 +1 @@ +crc test. Take a look at crc.cpp for details. diff --git a/staging_vespalib/src/tests/crc/FILES b/staging_vespalib/src/tests/crc/FILES new file mode 100644 index 00000000000..2e867a09e10 --- /dev/null +++ b/staging_vespalib/src/tests/crc/FILES @@ -0,0 +1 @@ +crc.cpp diff --git a/staging_vespalib/src/tests/crc/crc_test.cpp b/staging_vespalib/src/tests/crc/crc_test.cpp new file mode 100644 index 00000000000..6c028cc09ce --- /dev/null +++ b/staging_vespalib/src/tests/crc/crc_test.cpp @@ -0,0 +1,80 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/fastos/fastos.h> +#include <vespa/log/log.h> +LOG_SETUP("crc_test"); +#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/util/crc.h> +#include <boost/crc.hpp> +#include <vector> + +using namespace vespalib; + +class Test : public TestApp +{ +public: + int Main(); + void testCorrectNess(); + void testBenchmark(bool our, size_t bufSz, size_t numRep); +}; + +int +Test::Main() +{ + TEST_INIT("crc_test"); + testCorrectNess(); + if (_argc >= 2) { + testBenchmark(false, 1024, 1000*1000); + } else { + testBenchmark(true, 1024, 1000*1000); + } + TEST_DONE(); +} + +void Test::testCorrectNess() +{ + const char *a[7] = { "", "a", "ab", "abc", "abcd", "abcde", "doc:crawler:http://www.ntnu.no/" }; + for (size_t i(0); i < sizeof(a)/sizeof(a[0]); i++) { + uint32_t vespaCrc32 = crc_32_type::crc(a[i], strlen(a[i])); + boost::crc_32_type calculator; + calculator.process_bytes(a[i], strlen(a[i])); + EXPECT_EQUAL(vespaCrc32, calculator.checksum()); + vespalib::crc_32_type calculator2; + calculator2.process_bytes(a[i], strlen(a[i])); + EXPECT_EQUAL(vespaCrc32, calculator2.checksum()); + EXPECT_EQUAL(calculator.checksum(), calculator2.checksum()); + } + vespalib::crc_32_type calculator2; + boost::crc_32_type calculator; + for (size_t i(0); i < sizeof(a)/sizeof(a[0]); i++) { + calculator.process_bytes(a[i], strlen(a[i])); + calculator2.process_bytes(a[i], strlen(a[i])); + EXPECT_EQUAL(calculator.checksum(), calculator2.checksum()); + } + EXPECT_EQUAL(calculator.checksum(), calculator2.checksum()); +} + +void Test::testBenchmark(bool our, size_t bufSz, size_t numRep) +{ + std::vector<char> a(numRep+bufSz); + for(size_t i(0), m(a.size()); i < m; i++) { + a[i] = i&0xff; + } + uint32_t sum(0); + if (our) { + for (size_t i(0); i < (numRep); i++) { + //sum ^= crc_32_type::crc(&a[i], bufSz); + vespalib::crc_32_type calculator; + calculator.process_bytes(&a[i], bufSz); + sum ^=calculator.checksum(); + } + } else { + for (size_t i(0); i < (numRep); i++) { + boost::crc_32_type calculator; + calculator.process_bytes(&a[i], bufSz); + sum ^=calculator.checksum(); + } + } + printf("sum = %x\n", sum); +} + +TEST_APPHOOK(Test) diff --git a/staging_vespalib/src/tests/create-test.sh b/staging_vespalib/src/tests/create-test.sh new file mode 100755 index 00000000000..56234dbab30 --- /dev/null +++ b/staging_vespalib/src/tests/create-test.sh @@ -0,0 +1,65 @@ +#!/bin/sh +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +gen_project_file() { + echo "generating '$1' ..." + echo "APPLICATION ${test}_test" > $1 + echo "OBJS ${test}_test" >> $1 + echo "LIBS vespalib/staging_vespalib" >> $1 + echo "EXTERNALLIBS vespalib vespalog" >> $1 + echo "" >> $1 + echo "CUSTOMMAKE" >> $1 + echo "test: depend ${test}_test" >> $1 + echo -e "\t@./${test}_test" >> $1 +} + +gen_source() { + echo "generating '$1' ..." + echo "#include <vespa/log/log.h>" > $1 + echo "LOG_SETUP(\"${test}_test\");" >> $1 + echo "#include <vespa/fastos/fastos.h>" >> $1 + echo "#include <vespa/vespalib/testkit/testapp.h>" >> $1 + echo "" >> $1 + echo "using namespace vespalib;" >> $1 + echo "" >> $1 + echo "TEST_SETUP(Test);" >> $1 + echo "" >> $1 + echo "int" >> $1 + echo "Test::Main()" >> $1 + echo "{" >> $1 + echo " TEST_INIT(\"${test}_test\");" >> $1 + echo " TEST_DONE();" >> $1 + echo "}" >> $1 +} + +gen_desc() { + echo "generating '$1' ..." + echo "$test test. Take a look at ${test}_test.cpp for details." > $1 +} + +gen_file_list() { + echo "generating '$1' ..." + echo "${test}_test.cpp" > $1 +} + +if [ $# -ne 1 ]; then + echo "usage: $0 <name>" + echo " name: name of the test to create" + exit 1 +fi + +test=$1 +if [ -e $test ]; then + echo "$test already present, don't want to mess it up..." + exit 1 +fi + +echo "creating directory '$test' ..." +mkdir -p $test || exit 1 +cd $test || exit 1 +test=`basename $test` + +gen_project_file fastos.project +gen_source ${test}_test.cpp +gen_desc DESC +gen_file_list FILES diff --git a/staging_vespalib/src/tests/databuffer/.gitignore b/staging_vespalib/src/tests/databuffer/.gitignore new file mode 100644 index 00000000000..e7b0e69c372 --- /dev/null +++ b/staging_vespalib/src/tests/databuffer/.gitignore @@ -0,0 +1 @@ +staging_vespalib_databuffer_test_app diff --git a/staging_vespalib/src/tests/databuffer/CMakeLists.txt b/staging_vespalib/src/tests/databuffer/CMakeLists.txt new file mode 100644 index 00000000000..65eae47a502 --- /dev/null +++ b/staging_vespalib/src/tests/databuffer/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(staging_vespalib_databuffer_test_app + SOURCES + databuffer_test.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_databuffer_test_app COMMAND staging_vespalib_databuffer_test_app) diff --git a/staging_vespalib/src/tests/databuffer/databuffer_test.cpp b/staging_vespalib/src/tests/databuffer/databuffer_test.cpp new file mode 100644 index 00000000000..3793af27aa7 --- /dev/null +++ b/staging_vespalib/src/tests/databuffer/databuffer_test.cpp @@ -0,0 +1,145 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/fastos/fastos.h> +#include <vespa/log/log.h> +LOG_SETUP("databuffer_test"); + +#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/data/databuffer.h> +#include <iostream> + +using namespace vespalib; + +class Test : public vespalib::TestApp { +private: + void testBasic(); +public: + int Main() { + TEST_INIT("databuffer_test"); + + testBasic(); TEST_FLUSH(); + + TEST_DONE(); + } +}; + +TEST_APPHOOK(Test); + +void +Test::testBasic() +{ + DataBuffer a(50); + EXPECT_EQUAL(256u, a.getBufSize()); + EXPECT_EQUAL(a.getFreeLen(), a.getBufSize()); + a.ensureFree(1000); + EXPECT_EQUAL(1024u, a.getBufSize()); + EXPECT_EQUAL(a.getFreeLen(), a.getBufSize()); + EXPECT_EQUAL(0u, a.getDeadLen()); + EXPECT_EQUAL(0u, a.getDataLen()); + EXPECT_EQUAL(a.getData(), a.getDead()); + EXPECT_EQUAL(a.getData(), a.getFree()); + EXPECT_EQUAL(a.getBufSize(), a.getFreeLen()); + a.assertValid(); + + a.writeInt16(7); + EXPECT_EQUAL(0u, a.getDeadLen()); + EXPECT_EQUAL(2u, a.getDataLen()); + EXPECT_EQUAL(a.getBufSize()-2, a.getFreeLen()); + EXPECT_EQUAL(a.getData(), a.getDead()); + EXPECT_EQUAL(a.getData()+2, a.getFree()); + a.clear(); + EXPECT_EQUAL(0u, a.getDeadLen()); + EXPECT_EQUAL(0u, a.getDataLen()); + EXPECT_EQUAL(a.getBufSize(), a.getFreeLen()); + + a.writeInt8(0xaau); + EXPECT_EQUAL(1u, a.getDataLen()); + EXPECT_EQUAL(0xaau, a.peekInt8(0)); + EXPECT_EQUAL(1u, a.getDataLen()); + EXPECT_EQUAL(0xaau, a.readInt8()); + EXPECT_EQUAL(0u, a.getDataLen()); + + a.writeInt16(0xaabbu); + EXPECT_EQUAL(2u, a.getDataLen()); + EXPECT_EQUAL(0xaabbu, a.peekInt16(0)); + EXPECT_EQUAL(2u, a.getDataLen()); + EXPECT_EQUAL(0xaabbu, a.readInt16()); + EXPECT_EQUAL(0u, a.getDataLen()); + a.writeInt16(0xaabbu); + EXPECT_EQUAL(2u, a.getDataLen()); + EXPECT_EQUAL(0xbbaau, a.peekInt16Reverse(0)); + EXPECT_EQUAL(2u, a.getDataLen()); + EXPECT_EQUAL(0xbbaau, a.readInt16Reverse()); + EXPECT_EQUAL(0u, a.getDataLen()); + + a.writeInt32(0xaabbccddu); + EXPECT_EQUAL(4u, a.getDataLen()); + EXPECT_EQUAL(0xaabbccddu, a.peekInt32(0)); + EXPECT_EQUAL(4u, a.getDataLen()); + EXPECT_EQUAL(0xaabbccddu, a.readInt32()); + EXPECT_EQUAL(0u, a.getDataLen()); + a.writeInt32(0xaabbccddu); + EXPECT_EQUAL(4u, a.getDataLen()); + EXPECT_EQUAL(0xddccbbaau, a.peekInt32Reverse(0)); + EXPECT_EQUAL(4u, a.getDataLen()); + EXPECT_EQUAL(0xddccbbaau, a.readInt32Reverse()); + EXPECT_EQUAL(0u, a.getDataLen()); + + a.writeInt64(0xaabbccddeeff9988ul); + EXPECT_EQUAL(8u, a.getDataLen()); + EXPECT_EQUAL(0xaabbccddeeff9988ul, a.peekInt64(0)); + EXPECT_EQUAL(8u, a.getDataLen()); + EXPECT_EQUAL(0xaabbccddeeff9988ul, a.readInt64()); + EXPECT_EQUAL(0u, a.getDataLen()); + a.writeInt64(0xaabbccddeeff9988ul); + EXPECT_EQUAL(8u, a.getDataLen()); + EXPECT_EQUAL(0x8899ffeeddccbbaaul, a.peekInt64Reverse(0)); + EXPECT_EQUAL(8u, a.getDataLen()); + EXPECT_EQUAL(0x8899ffeeddccbbaaul, a.readInt64Reverse()); + EXPECT_EQUAL(0u, a.getDataLen()); + + a.writeFloat(8.9f); + EXPECT_EQUAL(4u, a.getDataLen()); + EXPECT_EQUAL(8.9f, a.readFloat()); + EXPECT_EQUAL(0u, a.getDataLen()); + + a.writeDouble(8.9); + EXPECT_EQUAL(8u, a.getDataLen()); + EXPECT_EQUAL(8.9, a.readDouble()); + EXPECT_EQUAL(0u, a.getDataLen()); + + const char *c = "abc"; + char b[3]; + a.writeBytes(c, 3); + EXPECT_EQUAL(3u, a.getDataLen()); + EXPECT_EQUAL(0, memcmp(c, a.getData(), a.getDataLen())); + a.peekBytes(b, 3, 0); + EXPECT_EQUAL(3u, a.getDataLen()); + EXPECT_EQUAL(0, memcmp(c, b, sizeof(b))); + a.readBytes(b, sizeof(b)); + EXPECT_EQUAL(0u, a.getDataLen()); + EXPECT_EQUAL(0, memcmp(c, b, sizeof(b))); + + a.writeInt64(67); + EXPECT_EQUAL(8u, a.getDataLen()); + EXPECT_FALSE(a.shrink(1025)); + EXPECT_FALSE(a.shrink(7)); + EXPECT_TRUE(a.shrink(16)); + EXPECT_EQUAL(8u, a.getDataLen()); + EXPECT_EQUAL(16u, a.getBufSize()); + + a.writeInt64(89); + EXPECT_EQUAL(16u, a.getDataLen()); + EXPECT_EQUAL(16u, a.getBufSize()); + EXPECT_EQUAL(0u, a.getDeadLen()); + EXPECT_EQUAL(67u, a.readInt64()); + EXPECT_EQUAL(8u, a.getDataLen()); + EXPECT_EQUAL(8u, a.getDeadLen()); + EXPECT_EQUAL(16u, a.getBufSize()); + a.pack(16); + EXPECT_EQUAL(8u, a.getDataLen()); + EXPECT_EQUAL(0u, a.getDeadLen()); + EXPECT_EQUAL(256u, a.getBufSize()); + EXPECT_EQUAL(89u, a.readInt64()); + EXPECT_EQUAL(0u, a.getDataLen()); + EXPECT_EQUAL(256u, a.getBufSize()); +} diff --git a/staging_vespalib/src/tests/directio/.gitignore b/staging_vespalib/src/tests/directio/.gitignore new file mode 100644 index 00000000000..6e6dbe13324 --- /dev/null +++ b/staging_vespalib/src/tests/directio/.gitignore @@ -0,0 +1 @@ +staging_vespalib_directio_test_app diff --git a/staging_vespalib/src/tests/directio/CMakeLists.txt b/staging_vespalib/src/tests/directio/CMakeLists.txt new file mode 100644 index 00000000000..334ae825bf6 --- /dev/null +++ b/staging_vespalib/src/tests/directio/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(staging_vespalib_directio_test_app + SOURCES + directio.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_directio_test_app COMMAND staging_vespalib_directio_test_app) diff --git a/staging_vespalib/src/tests/directio/directio.cpp b/staging_vespalib/src/tests/directio/directio.cpp new file mode 100644 index 00000000000..570d7276bc9 --- /dev/null +++ b/staging_vespalib/src/tests/directio/directio.cpp @@ -0,0 +1,58 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/fastos/fastos.h> +#include <vespa/log/log.h> +LOG_SETUP("directio_test"); +#include <vespa/vespalib/testkit/test_kit.h> +#include <vespa/vespalib/stllike/string.h> +#include <vespa/vespalib/data/databuffer.h> + +using namespace fastos; +using namespace vespalib; + +TEST("that DirectIOException propagates the correct information.") { + const char *msg("The buffer"); + DirectIOException e("file.a", msg, 10, 3); + EXPECT_EQUAL(10u, e.getLength()); + EXPECT_EQUAL(3u, e.getOffset()); + EXPECT_EQUAL(msg, e.getBuffer()); + EXPECT_EQUAL(0u, string(e.what()).find("DirectIO failed for file 'file.a' buffer=")); + EXPECT_EQUAL(string("file.a"), e.getFileName()); +} + +TEST("that DirectIOException is thrown on unaligned buf.") { + FastOS_File f("staging_vespalib_directio_test_app"); + f.EnableDirectIO(); + EXPECT_TRUE(f.OpenReadOnly()); + DataBuffer buf(10000, 4096); + bool caught(false); + try { + f.ReadBuf(buf.getFree()+1, 4096, 0); + } catch (const DirectIOException & e) { + EXPECT_EQUAL(4096u, e.getLength()); + EXPECT_EQUAL(0u, e.getOffset()); + EXPECT_EQUAL(buf.getFree()+1, e.getBuffer()); + EXPECT_EQUAL(string(f.GetFileName()), e.getFileName()); + caught = true; + } + EXPECT_TRUE(caught); +} + +TEST("that DirectIOException is thrown on unaligned offset.") { + FastOS_File f("staging_vespalib_directio_test_app"); + f.EnableDirectIO(); + EXPECT_TRUE(f.OpenReadOnly()); + DataBuffer buf(10000, 4096); + bool caught(false); + try { + f.ReadBuf(buf.getFree(), 4096, 1); + } catch (const DirectIOException & e) { + EXPECT_EQUAL(4096u, e.getLength()); + EXPECT_EQUAL(1u, e.getOffset()); + EXPECT_EQUAL(buf.getFree(), e.getBuffer()); + EXPECT_EQUAL(string(f.GetFileName()), e.getFileName()); + caught = true; + } + EXPECT_TRUE(caught); +} + +TEST_MAIN() { TEST_RUN_ALL(); } diff --git a/staging_vespalib/src/tests/dotproduct/.gitignore b/staging_vespalib/src/tests/dotproduct/.gitignore new file mode 100644 index 00000000000..5d9432fbd08 --- /dev/null +++ b/staging_vespalib/src/tests/dotproduct/.gitignore @@ -0,0 +1,2 @@ +dotproductbenchmark +staging_vespalib_dotproductbenchmark_app diff --git a/staging_vespalib/src/tests/dotproduct/CMakeLists.txt b/staging_vespalib/src/tests/dotproduct/CMakeLists.txt new file mode 100644 index 00000000000..30a02632f1c --- /dev/null +++ b/staging_vespalib/src/tests/dotproduct/CMakeLists.txt @@ -0,0 +1,21 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(staging_vespalib_dotproductbenchmark_app + SOURCES + dotproductbenchmark.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_dotproductbenchmark_app_sparse-ordered COMMAND staging_vespalib_dotproductbenchmark_app 10 10 1000 1000 BENCHMARK) +vespa_add_test(NAME staging_vespalib_dotproductbenchmark_app_sparse-unordered COMMAND staging_vespalib_dotproductbenchmark_app 10 10 1000 1000 BENCHMARK) +vespa_add_test(NAME staging_vespalib_dotproductbenchmark_app_full COMMAND staging_vespalib_dotproductbenchmark_app 10 10 1000 1000 BENCHMARK) + +# benchmark: dotproductbenchmark +# $(HIDE)$(LDL) time $(VALGRIND) ./dotproductbenchmark sparse-ordered 1000 1000 1000 1000 +# $(HIDE)$(LDL) time $(VALGRIND) ./dotproductbenchmark sparse-unordered 1000 1000 1000 1000 +# $(HIDE)$(LDL) time $(VALGRIND) ./dotproductbenchmark full 1000 1000 1000 1000 +# $(HIDE)$(LDL) time $(VALGRIND) ./dotproductbenchmark sparse-ordered 1000 1000 100 1000 +# $(HIDE)$(LDL) time $(VALGRIND) ./dotproductbenchmark sparse-unordered 1000 1000 100 1000 +# $(HIDE)$(LDL) time $(VALGRIND) ./dotproductbenchmark full 1000 1000 100 1000 +# $(HIDE)$(LDL) time $(VALGRIND) ./dotproductbenchmark sparse-ordered 1000 1000 1000 100 +# $(HIDE)$(LDL) time $(VALGRIND) ./dotproductbenchmark sparse-unordered 1000 1000 1000 100 +# $(HIDE)$(LDL) time $(VALGRIND) ./dotproductbenchmark full 1000 1000 1000 100 diff --git a/staging_vespalib/src/tests/dotproduct/dotproductbenchmark.cpp b/staging_vespalib/src/tests/dotproduct/dotproductbenchmark.cpp new file mode 100644 index 00000000000..9ef3d959f3b --- /dev/null +++ b/staging_vespalib/src/tests/dotproduct/dotproductbenchmark.cpp @@ -0,0 +1,179 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/fastos/fastos.h> +#include <vespa/vespalib/hwaccelrated/iaccelrated.h> +#include <vespa/vespalib/stllike/string.h> +#include <vespa/vespalib/stllike/hash_map.h> +#include <iostream> + +using namespace vespalib; +using vespalib::hwaccelrated::IAccelrated; + +class Benchmark { +public: + virtual ~Benchmark() { } + virtual void compute(size_t docId) const = 0; +}; + +void +runBenchmark(size_t count, size_t docs, const Benchmark & benchmark) +{ + for (size_t i(0); i < count; i++) { + for (size_t docId(0); docId < docs; docId++) { + benchmark.compute(docId); + } + } +} + +template <typename T> +class FullBenchmark : public Benchmark +{ +public: + FullBenchmark(size_t numDocs, size_t numValues) : + _values(numDocs*numValues), + _query(numValues), + _dp(IAccelrated::getAccelrator()) + { + for (size_t i(0); i < numDocs; i++) { + for (size_t j(0); j < numValues; j++) { + _values[i*numValues + j] = j; + } + } + for (size_t j(0); j < numValues; j++) { + _query[j] = j; + } + } + virtual void compute(size_t docId) const { + _dp->dotProduct(&_query[0], &_values[docId * _query.size()], _query.size()); + } +private: + std::vector<T> _values; + std::vector<T> _query; + IAccelrated::UP _dp; +}; + +class SparseBenchmark : public Benchmark +{ +public: + SparseBenchmark(size_t numDocs, size_t numValues, size_t numQueryValues) : + _numValues(numValues), + _values(numDocs*numValues) + { + for (size_t i(0); i < numDocs; i++) { + for (size_t j(0); j < numValues; j++) { + size_t k(numValues < numQueryValues ? (j*numQueryValues)/numValues : j); + _values[i*numValues + j] = P(k, k); + } + } + } +protected: + struct P { + P(uint32_t key=0, int32_t value=0) : + _key(key), + _value(value) + { } + uint32_t _key; + int32_t _value; + }; + size_t _numValues; + std::vector<P> _values; +}; + +class UnorderedSparseBenchmark : public SparseBenchmark +{ +private: + typedef hash_map<uint32_t, int32_t> map; +public: + UnorderedSparseBenchmark(size_t numDocs, size_t numValues, size_t numQueryValues) : + SparseBenchmark(numDocs, numValues, numQueryValues) + { + for (size_t j(0); j < numQueryValues; j++) { + _query[j] = j; + } + } +private: + virtual void compute(size_t docId) const { + int64_t sum(0); + size_t offset(docId*_numValues); + const auto e(_query.end()); + for (size_t i(0); i < _numValues; i++) { + auto it = _query.find(_values[offset + i]._key); + if (it != e) { + sum += static_cast<int64_t>(_values[offset + i]._value) * it->second; + } + } + } + map _query; +}; + +class OrderedSparseBenchmark : public SparseBenchmark +{ +private: +public: + OrderedSparseBenchmark(size_t numDocs, size_t numValues, size_t numQueryValues) : + SparseBenchmark(numDocs, numValues, numQueryValues), + _query(numQueryValues) + { + for (size_t j(0); j < numQueryValues; j++) { + size_t k(numValues > numQueryValues ? j*numValues/numQueryValues : j); + _query[j] = P(k, k); + } + } +private: + virtual void compute(size_t docId) const { + int64_t sum(0); + size_t offset(docId*_numValues); + + for (size_t a(0), b(0); a < _query.size() && b < _numValues; b++) { + for (; a < _query.size() && (_query[a]._key <= _values[offset + b]._key); a++); + if (_query[a]._key == _values[offset + b]._key) { + sum += static_cast<int64_t>(_values[offset + b]._value) * _query[a]._value; + } + } + } + std::vector<P> _query; +}; + +int main(int argc, char *argv[]) +{ + size_t numDocs(1); + size_t numValues(1000); + size_t numQueryValues(1000); + size_t numQueries(1000000); + string type("full"); + if ( argc > 1) { + type = argv[1]; + } + if ( argc > 2) { + numQueries = strtoul(argv[2], NULL, 0); + } + if ( argc > 3) { + numDocs = strtoul(argv[3], NULL, 0); + } + if ( argc > 4) { + numValues = strtoul(argv[4], NULL, 0); + } + if ( argc > 5) { + numQueryValues = strtoul(argv[5], NULL, 0); + } + + std::cout << "type = " << type << std::endl; + std::cout << "numQueries = " << numQueries << std::endl; + std::cout << "numDocs = " << numDocs << std::endl; + std::cout << "numValues = " << numValues << std::endl; + std::cout << "numQueryValues = " << numQueryValues << std::endl; + if (type == "full") { + FullBenchmark<int32_t> bm(numDocs, numValues); + runBenchmark(numQueries, numDocs, bm); + } else if (type == "sparse-ordered") { + OrderedSparseBenchmark bm(numDocs, numValues, numQueryValues); + runBenchmark(numQueries, numDocs, bm); + } else if (type == "sparse-unordered") { + UnorderedSparseBenchmark bm(numDocs, numValues, numQueryValues); + runBenchmark(numQueries, numDocs, bm); + } else { + std::cerr << "type '" << type << "' is unknown." << std::endl; + } + + return 0; +} + diff --git a/staging_vespalib/src/tests/encoding/.gitignore b/staging_vespalib/src/tests/encoding/.gitignore new file mode 100644 index 00000000000..a3e9c375723 --- /dev/null +++ b/staging_vespalib/src/tests/encoding/.gitignore @@ -0,0 +1,3 @@ +.depend +Makefile +*_test diff --git a/staging_vespalib/src/tests/encoding/base64/.gitignore b/staging_vespalib/src/tests/encoding/base64/.gitignore new file mode 100644 index 00000000000..04f2994a28f --- /dev/null +++ b/staging_vespalib/src/tests/encoding/base64/.gitignore @@ -0,0 +1 @@ +staging_vespalib_base64_test_app diff --git a/staging_vespalib/src/tests/encoding/base64/CMakeLists.txt b/staging_vespalib/src/tests/encoding/base64/CMakeLists.txt new file mode 100644 index 00000000000..bc515aa26d6 --- /dev/null +++ b/staging_vespalib/src/tests/encoding/base64/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(staging_vespalib_base64_test_app + SOURCES + base64_test.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_base64_test_app COMMAND staging_vespalib_base64_test_app) diff --git a/staging_vespalib/src/tests/encoding/base64/DESC b/staging_vespalib/src/tests/encoding/base64/DESC new file mode 100644 index 00000000000..e9ece74e119 --- /dev/null +++ b/staging_vespalib/src/tests/encoding/base64/DESC @@ -0,0 +1 @@ +base64 test. Take a look at base64.cpp for details. diff --git a/staging_vespalib/src/tests/encoding/base64/FILES b/staging_vespalib/src/tests/encoding/base64/FILES new file mode 100644 index 00000000000..475b11151a3 --- /dev/null +++ b/staging_vespalib/src/tests/encoding/base64/FILES @@ -0,0 +1 @@ +base64.cpp diff --git a/staging_vespalib/src/tests/encoding/base64/base64_test.cpp b/staging_vespalib/src/tests/encoding/base64/base64_test.cpp new file mode 100644 index 00000000000..e765ac7d601 --- /dev/null +++ b/staging_vespalib/src/tests/encoding/base64/base64_test.cpp @@ -0,0 +1,89 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include <vespa/fastos/fastos.h> +#include <vespa/vespalib/encoding/base64.h> + +#include <vespa/log/log.h> +#include <iostream> +#include <vector> +#include <vespa/vespalib/testkit/testapp.h> + +LOG_SETUP("base64_test"); + +using namespace vespalib; + +TEST_SETUP(Test); + +int +Test::Main() +{ + TEST_INIT("base64_test"); + + // Basic test without padding + std::string source = "No need to pad this string."; + std::string encoded = Base64::encode(source); + std::string expected = "Tm8gbmVlZCB0byBwYWQgdGhpcyBzdHJpbmcu"; + std::string decoded = Base64::decode(encoded); + + EXPECT_EQUAL(expected, encoded); + EXPECT_EQUAL(source, decoded); + + EXPECT_TRUE(static_cast<uint32_t>( + Base64::getMaximumEncodeLength(source.size())) >= encoded.size()); + EXPECT_TRUE(static_cast<uint32_t>( + Base64::getMaximumDecodeLength(encoded.size())) >= source.size()); + + // Basic string that needs padding + source = "This string will need to be padded."; + encoded = Base64::encode(source); + expected = "VGhpcyBzdHJpbmcgd2lsbCBuZWVkIHRvIGJlIHBhZGRlZC4="; + decoded = Base64::decode(encoded); + + EXPECT_EQUAL(expected, encoded); + EXPECT_EQUAL(source, decoded); + + EXPECT_TRUE(static_cast<uint32_t>( + Base64::getMaximumEncodeLength(source.size())) >= encoded.size()); + EXPECT_TRUE(static_cast<uint32_t>( + Base64::getMaximumDecodeLength(encoded.size())) >= source.size()); + + // Check that max sizes are good for whatever input sizes + source = ""; + for (uint32_t i=0; i<100; ++i) { + source += "a"; + // Code will assert if -1 is returned from either + // getMaximumEncodeLength() or getMaximumDecodeLength(). + encoded = Base64::encode(source); + decoded = Base64::decode(encoded); + EXPECT_EQUAL(source, decoded); + } + + // Check that -1 is returned on too little space when encoding + source = "Checking that -1 is returned when not enough space to encode"; + std::vector<char> buffer(100, '\0'); + uint32_t minSizeNeeded = 81; + for (uint32_t i=0; i<minSizeNeeded; ++i) { + EXPECT_EQUAL(-1, Base64::encode(source.c_str(), source.size(), + &buffer[0], i)); + } + EXPECT_EQUAL(80, Base64::encode(source.c_str(), source.size(), + &buffer[0], minSizeNeeded)); + EXPECT_EQUAL(Base64::encode(source), std::string(&buffer[0], 80)); + EXPECT_TRUE(minSizeNeeded <= static_cast<uint32_t>( + Base64::getMaximumEncodeLength(source.size()))); + + EXPECT_TRUE(buffer[80] == '\0'); + + // Check that -1 is returned on too little space when decoding + encoded = Base64::encode(source); + minSizeNeeded = 60; + for (uint32_t i=0; i<minSizeNeeded; ++i) { + EXPECT_EQUAL(-1, Base64::decode(encoded.c_str(), encoded.size(), + &buffer[0], i)); + } + EXPECT_EQUAL(60, Base64::decode(encoded.c_str(), encoded.size(), + &buffer[0], minSizeNeeded)); + EXPECT_EQUAL(source, std::string(&buffer[0], 60)); + + TEST_DONE(); +} diff --git a/staging_vespalib/src/tests/fileheader/.gitignore b/staging_vespalib/src/tests/fileheader/.gitignore new file mode 100644 index 00000000000..909655ba711 --- /dev/null +++ b/staging_vespalib/src/tests/fileheader/.gitignore @@ -0,0 +1,6 @@ +*.So +.depend* +Makefile +fileheader.tmp +fileheader_test +staging_vespalib_fileheader_test_app diff --git a/staging_vespalib/src/tests/fileheader/CMakeLists.txt b/staging_vespalib/src/tests/fileheader/CMakeLists.txt new file mode 100644 index 00000000000..9e8e834147e --- /dev/null +++ b/staging_vespalib/src/tests/fileheader/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(staging_vespalib_fileheader_test_app + SOURCES + fileheader_test.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_fileheader_test_app COMMAND staging_vespalib_fileheader_test_app) diff --git a/staging_vespalib/src/tests/fileheader/DESC b/staging_vespalib/src/tests/fileheader/DESC new file mode 100644 index 00000000000..feb98035803 --- /dev/null +++ b/staging_vespalib/src/tests/fileheader/DESC @@ -0,0 +1 @@ +fileheader test. Take a look at fileheader.cpp for details. diff --git a/staging_vespalib/src/tests/fileheader/FILES b/staging_vespalib/src/tests/fileheader/FILES new file mode 100644 index 00000000000..f1ade37b054 --- /dev/null +++ b/staging_vespalib/src/tests/fileheader/FILES @@ -0,0 +1 @@ +fileheader.cpp diff --git a/staging_vespalib/src/tests/fileheader/fileheader.dat b/staging_vespalib/src/tests/fileheader/fileheader.dat Binary files differnew file mode 100644 index 00000000000..90660f64b98 --- /dev/null +++ b/staging_vespalib/src/tests/fileheader/fileheader.dat diff --git a/staging_vespalib/src/tests/fileheader/fileheader_test.cpp b/staging_vespalib/src/tests/fileheader/fileheader_test.cpp new file mode 100644 index 00000000000..2aaeeea58a8 --- /dev/null +++ b/staging_vespalib/src/tests/fileheader/fileheader_test.cpp @@ -0,0 +1,694 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/fastos/fastos.h> +#include <vespa/log/log.h> +LOG_SETUP("fileheader_test"); + +#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/data/fileheader.h> +#include <iostream> + +using namespace vespalib; + +class Test : public vespalib::TestApp { +private: + void testTag(); + void testTagErrors(); + void testTagIteration(); + void testGenericHeader(); + void testBufferReader(); + void testBufferWriter(); + void testBufferAccess(); + void testFileReader(); + void testFileWriter(); + void testFileHeader(); + void testFileAlign(); + void testFileSize(); + void testReadErrors(); + bool testReadError(DataBuffer &buf, const std::string &expected); + void testWriteErrors(); + void testRewriteErrors(); + void testLayout(); + + void + testReadSize(bool mapped); + + void + testReadSizeErrors(bool mapped); + + bool + testReadSizeError(DataBuffer &buf, const std::string &expected, + bool mapped); + +public: + int Main() { + TEST_INIT("fileheader_test"); + + testTag(); TEST_FLUSH(); + testTagErrors(); TEST_FLUSH(); + testTagIteration(); TEST_FLUSH(); + testGenericHeader(); TEST_FLUSH(); + testBufferReader(); TEST_FLUSH(); + testBufferWriter(); TEST_FLUSH(); + testBufferAccess(); TEST_FLUSH(); + testFileReader(); TEST_FLUSH(); + testFileWriter(); TEST_FLUSH(); + testFileHeader(); TEST_FLUSH(); + testFileAlign(); TEST_FLUSH(); + testFileSize(); TEST_FLUSH(); + testReadErrors(); TEST_FLUSH(); + testWriteErrors(); TEST_FLUSH(); + testRewriteErrors(); TEST_FLUSH(); + testLayout(); TEST_FLUSH(); + testReadSize(false); TEST_FLUSH(); + testReadSizeErrors(false); TEST_FLUSH(); + testReadSize(true); TEST_FLUSH(); + testReadSizeErrors(true); TEST_FLUSH(); + + TEST_DONE(); + } +}; + +TEST_APPHOOK(Test); + +void +Test::testTag() +{ + { + std::vector<GenericHeader::Tag> tags; + tags.push_back(GenericHeader::Tag("foo", 6.9)); + tags.push_back(GenericHeader::Tag("foo", 6.9f)); + for (std::vector<GenericHeader::Tag>::iterator it = tags.begin(); + it != tags.end(); ++it) + { + GenericHeader::Tag tag = *it; + for (uint32_t i = 0; i < 2; ++i) { + EXPECT_EQUAL(GenericHeader::Tag::TYPE_FLOAT, tag.getType()); + EXPECT_EQUAL("foo", tag.getName()); + EXPECT_TRUE(tag.asString().empty()); + EXPECT_APPROX(6.9, tag.asFloat(), 1E-6); + EXPECT_EQUAL(0, tag.asInteger()); + + uint32_t len = tag.getSize(); + DataBuffer buf(len); + EXPECT_EQUAL(len, tag.write(buf)); + + GenericHeader::Tag tmp; + EXPECT_EQUAL(len, tmp.read(buf)); + tag = tmp; + } + } + } + { + std::vector<GenericHeader::Tag> tags; + tags.push_back(GenericHeader::Tag("foo", (int8_t)69)); + tags.push_back(GenericHeader::Tag("foo", (uint8_t)69)); + tags.push_back(GenericHeader::Tag("foo", (int16_t)69)); + tags.push_back(GenericHeader::Tag("foo", (uint16_t)69)); + tags.push_back(GenericHeader::Tag("foo", (int32_t)69)); + tags.push_back(GenericHeader::Tag("foo", (uint32_t)69)); + tags.push_back(GenericHeader::Tag("foo", (int64_t)69)); + for (std::vector<GenericHeader::Tag>::iterator it = tags.begin(); + it != tags.end(); ++it) + { + GenericHeader::Tag tag = *it; + for (uint32_t i = 0; i < 2; ++i) { + EXPECT_EQUAL(GenericHeader::Tag::TYPE_INTEGER, tag.getType()); + EXPECT_EQUAL("foo", tag.getName()); + EXPECT_TRUE(tag.asString().empty()); + EXPECT_EQUAL(0.0, tag.asFloat()); + EXPECT_EQUAL(69l, tag.asInteger()); + + uint32_t len = tag.getSize(); + DataBuffer buf(len); + EXPECT_EQUAL(len, tag.write(buf)); + + GenericHeader::Tag tmp; + EXPECT_EQUAL(len, tmp.read(buf)); + tag = tmp; + } + } + } + { + GenericHeader::Tag tag("foo", "bar"); + for (uint32_t i = 0; i < 2; ++i) { + EXPECT_EQUAL(GenericHeader::Tag::TYPE_STRING, tag.getType()); + EXPECT_EQUAL("foo", tag.getName()); + EXPECT_EQUAL("bar", tag.asString()); + EXPECT_EQUAL(0.0, tag.asFloat()); + EXPECT_EQUAL(0, tag.asInteger()); + + uint32_t len = tag.getSize(); + DataBuffer buf(len); + EXPECT_EQUAL(len, tag.write(buf)); + + GenericHeader::Tag tmp; + EXPECT_EQUAL(len, tmp.read(buf)); + tag = tmp; + } + } +} + +void +Test::testTagErrors() +{ + DataBuffer buf(1024); + buf.writeBytes("foo", 3); + buf.writeInt8(0); + buf.writeInt8((uint8_t)GenericHeader::Tag::TYPE_EMPTY); + + GenericHeader::Tag tag("bar", 6.9); + try { + tag.read(buf); + EXPECT_TRUE(false); + } catch (IllegalHeaderException &e) { + EXPECT_EQUAL("Can not deserialize empty tag.", e.getMessage()); + } + EXPECT_EQUAL("bar", tag.getName()); + EXPECT_EQUAL(GenericHeader::Tag::TYPE_FLOAT, tag.getType()); + EXPECT_EQUAL(6.9, tag.asFloat()); +} + +void +Test::testTagIteration() +{ + GenericHeader header; + header.putTag(GenericHeader::Tag("foo", 6.9)); + header.putTag(GenericHeader::Tag("bar", 6699)); + header.putTag(GenericHeader::Tag("baz", "666999")); + + EXPECT_EQUAL(3u, header.getNumTags()); + EXPECT_EQUAL("bar", header.getTag(0).getName()); + EXPECT_EQUAL("baz", header.getTag(1).getName()); + EXPECT_EQUAL("foo", header.getTag(2).getName()); +} + +void +Test::testGenericHeader() +{ + GenericHeader header; + EXPECT_TRUE(header.isEmpty()); + EXPECT_EQUAL(0u, header.getNumTags()); + EXPECT_TRUE(!header.hasTag("foo")); + EXPECT_TRUE(header.getTag("foo").isEmpty()); + EXPECT_TRUE(!header.hasTag("bar")); + EXPECT_TRUE(header.getTag("bar").isEmpty()); + EXPECT_TRUE(!header.hasTag("baz")); + EXPECT_TRUE(header.getTag("baz").isEmpty()); + + header.putTag(GenericHeader::Tag("foo", 6.9)); + EXPECT_TRUE(!header.isEmpty()); + EXPECT_EQUAL(1u, header.getNumTags()); + EXPECT_TRUE(header.hasTag("foo")); + EXPECT_EQUAL(6.9, header.getTag("foo").asFloat()); + EXPECT_TRUE(!header.hasTag("bar")); + EXPECT_TRUE(header.getTag("bar").isEmpty()); + EXPECT_TRUE(!header.hasTag("baz")); + EXPECT_TRUE(header.getTag("baz").isEmpty()); + + header.putTag(GenericHeader::Tag("bar", 6699)); + EXPECT_TRUE(!header.isEmpty()); + EXPECT_EQUAL(2u, header.getNumTags()); + EXPECT_TRUE(header.hasTag("foo")); + EXPECT_EQUAL(6.9, header.getTag("foo").asFloat()); + EXPECT_TRUE(header.hasTag("bar")); + EXPECT_EQUAL(6699, header.getTag("bar").asInteger()); + EXPECT_TRUE(!header.hasTag("baz")); + EXPECT_TRUE(header.getTag("baz").isEmpty()); + + header.putTag(GenericHeader::Tag("baz", "666999")); + EXPECT_TRUE(header.hasTag("foo")); + EXPECT_EQUAL(6.9, header.getTag("foo").asFloat()); + EXPECT_TRUE(header.hasTag("bar")); + EXPECT_EQUAL(6699, header.getTag("bar").asInteger()); + EXPECT_TRUE(header.hasTag("baz")); + EXPECT_EQUAL("666999", header.getTag("baz").asString()); + + header.removeTag("bar"); + EXPECT_TRUE(header.hasTag("foo")); + EXPECT_EQUAL(6.9, header.getTag("foo").asFloat()); + EXPECT_TRUE(!header.hasTag("bar")); + EXPECT_TRUE(header.getTag("bar").isEmpty()); + EXPECT_TRUE(header.hasTag("baz")); + EXPECT_EQUAL("666999", header.getTag("baz").asString()); + + header.removeTag("foo"); + EXPECT_TRUE(!header.hasTag("foo")); + EXPECT_TRUE(header.getTag("foo").isEmpty()); + EXPECT_TRUE(!header.hasTag("bar")); + EXPECT_TRUE(header.getTag("bar").isEmpty()); + EXPECT_TRUE(header.hasTag("baz")); + EXPECT_EQUAL("666999", header.getTag("baz").asString()); + + header.removeTag("baz"); + EXPECT_TRUE(!header.hasTag("foo")); + EXPECT_TRUE(header.getTag("foo").isEmpty()); + EXPECT_TRUE(!header.hasTag("bar")); + EXPECT_TRUE(header.getTag("bar").isEmpty()); + EXPECT_TRUE(!header.hasTag("baz")); + EXPECT_TRUE(header.getTag("baz").isEmpty()); +} + +void +Test::testBufferReader() +{ + DataBuffer src(256); + for (uint32_t i = 0; i < 256; ++i) { + src.writeInt8((uint8_t)i); + } + + GenericHeader::BufferReader reader(src); + + char dst[7]; + uint32_t sum = 0; + while (sum < 256) { + uint32_t len = (uint32_t)reader.getData(dst, 7); + for (uint32_t i = 0; i < len; ++i) { + EXPECT_EQUAL(sum + i, (uint8_t)dst[i]); + } + sum += len; + } + EXPECT_EQUAL(256u, sum); +} + +void +Test::testBufferWriter() +{ + DataBuffer dst(256); + GenericHeader::BufferWriter writer(dst); + + uint32_t sum = 0; + while(sum < 256) { + char src[7]; + for (uint32_t i = 0; i < 7; ++i) { + src[i] = (uint8_t)(sum + i); + } + uint32_t len = std::min(7u, 256 - sum); + EXPECT_EQUAL(len, (uint32_t)writer.putData(src, len)); + sum += len; + } + EXPECT_EQUAL(256u, sum); + + // flip dst + for (uint32_t i = 0; i < 256; ++i) { + uint8_t b = dst.readInt8(); + EXPECT_EQUAL(i, (uint32_t)b); + } +} + +void +Test::testBufferAccess() +{ + DataBuffer buf; + uint32_t len = 0; + { + GenericHeader header; + header.putTag(GenericHeader::Tag("foo", 6.9)); + header.putTag(GenericHeader::Tag("bar", 6699)); + header.putTag(GenericHeader::Tag("baz", "666999")); + + int64_t bval = 0x1234567890abcdefLL; + header.putTag(GenericHeader::Tag("big", bval)); + + len = header.getSize(); + buf.ensureFree(len); + GenericHeader::BufferWriter writer(buf); + EXPECT_EQUAL(len, header.write(writer)); + } + { + GenericHeader header; + GenericHeader::BufferReader reader(buf); + EXPECT_EQUAL(len, header.read(reader)); + + EXPECT_TRUE(header.hasTag("foo")); + EXPECT_EQUAL(6.9, header.getTag("foo").asFloat()); + EXPECT_TRUE(header.hasTag("bar")); + EXPECT_EQUAL(6699, header.getTag("bar").asInteger()); + EXPECT_TRUE(header.hasTag("baz")); + EXPECT_EQUAL("666999", header.getTag("baz").asString()); + EXPECT_TRUE(header.hasTag("big")); + EXPECT_EQUAL(0x1234567890abcdefLL, header.getTag("big").asInteger()); + } +} + +void +Test::testFileReader() +{ + { + FastOS_File file; + ASSERT_TRUE(file.OpenWriteOnlyTruncate("fileheader.tmp")); + + uint8_t buf[256]; + for (uint32_t i = 0; i < 256; ++i) { + buf[i] = (uint8_t)i; + } + EXPECT_EQUAL(256, file.Write2(buf, 256)); + + file.Close(); + } + { + FastOS_File file; + ASSERT_TRUE(file.OpenReadOnly("fileheader.tmp")); + FileHeader::FileReader reader(file); + + char buf[7]; + uint32_t sum = 0; + while(sum < 256) { + uint32_t len = (uint32_t)reader.getData(buf, 7); + for (uint32_t i = 0; i < len; ++i) { + EXPECT_EQUAL(sum + i, (uint8_t)buf[i]); + } + sum += len; + } + EXPECT_EQUAL(256u, sum); + + file.Close(); + file.Delete(); + } +} + +void +Test::testFileWriter() +{ + { + FastOS_File file; + ASSERT_TRUE(file.OpenWriteOnlyTruncate("fileheader.tmp")); + FileHeader::FileWriter writer(file); + + uint32_t sum = 0; + while(sum < 256) { + char src[7]; + for (uint32_t i = 0; i < 7; ++i) { + src[i] = (uint8_t)(sum + i); + } + uint32_t len = std::min(7u, 256 - sum); + EXPECT_EQUAL(len, (uint32_t)writer.putData(src, len)); + sum += len; + } + EXPECT_EQUAL(256u, sum); + } + { + FastOS_File file; + ASSERT_TRUE(file.OpenReadOnly("fileheader.tmp")); + + uint8_t buf[256]; + EXPECT_EQUAL(256, file.Read(buf, 256)); + for (uint32_t i = 0; i < 256; ++i) { + EXPECT_EQUAL(i, (uint32_t)buf[i]); + } + + file.Close(); + file.Delete(); + } +} + +void +Test::testFileHeader() +{ + uint32_t len = 0; + { + FileHeader header; + header.putTag(FileHeader::Tag("foo", 6.9)); + header.putTag(FileHeader::Tag("bar", 6699)); + header.putTag(FileHeader::Tag("baz", "666999")); + + FastOS_File file; + ASSERT_TRUE(file.OpenWriteOnlyTruncate("fileheader.tmp")); + len = header.writeFile(file); + EXPECT_EQUAL(len, header.getSize()); + file.Close(); + } + { + FastOS_File file; + ASSERT_TRUE(file.OpenReadWrite("fileheader.tmp")); + + FileHeader header; + EXPECT_EQUAL(len, header.readFile(file)); + EXPECT_EQUAL(len, header.getSize()); + + EXPECT_TRUE(header.hasTag("foo")); + EXPECT_EQUAL(6.9, header.getTag("foo").asFloat()); + EXPECT_TRUE(header.hasTag("bar")); + EXPECT_EQUAL(6699, header.getTag("bar").asInteger()); + EXPECT_TRUE(header.hasTag("baz")); + EXPECT_EQUAL("666999", header.getTag("baz").asString()); + + header.putTag(FileHeader::Tag("foo", 9.6)); + header.putTag(FileHeader::Tag("bar", 9966)); + header.putTag(FileHeader::Tag("baz", "999666")); + EXPECT_EQUAL(len, header.getSize()); + EXPECT_EQUAL(len, header.rewriteFile(file)); + + file.Close(); + } + { + FileHeader header; + + FastOS_File file; + ASSERT_TRUE(file.OpenReadOnly("fileheader.tmp")); + EXPECT_EQUAL(len, header.readFile(file)); + EXPECT_EQUAL(len, header.getSize()); + file.Close(); + file.Delete(); + + EXPECT_TRUE(header.hasTag("foo")); + EXPECT_EQUAL(9.6, header.getTag("foo").asFloat()); + EXPECT_TRUE(header.hasTag("bar")); + EXPECT_EQUAL(9966, header.getTag("bar").asInteger()); + EXPECT_TRUE(header.hasTag("baz")); + EXPECT_EQUAL("999666", header.getTag("baz").asString()); + } +} + +void +Test::testFileAlign() +{ + for (uint32_t alignTo = 1; alignTo < 16; ++alignTo) { + FileHeader header(alignTo); + header.putTag(FileHeader::Tag("foo", "bar")); + EXPECT_EQUAL(0u, header.getSize() % alignTo); + } +} + +void +Test::testFileSize() +{ + for (uint32_t minSize = 0; minSize < 512; ++minSize) { + FileHeader header(1u, minSize); + header.putTag(FileHeader::Tag("foo", "bar")); + EXPECT_TRUE(header.getSize() >= minSize); + } +} + +void +Test::testReadErrors() +{ + { + DataBuffer buf; + EXPECT_TRUE(testReadError(buf, "Failed to read header info.")); + } + { + DataBuffer buf; + buf.writeInt32(0xDEADBEAF); + buf.writeInt32(8); + EXPECT_TRUE(testReadError(buf, "Failed to verify magic bits.")); + } + { + DataBuffer buf; + buf.writeInt32(GenericHeader::MAGIC); + buf.writeInt32(8); + EXPECT_TRUE(testReadError(buf, "Failed to verify header size.")); + } + { + DataBuffer buf; + buf.writeInt32(GenericHeader::MAGIC); + buf.writeInt32(16); + buf.writeInt32(-1); + buf.writeInt32(0); + EXPECT_TRUE(testReadError(buf, "Failed to verify header version.")); + } + { + DataBuffer buf; + buf.writeInt32(GenericHeader::MAGIC); + buf.writeInt32(21); + buf.writeInt32(GenericHeader::VERSION); + buf.writeInt32(1); + buf.writeBytes("foo", 3); + buf.writeInt8(0); + buf.writeInt8((uint8_t)GenericHeader::Tag::TYPE_EMPTY); + EXPECT_TRUE(testReadError(buf, "Can not deserialize empty tag.")); + } +} + +bool +Test::testReadError(DataBuffer &buf, const std::string &expected) +{ + GenericHeader header; + header.putTag(GenericHeader::Tag("foo", "bar")); + try { + GenericHeader::BufferReader reader(buf); + header.read(reader); + EXPECT_TRUE(false); + return false; + } catch (IllegalHeaderException &e) { + if (!EXPECT_EQUAL(expected, e.getMessage())) { + return false; + } + } + if (!EXPECT_EQUAL(1u, header.getNumTags())) { + return false; + } + if (!EXPECT_EQUAL("bar", header.getTag("foo").asString())) { + return false; + } + return true; +} + +void +Test::testWriteErrors() +{ + GenericHeader header; + header.putTag(GenericHeader::Tag("foo", 69)); + + DataBuffer buf; + buf.ensureFree(4); + buf.moveFreeToData(buf.getFreeLen() - 4); + EXPECT_TRUE(header.getSize() > buf.getFreeLen()); + try { + GenericHeader::BufferWriter writer(buf); + header.write(writer); + EXPECT_TRUE(false); + } catch (IllegalHeaderException &e) { + EXPECT_EQUAL("Failed to write header.", e.getMessage()); + } + + EXPECT_TRUE(header.hasTag("foo")); + EXPECT_EQUAL(69, header.getTag("foo").asInteger()); +} + +void +Test::testRewriteErrors() +{ + FileHeader header; + header.putTag(FileHeader::Tag("foo", "bar")); + uint32_t len = header.getSize(); + + FastOS_File file; + ASSERT_TRUE(file.OpenWriteOnlyTruncate("fileheader.tmp")); + EXPECT_EQUAL(len, header.writeFile(file)); + file.Close(); + + ASSERT_TRUE(file.OpenReadWrite("fileheader.tmp")); + header.putTag(FileHeader::Tag("baz", "cox")); + EXPECT_TRUE(len != header.getSize()); + try { + header.rewriteFile(file); + EXPECT_TRUE(false); + } catch (IllegalHeaderException &e) { + EXPECT_EQUAL("Failed to rewrite resized header.", e.getMessage()); + } + file.Close(); +} + +void +Test::testLayout() +{ + FastOS_File file; + ASSERT_TRUE(file.OpenReadOnly("fileheader.dat")); + + FileHeader header; + uint32_t len = header.readFile(file); + EXPECT_EQUAL(len, header.getSize()); + file.Close(); + + EXPECT_TRUE(header.hasTag("foo")); + EXPECT_EQUAL(6.9, header.getTag("foo").asFloat()); + EXPECT_TRUE(header.hasTag("bar")); + EXPECT_EQUAL(6699, header.getTag("bar").asInteger()); + EXPECT_TRUE(header.hasTag("baz")); + EXPECT_EQUAL("666999", header.getTag("baz").asString()); +} + + +void +Test::testReadSize(bool mapped) +{ + DataBuffer buf; + buf.writeInt32(GenericHeader::MAGIC); + buf.writeInt32(21); + buf.writeInt32(GenericHeader::VERSION); + buf.writeInt32(1); + uint32_t headerLen = 0u; + if (mapped) { + GenericHeader::MMapReader reader(buf.getData(), buf.getDataLen()); + headerLen = FileHeader::readSize(reader); + } else { + GenericHeader::BufferReader reader(buf); + headerLen = FileHeader::readSize(reader); + } + EXPECT_EQUAL(21u, headerLen); +} + + +void +Test::testReadSizeErrors(bool mapped) +{ + { + DataBuffer buf; + EXPECT_TRUE(testReadSizeError(buf, "Failed to read header info.", + mapped)); + } + { + DataBuffer buf; + buf.writeInt32(0xDEADBEAF); + buf.writeInt32(8); + buf.writeInt32(0); + buf.writeInt32(0); + EXPECT_TRUE(testReadSizeError(buf, "Failed to verify magic bits.", + mapped)); + } + { + DataBuffer buf; + buf.writeInt32(GenericHeader::MAGIC); + buf.writeInt32(8); + buf.writeInt32(GenericHeader::VERSION); + buf.writeInt32(0); + EXPECT_TRUE(testReadSizeError(buf, "Failed to verify header size.", + mapped)); + } + { + DataBuffer buf; + buf.writeInt32(GenericHeader::MAGIC); + buf.writeInt32(16); + buf.writeInt32(-1); + buf.writeInt32(0); + EXPECT_TRUE(testReadSizeError(buf, + "Failed to verify header version.", + mapped)); + } +} + + +bool +Test::testReadSizeError(DataBuffer &buf, const std::string &expected, + bool mapped) +{ + uint32_t headerLen = 0u; + try { + if (mapped) { + GenericHeader::MMapReader reader(buf.getData(), buf.getDataLen()); + headerLen = FileHeader::readSize(reader); + } else { + GenericHeader::BufferReader reader(buf); + headerLen = FileHeader::readSize(reader); + } + EXPECT_TRUE(false); + return false; + } catch (IllegalHeaderException &e) { + if (!EXPECT_EQUAL(expected, e.getMessage())) { + return false; + } + } + EXPECT_EQUAL(headerLen, 0u); + return true; +} + diff --git a/staging_vespalib/src/tests/floatingpointtype/.gitignore b/staging_vespalib/src/tests/floatingpointtype/.gitignore new file mode 100644 index 00000000000..f99dd0fd707 --- /dev/null +++ b/staging_vespalib/src/tests/floatingpointtype/.gitignore @@ -0,0 +1,4 @@ +.depend +Makefile +floatingpointtype_test +staging_vespalib_floatingpointtype_test_app diff --git a/staging_vespalib/src/tests/floatingpointtype/CMakeLists.txt b/staging_vespalib/src/tests/floatingpointtype/CMakeLists.txt new file mode 100644 index 00000000000..88c73073ed4 --- /dev/null +++ b/staging_vespalib/src/tests/floatingpointtype/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(staging_vespalib_floatingpointtype_test_app + SOURCES + floatingpointtypetest.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_floatingpointtype_test_app COMMAND staging_vespalib_floatingpointtype_test_app) diff --git a/staging_vespalib/src/tests/floatingpointtype/DESC b/staging_vespalib/src/tests/floatingpointtype/DESC new file mode 100644 index 00000000000..4bdf790ff44 --- /dev/null +++ b/staging_vespalib/src/tests/floatingpointtype/DESC @@ -0,0 +1 @@ +Floating point wrapper test. diff --git a/staging_vespalib/src/tests/floatingpointtype/FILES b/staging_vespalib/src/tests/floatingpointtype/FILES new file mode 100644 index 00000000000..dd496cb1e12 --- /dev/null +++ b/staging_vespalib/src/tests/floatingpointtype/FILES @@ -0,0 +1 @@ +floatingpointtypetest.cpp diff --git a/staging_vespalib/src/tests/floatingpointtype/floatingpointtypetest.cpp b/staging_vespalib/src/tests/floatingpointtype/floatingpointtypetest.cpp new file mode 100644 index 00000000000..41eed2f7dc9 --- /dev/null +++ b/staging_vespalib/src/tests/floatingpointtype/floatingpointtypetest.cpp @@ -0,0 +1,75 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + // Include first to make sure it includes all it need. +#include <vespa/fastos/fastos.h> +#include <vespa/vespalib/objects/floatingpointtype.h> + +#include <vespa/vespalib/testkit/testapp.h> + +class Test : public vespalib::TestApp +{ +public: + void testFloatingPoint(); + int Main(); +}; + +void +Test::testFloatingPoint() +{ + vespalib::Double d1(1.0); + vespalib::Double d2(1.000000000000001); + vespalib::Double d3(-1.00000000000001); + vespalib::Double d4(4.0); + + EXPECT_TRUE(d1.getValue() != d2.getValue()); + + EXPECT_EQUAL(d1, d2); + EXPECT_EQUAL(d2, d1); + + EXPECT_NOT_EQUAL(d1, d3); + EXPECT_NOT_EQUAL(d1, d4); + + EXPECT_TRUE(d1 - d2 == 0); + EXPECT_TRUE(d2 - d1 == 0); + + EXPECT_TRUE(d1 - 1 == 0); + EXPECT_TRUE(d1 + 1 != 0); + + EXPECT_TRUE(d2 * d4 == 4.0); + EXPECT_TRUE(d2 / d4 == 0.25); + + EXPECT_TRUE(d1 >= 1); + EXPECT_TRUE(d1 <= 1); + EXPECT_TRUE(!(d1 < 1)); + EXPECT_TRUE(!(d1 > 1)); + + EXPECT_EQUAL(d2 * 4, d4); + + EXPECT_EQUAL(++d4, 5.0); + EXPECT_EQUAL(d4++, 5.0); + EXPECT_EQUAL(d4, 6.0); + + d4 /= 3; + EXPECT_EQUAL(d4, 2.00000000001); + d4 *= 2; + EXPECT_EQUAL(d4, 4.000000000001); + + EXPECT_EQUAL(--d4, 3.0); + EXPECT_EQUAL(d4--, 3.0); + EXPECT_EQUAL(d4, 2.0); + d4 /= 0.50000000001; + + EXPECT_EQUAL(d4, 4.0); + + EXPECT_TRUE(!(d3 + 1 > 0)); + EXPECT_TRUE(!(d3 + 1 < 0)); +} + +int +Test::Main() +{ + TEST_INIT("floatingpointtype_test"); + testFloatingPoint(); + TEST_DONE(); +} + +TEST_APPHOOK(Test) diff --git a/staging_vespalib/src/tests/growablebytebuffer/.gitignore b/staging_vespalib/src/tests/growablebytebuffer/.gitignore new file mode 100644 index 00000000000..8df98f682b8 --- /dev/null +++ b/staging_vespalib/src/tests/growablebytebuffer/.gitignore @@ -0,0 +1,4 @@ +.depend +Makefile +growablebytebuffer_test +staging_vespalib_growablebytebuffer_test_app diff --git a/staging_vespalib/src/tests/growablebytebuffer/CMakeLists.txt b/staging_vespalib/src/tests/growablebytebuffer/CMakeLists.txt new file mode 100644 index 00000000000..cd19f0f1256 --- /dev/null +++ b/staging_vespalib/src/tests/growablebytebuffer/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(staging_vespalib_growablebytebuffer_test_app + SOURCES + growablebytebuffer_test.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_growablebytebuffer_test_app COMMAND staging_vespalib_growablebytebuffer_test_app) diff --git a/staging_vespalib/src/tests/growablebytebuffer/growablebytebuffer_test.cpp b/staging_vespalib/src/tests/growablebytebuffer/growablebytebuffer_test.cpp new file mode 100644 index 00000000000..121f8d2e011 --- /dev/null +++ b/staging_vespalib/src/tests/growablebytebuffer/growablebytebuffer_test.cpp @@ -0,0 +1,39 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/fastos/fastos.h> +#include <vespa/log/log.h> +LOG_SETUP("guard_test"); +#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/util/growablebytebuffer.h> + +using namespace vespalib; + +class Test : public TestApp +{ +public: + void testGrowing(); + int Main(); +}; + +void +Test::testGrowing() +{ + GrowableByteBuffer buf(10); + + buf.putInt(3); + buf.putInt(7); + buf.putLong(1234); + buf.putDouble(1234); + buf.putString("hei der"); + + EXPECT_EQUAL(35u, buf.position()); +} + +int +Test::Main() +{ + TEST_INIT("guard_test"); + testGrowing(); + TEST_DONE(); +} + +TEST_APPHOOK(Test) diff --git a/staging_vespalib/src/tests/health_server/.gitignore b/staging_vespalib/src/tests/health_server/.gitignore new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/staging_vespalib/src/tests/health_server/.gitignore diff --git a/staging_vespalib/src/tests/json/.gitignore b/staging_vespalib/src/tests/json/.gitignore new file mode 100644 index 00000000000..963bafed038 --- /dev/null +++ b/staging_vespalib/src/tests/json/.gitignore @@ -0,0 +1 @@ +staging_vespalib_json_test_app diff --git a/staging_vespalib/src/tests/json/CMakeLists.txt b/staging_vespalib/src/tests/json/CMakeLists.txt new file mode 100644 index 00000000000..284e858e033 --- /dev/null +++ b/staging_vespalib/src/tests/json/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(staging_vespalib_json_test_app + SOURCES + json.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_json_test_app COMMAND staging_vespalib_json_test_app boost) diff --git a/staging_vespalib/src/tests/json/json.cpp b/staging_vespalib/src/tests/json/json.cpp new file mode 100644 index 00000000000..16d27643983 --- /dev/null +++ b/staging_vespalib/src/tests/json/json.cpp @@ -0,0 +1,473 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/fastos/fastos.h> +#include <vespa/log/log.h> +LOG_SETUP("json_test"); +#include <vespa/vespalib/testkit/testapp.h> + +#include <vespa/vespalib/util/exception.h> +#include <vespa/vespalib/util/jsonstream.h> +#include <cmath> + +using namespace vespalib; + +class JSONTest : public vespalib::TestApp +{ +private: + void testJSONWriterValues(); + void testJSONWriterObject(); + void testJSONWriterArray(); + void testJSONWriterComplex(); + void testJsonStream(); + void testJsonStreamErrors(); + void testJsonStreamStateReporting(); + +public: + int Main(); +}; + +void +JSONTest::testJSONWriterValues() +{ + JSONStringer js; + + { // bool + js.appendBool(true); + EXPECT_EQUAL(js.toString(), "true"); + js.clear().appendBool(false); + EXPECT_EQUAL(js.toString(), "false"); + } + { // double + js.clear().appendDouble(1234.5678); + EXPECT_EQUAL(js.toString(), "1234.5678"); + js.clear().appendDouble(-1234.5678); + EXPECT_EQUAL(js.toString(), "-1234.5678"); + js.clear().appendDouble(0.0); + EXPECT_EQUAL(js.toString(), "0.0"); + js.clear().appendDouble(0.00000000012345678912356789123456789); + EXPECT_EQUAL(js.toString(), "1.234567891235679e-10"); + js.clear().appendDouble(std::numeric_limits<double>::max()); + EXPECT_EQUAL(js.toString(), "1.797693134862316e+308"); + js.clear().appendDouble(std::numeric_limits<double>::min()); + EXPECT_EQUAL(js.toString(), "2.225073858507201e-308"); + js.clear().appendDouble(1.0 * (uint64_t(1) << 53)); + EXPECT_EQUAL(js.toString(), "9007199254740992.0"); + js.clear().appendDouble(1000); + EXPECT_EQUAL(js.toString(), "1000.0"); + } + { // float + js.clear().appendFloat(1234.5678f); + EXPECT_EQUAL(js.toString(), "1234.5677"); + js.clear().appendFloat(-1234.5678f); + EXPECT_EQUAL(js.toString(), "-1234.5677"); + js.clear().appendFloat(0.0f); + EXPECT_EQUAL(js.toString(), "0.0"); + js.clear().appendFloat(0.00000000012345678912356789123456789f); + EXPECT_EQUAL(js.toString(), "1.2345679e-10"); + js.clear().appendFloat(std::numeric_limits<float>::max()); + EXPECT_EQUAL(js.toString(), "3.4028235e+38"); + js.clear().appendFloat(std::numeric_limits<float>::min()); + EXPECT_EQUAL(js.toString(), "1.1754944e-38"); + js.clear().appendFloat(1.0 * (uint64_t(1) << 24)); + EXPECT_EQUAL(js.toString(), "16777216.0"); + js.clear().appendFloat(1000); + EXPECT_EQUAL(js.toString(), "1000.0"); + } + { // long + js.clear().appendInt64(4294967296ll); + EXPECT_EQUAL(js.toString(), "4294967296"); + js.clear().appendInt64(-4294967296ll); + EXPECT_EQUAL(js.toString(), "-4294967296"); + } + { // string + js.clear().appendString("string"); + EXPECT_EQUAL(js.toString(), "\"string\""); + } + { // NULL + js.clear().appendNull(); + EXPECT_EQUAL(js.toString(), "null"); + } + { // quote + js.clear().appendString("x\"y"); + EXPECT_EQUAL(js.toString(), "\"x\\\"y\""); + js.clear().appendString("x\\y"); + EXPECT_EQUAL(js.toString(), "\"x\\\\y\""); + js.clear().appendString("x/y"); + EXPECT_EQUAL(js.toString(), "\"x/y\""); + js.clear().appendString("x\by"); + EXPECT_EQUAL(js.toString(), "\"x\\by\""); + js.clear().appendString("x\fy"); + EXPECT_EQUAL(js.toString(), "\"x\\fy\""); + js.clear().appendString("x\ny"); + EXPECT_EQUAL(js.toString(), "\"x\\ny\""); + js.clear().appendString("x\ry"); + EXPECT_EQUAL(js.toString(), "\"x\\ry\""); + js.clear().appendString("x\ty"); + EXPECT_EQUAL(js.toString(), "\"x\\ty\""); + } +} + +void +JSONTest::testJSONWriterObject() +{ + JSONStringer js; + + { // single pair + js.beginObject().appendKey("k1").appendInt64(1l).endObject(); + EXPECT_EQUAL(js.toString(), "{\"k1\":1}"); + } + { // multiple pairs + js.clear().beginObject().appendKey("k1").appendInt64(1l).appendKey("k2").appendInt64(2l).endObject(); + EXPECT_EQUAL(js.toString(), "{\"k1\":1,\"k2\":2}"); + } + { // object in object + js.clear().beginObject().appendKey("k1").beginObject().appendKey("k1.1").appendInt64(11l).endObject().endObject(); + EXPECT_EQUAL(js.toString(), "{\"k1\":{\"k1.1\":11}}"); + } + { // object in object (multiple pairs) + js.clear().beginObject(). + appendKey("k1"). + beginObject(). + appendKey("k1.1").appendInt64(11l). + appendKey("k1.2").appendInt64(12l). + endObject(). + appendKey("k2"). + beginObject(). + appendKey("k2.1").appendInt64(21l). + appendKey("k2.2").appendInt64(22l). + endObject(). + endObject(); + EXPECT_EQUAL(js.toString(), "{\"k1\":{\"k1.1\":11,\"k1.2\":12},\"k2\":{\"k2.1\":21,\"k2.2\":22}}"); + } + { // array in object + js.clear().beginObject().appendKey("k1"). + beginArray().appendInt64(1l).appendInt64(2l).endArray().endObject(); + EXPECT_EQUAL(js.toString(), "{\"k1\":[1,2]}"); + } + { // array in object (multiple pairs) + js.clear().beginObject(). + appendKey("k1").beginArray().appendInt64(1l).appendInt64(2l).endArray(). + appendKey("k2").beginArray().appendInt64(3l).appendInt64(4l).endArray(). + endObject(); + EXPECT_EQUAL(js.toString(), "{\"k1\":[1,2],\"k2\":[3,4]}"); + } +} + + +void +JSONTest::testJSONWriterArray() +{ + JSONStringer js; + + { // single element + js.beginArray().appendInt64(1l).endArray(); + EXPECT_EQUAL(js.toString(), "[1]"); + } + { // multiple elements + js.clear().beginArray().appendInt64(1l).appendInt64(2l).endArray(); + EXPECT_EQUAL(js.toString(), "[1,2]"); + } + { // array in array + js.clear().beginArray().beginArray().appendInt64(1l).endArray().endArray(); + EXPECT_EQUAL(js.toString(), "[[1]]"); + } + { // array in array (multiple elements) + js.clear().beginArray(). + beginArray().appendInt64(1l).appendInt64(2l).endArray(). + beginArray().appendInt64(3l).appendInt64(4l).endArray(). + endArray(); + EXPECT_EQUAL(js.toString(), "[[1,2],[3,4]]"); + } + { // object in array + js.clear().beginArray(). + beginObject().appendKey("k1").appendInt64(1l).endObject(). + endArray(); + EXPECT_EQUAL(js.toString(), "[{\"k1\":1}]"); + } + { // object in array (multiple elements) + js.clear().beginArray(). + beginObject().appendKey("k1").appendInt64(1l).appendKey("k2").appendInt64(2l).endObject(). + beginObject().appendKey("k3").appendInt64(3l).appendKey("k4").appendInt64(4l).endObject(). + endArray(); + EXPECT_EQUAL(js.toString(), "[{\"k1\":1,\"k2\":2},{\"k3\":3,\"k4\":4}]"); + } +} + + +void +JSONTest::testJSONWriterComplex() +{ + JSONStringer js; + + js.beginObject(); + { // object + js.appendKey("k1"); + js.beginObject(); + { + js.appendKey("k1.1"); + js.appendInt64(1l); + } + { + js.appendKey("k1.2"); + js.beginArray(); + js.appendInt64(2l); + js.appendInt64(3l); + js.endArray(); + } + js.endObject(); + } + { // object of object + js.appendKey("k2"); + js.beginObject(); + { + js.appendKey("k2.1"); + js.beginObject(); + { + js.appendKey("k2.1.1"); + js.appendInt64(4l); + } + { + js.appendKey("k2.1.2"); + js.beginArray(); + js.appendInt64(5l); + js.appendInt64(6l); + js.endArray(); + } + js.endObject(); + } + js.endObject(); + } + { // array of object + js.appendKey("k3"); + js.beginArray(); + { + js.beginObject(); + { + js.appendKey("k3.1"); + js.appendInt64(7l); + } + { + js.appendKey("k3.2"); + js.beginArray(); + js.appendInt64(8l); + js.appendInt64(9l); + js.endArray(); + } + js.endObject(); + } + { + js.beginObject(); + { + js.appendKey("k3.1"); + js.appendInt64(10l); + } + { + js.appendKey("k3.2"); + js.beginArray(); + js.appendInt64(11l); + js.appendInt64(12l); + js.endArray(); + } + js.endObject(); + } + js.endArray(); + } + js.endObject(); + EXPECT_EQUAL(js.toString(), "{\"k1\":{\"k1.1\":1,\"k1.2\":[2,3]},\"k2\":{\"k2.1\":{\"k2.1.1\":4,\"k2.1.2\":[5,6]}},\"k3\":[{\"k3.1\":7,\"k3.2\":[8,9]},{\"k3.1\":10,\"k3.2\":[11,12]}]}"); +} + +namespace { + struct Builder : public vespalib::JsonStreamTypes { + void build(JsonStream& s) { + s << Object() << "k1" << Object() + << "k1.1" << 1l + << "k1.2" << Array() + << 2l << 3l << End() + << End() + << "k2" << Object() + << "k2.1" << Object() + << "k2.1.1" << 4l + << "k2.1.2" << Array() + << 5l << 6l << End() + << End() + << End() + << "k3" << Array() + << Object() + << "k3.1" << 7l + << "k3.2" << Array() + << 8l << 9l << End() + << End() + << Object() + << "k3.1" << 10l + << "k3.2" << Array() + << 11l << 12l << End() + << End() + << End() + << End(); + } + }; +} + +void +JSONTest::testJsonStream() +{ + vespalib::asciistream as; + vespalib::JsonStream stream(as); + Builder b; + b.build(stream); + stream.finalize(); + EXPECT_EQUAL(as.str(), "{\"k1\":{\"k1.1\":1,\"k1.2\":[2,3]},\"k2\":{\"k2.1\":{\"k2.1.1\":4,\"k2.1.2\":[5,6]}},\"k3\":[{\"k3.1\":7,\"k3.2\":[8,9]},{\"k3.1\":10,\"k3.2\":[11,12]}]}"); +} + +void +JSONTest::testJsonStreamErrors() +{ + using namespace vespalib::jsonstream; + // Unsupported object keys + try{ + vespalib::asciistream as; + vespalib::JsonStream stream(as); + stream << Object() << Object(); + } catch (vespalib::JsonStreamException& e) { + EXPECT_EQUAL("Invalid state on call: An object value cannot be an object key ({}(ObjectExpectingKey))", e.getReason()); + } + try{ + vespalib::asciistream as; + vespalib::JsonStream stream(as); + stream << Object() << true; + } catch (vespalib::JsonStreamException& e) { + EXPECT_EQUAL("Invalid state on call: A bool value cannot be an object key ({}(ObjectExpectingKey))", e.getReason()); + } + try{ + vespalib::asciistream as; + vespalib::JsonStream stream(as); + stream << Object() << 13; + } catch (vespalib::JsonStreamException& e) { + EXPECT_EQUAL("Invalid state on call: An int64_t value cannot be an object key ({}(ObjectExpectingKey))", e.getReason()); + } + try{ + vespalib::asciistream as; + vespalib::JsonStream stream(as); + stream << Object() << uint64_t(13); + } catch (vespalib::JsonStreamException& e) { + EXPECT_EQUAL("Invalid state on call: A uint64_t value cannot be an object key ({}(ObjectExpectingKey))", e.getReason()); + } + try{ + vespalib::asciistream as; + vespalib::JsonStream stream(as); + stream << Object() << 0.5; + } catch (vespalib::JsonStreamException& e) { + EXPECT_EQUAL("Invalid state on call: A double value cannot be an object key ({}(ObjectExpectingKey))", e.getReason()); + } + try{ + vespalib::asciistream as; + vespalib::JsonStream stream(as); + stream << Object() << Array(); + } catch (vespalib::JsonStreamException& e) { + EXPECT_EQUAL("Invalid state on call: An array value cannot be an object key ({}(ObjectExpectingKey))", e.getReason()); + } + // Invalid points to add End() + try{ + vespalib::asciistream as; + vespalib::JsonStream stream(as); + stream << Object() << "foo" << End(); + } catch (vespalib::JsonStreamException& e) { + EXPECT_EQUAL("Invalid state on call: Object got key but not value. Cannot end it now ({foo}(ObjectExpectingValue))", e.getReason()); + } + try{ + vespalib::asciistream as; + vespalib::JsonStream stream(as); + stream << End(); + } catch (vespalib::JsonStreamException& e) { + EXPECT_EQUAL("Invalid state on call: No tag to end. At root ((RootExpectingArrayOrObjectStart))", e.getReason()); + } + // Adding to finalized stream + try{ + vespalib::asciistream as; + vespalib::JsonStream stream(as); + stream << Object() << End() << "foo"; + } catch (vespalib::JsonStreamException& e) { + EXPECT_EQUAL("Invalid state on call: Stream already finalized. Can't add a string value. (Finalized)", e.getReason()); + } + try{ + vespalib::asciistream as; + vespalib::JsonStream stream(as); + stream << Object() << End() << false; + } catch (vespalib::JsonStreamException& e) { + EXPECT_EQUAL("Invalid state on call: Stream already finalized. Can't add a bool value. (Finalized)", e.getReason()); + } + try{ + vespalib::asciistream as; + vespalib::JsonStream stream(as); + stream << Object() << End() << 13; + } catch (vespalib::JsonStreamException& e) { + EXPECT_EQUAL("Invalid state on call: Stream already finalized. Can't add an int64_t value. (Finalized)", e.getReason()); + } + try{ + vespalib::asciistream as; + vespalib::JsonStream stream(as); + stream << Object() << End() << uint64_t(13); + } catch (vespalib::JsonStreamException& e) { + EXPECT_EQUAL("Invalid state on call: Stream already finalized. Can't add a uint64_t value. (Finalized)", e.getReason()); + } + try{ + vespalib::asciistream as; + vespalib::JsonStream stream(as); + stream << Object() << End() << 0.2; + } catch (vespalib::JsonStreamException& e) { + EXPECT_EQUAL("Invalid state on call: Stream already finalized. Can't add a double value. (Finalized)", e.getReason()); + } + try{ + vespalib::asciistream as; + vespalib::JsonStream stream(as); + stream << Object() << End() << Object(); + } catch (vespalib::JsonStreamException& e) { + EXPECT_EQUAL("Invalid state on call: Stream already finalized. Can't start a new object. (Finalized)", e.getReason()); + } + try{ + vespalib::asciistream as; + vespalib::JsonStream stream(as); + stream << Object() << End() << Array(); + } catch (vespalib::JsonStreamException& e) { + EXPECT_EQUAL("Invalid state on call: Stream already finalized. Can't start a new array. (Finalized)", e.getReason()); + } + try{ + vespalib::asciistream as; + vespalib::JsonStream stream(as); + stream << Object() << End() << End(); + } catch (vespalib::JsonStreamException& e) { + EXPECT_EQUAL("Invalid state on call: Stream already finalized. Can't end it. (Finalized)", e.getReason()); + } +} + +void +JSONTest::testJsonStreamStateReporting() +{ + using namespace vespalib::jsonstream; + vespalib::asciistream as; + vespalib::JsonStream stream(as); + stream << Array() << 13 + << "foo" + << Object() << "key" << "value" << End() + << false + << End(); + EXPECT_EQUAL("Current: Finalized", stream.getJsonStreamState()); +} + +int +JSONTest::Main() +{ + TEST_INIT("json_test"); + + testJSONWriterValues(); + testJSONWriterObject(); + testJSONWriterArray(); + testJSONWriterComplex(); + testJsonStream(); + testJsonStreamErrors(); + testJsonStreamStateReporting(); + + TEST_DONE(); +} + +TEST_APPHOOK(JSONTest); + diff --git a/staging_vespalib/src/tests/librarypool/.gitignore b/staging_vespalib/src/tests/librarypool/.gitignore new file mode 100644 index 00000000000..1a1aea2fda0 --- /dev/null +++ b/staging_vespalib/src/tests/librarypool/.gitignore @@ -0,0 +1 @@ +staging_vespalib_librarypool_test_app diff --git a/staging_vespalib/src/tests/librarypool/CMakeLists.txt b/staging_vespalib/src/tests/librarypool/CMakeLists.txt new file mode 100644 index 00000000000..0ef8d03ccda --- /dev/null +++ b/staging_vespalib/src/tests/librarypool/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(staging_vespalib_librarypool_test_app + SOURCES + librarypool_test.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_librarypool_test_app COMMAND staging_vespalib_librarypool_test_app) diff --git a/staging_vespalib/src/tests/librarypool/DESC b/staging_vespalib/src/tests/librarypool/DESC new file mode 100644 index 00000000000..2330c52fae7 --- /dev/null +++ b/staging_vespalib/src/tests/librarypool/DESC @@ -0,0 +1 @@ +Library pool test. Take a look at librarypool_test.cpp for details. diff --git a/staging_vespalib/src/tests/librarypool/FILES b/staging_vespalib/src/tests/librarypool/FILES new file mode 100644 index 00000000000..c8bb90cf093 --- /dev/null +++ b/staging_vespalib/src/tests/librarypool/FILES @@ -0,0 +1 @@ +librarypool_test.cpp diff --git a/staging_vespalib/src/tests/librarypool/librarypool_test.cpp b/staging_vespalib/src/tests/librarypool/librarypool_test.cpp new file mode 100644 index 00000000000..5808d1c91e5 --- /dev/null +++ b/staging_vespalib/src/tests/librarypool/librarypool_test.cpp @@ -0,0 +1,41 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/fastos/fastos.h> +#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/util/librarypool.h> +#include <vespa/vespalib/util/exceptions.h> +#include <vespa/log/log.h> +LOG_SETUP("librarypool_test"); + +using namespace vespalib; + +class Test : public TestApp +{ +public: + int Main(); +}; + +int +Test::Main() +{ + TEST_INIT("librarypool_test"); + LibraryPool p; + ASSERT_TRUE(p.get("z") == NULL); + p.loadLibrary("z"); + ASSERT_TRUE(p.get("z") != NULL); + ASSERT_TRUE(p.get("z")->GetSymbol("some_symbol_that_is_not_there") == NULL); + ASSERT_TRUE(p.get("z")->GetSymbol("compress") != NULL); + try { + p.loadLibrary("not_found"); + ASSERT_TRUE(false); + } catch (const IllegalArgumentException & e) { + ASSERT_TRUE(p.get("not_found") == NULL); + } + { + const LibraryPool & c(p); + ASSERT_TRUE(c.get("z") != NULL); + ASSERT_TRUE(c.get("not_found") == NULL); + } + TEST_DONE(); +} + +TEST_APPHOOK(Test) diff --git a/staging_vespalib/src/tests/memorydatastore/.gitignore b/staging_vespalib/src/tests/memorydatastore/.gitignore new file mode 100644 index 00000000000..634cea1ae88 --- /dev/null +++ b/staging_vespalib/src/tests/memorydatastore/.gitignore @@ -0,0 +1 @@ +staging_vespalib_memorydatastore_test_app diff --git a/staging_vespalib/src/tests/memorydatastore/CMakeLists.txt b/staging_vespalib/src/tests/memorydatastore/CMakeLists.txt new file mode 100644 index 00000000000..386cf7d6865 --- /dev/null +++ b/staging_vespalib/src/tests/memorydatastore/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(staging_vespalib_memorydatastore_test_app + SOURCES + memorydatastore.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_memorydatastore_test_app COMMAND staging_vespalib_memorydatastore_test_app) diff --git a/staging_vespalib/src/tests/memorydatastore/memorydatastore.cpp b/staging_vespalib/src/tests/memorydatastore/memorydatastore.cpp new file mode 100644 index 00000000000..2bb5a272783 --- /dev/null +++ b/staging_vespalib/src/tests/memorydatastore/memorydatastore.cpp @@ -0,0 +1,75 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/fastos/fastos.h> +#include <vespa/log/log.h> +LOG_SETUP("data_test"); +#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/data/memorydatastore.h> +#include <vespa/vespalib/stllike/asciistream.h> +#include <vector> + +using namespace vespalib; + +class MemoryDataStoreTest : public vespalib::TestApp +{ +private: + void testMemoryDataStore(); + void testVariableSizeVector(); +public: + int Main(); +}; + +void +MemoryDataStoreTest::testMemoryDataStore() +{ + MemoryDataStore s(256); + std::vector<MemoryDataStore::Reference> v; + v.push_back(s.push_back("mumbo", 5)); + for (size_t i(0); i < 50; i++) { + v.push_back(s.push_back("mumbo", 5)); + EXPECT_EQUAL(static_cast<const char *>(v[i].data()) + 5, v[i+1].data()); + } + v.push_back(s.push_back("mumbo", 5)); + EXPECT_EQUAL(52ul, v.size()); + EXPECT_NOT_EQUAL(static_cast<const char *>(v[50].data()) + 5, v[51].data()); + for (size_t i(0); i < v.size(); i++) { + EXPECT_EQUAL(0, memcmp("mumbo", v[i].data(), 5)); + } +} + +void +MemoryDataStoreTest::testVariableSizeVector() +{ + VariableSizeVector v(256); + for (size_t i(0); i < 10000; i++) { + asciistream os; + os << i; + v.push_back(os.str().c_str(), os.str().size()); + } + for (size_t i(0); i < v.size(); i++) { + asciistream os; + os << i; + EXPECT_EQUAL(os.str().size(), v[i].size()); + EXPECT_EQUAL(0, memcmp(os.str().c_str(), v[i].data(), os.str().size())); + } + size_t i(0); + for (auto it(v.begin()), mt(v.end()); it != mt; it++, i++) { + asciistream os; + os << i; + EXPECT_EQUAL(os.str().size(), it->size()); + EXPECT_EQUAL(0, memcmp(os.str().c_str(), (*it).data(), os.str().size())); + } + +} + +int +MemoryDataStoreTest::Main() +{ + TEST_INIT("data_test"); + testMemoryDataStore(); + testVariableSizeVector(); + + TEST_DONE(); +} + +TEST_APPHOOK(MemoryDataStoreTest); + diff --git a/staging_vespalib/src/tests/objectdump/.gitignore b/staging_vespalib/src/tests/objectdump/.gitignore new file mode 100644 index 00000000000..d243567aea6 --- /dev/null +++ b/staging_vespalib/src/tests/objectdump/.gitignore @@ -0,0 +1,4 @@ +.depend +Makefile +objectdump_test +staging_vespalib_objectdump_test_app diff --git a/staging_vespalib/src/tests/objectdump/CMakeLists.txt b/staging_vespalib/src/tests/objectdump/CMakeLists.txt new file mode 100644 index 00000000000..e8b5f76b934 --- /dev/null +++ b/staging_vespalib/src/tests/objectdump/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(staging_vespalib_objectdump_test_app + SOURCES + objectdump.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_objectdump_test_app COMMAND staging_vespalib_objectdump_test_app) diff --git a/staging_vespalib/src/tests/objectdump/DESC b/staging_vespalib/src/tests/objectdump/DESC new file mode 100644 index 00000000000..747ea8bb015 --- /dev/null +++ b/staging_vespalib/src/tests/objectdump/DESC @@ -0,0 +1 @@ +Test dumping of identifiable objects to human-readable form. diff --git a/staging_vespalib/src/tests/objectdump/FILES b/staging_vespalib/src/tests/objectdump/FILES new file mode 100644 index 00000000000..f44f8ce9c4c --- /dev/null +++ b/staging_vespalib/src/tests/objectdump/FILES @@ -0,0 +1 @@ +objectdump.cpp diff --git a/staging_vespalib/src/tests/objectdump/objectdump.cpp b/staging_vespalib/src/tests/objectdump/objectdump.cpp new file mode 100644 index 00000000000..3427bbbff3b --- /dev/null +++ b/staging_vespalib/src/tests/objectdump/objectdump.cpp @@ -0,0 +1,107 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/fastos/fastos.h> +#include <vespa/log/log.h> +LOG_SETUP("objectdump_test"); +#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/objects/identifiable.h> +#include <vespa/vespalib/objects/visit.h> + +using namespace vespalib; + +#define CID_Base 10000000 +#define CID_Foo 10000001 +#define CID_Bar 10000002 +#define CID_Baz 10000003 + +struct Base : public vespalib::Identifiable +{ + DECLARE_IDENTIFIABLE(Base); + virtual Base *clone() const { return new Base(*this); } +}; +IMPLEMENT_IDENTIFIABLE(Base, vespalib::Identifiable); + +struct Baz : public Base +{ + DECLARE_IDENTIFIABLE(Baz); + virtual Baz *clone() const { return new Baz(*this); } +}; +IMPLEMENT_IDENTIFIABLE(Baz, Base); + +struct Bar : public Base +{ + DECLARE_IDENTIFIABLE(Bar); + bool _bool; + int8_t _int8; + uint8_t _uint8; + int16_t _int16; + uint16_t _uint16; + int32_t _int32; + uint32_t _uint32; + int64_t _int64; + uint64_t _uint64; + float _float; + double _double; + std::string _string; + Bar() : _bool(true), _int8(-1), _uint8(1), _int16(-2), _uint16(2), + _int32(-4), _uint32(4), _int64(-8), _uint64(8), + _float(2.5), _double(2.75), _string("bla bla") {} + + virtual Bar *clone() const { return new Bar(*this); } + + virtual void visitMembers(ObjectVisitor &v) const { + visit(v, "_bool", _bool); + visit(v, "_int8", _int8); + visit(v, "_uint8", _uint8); + visit(v, "_int16", _int16); + visit(v, "_uint16", _uint16); + visit(v, "_int32", _int32); + visit(v, "_uint32", _uint32); + visit(v, "_int64", _int64); + visit(v, "_uint64", _uint64); + visit(v, "_float", _float); + visit(v, "_double", _double); + visit(v, "_string", _string); + visit(v, "info", "a dummy string"); + visit(v, "(const char*)0", (const char*)0); + } +}; +IMPLEMENT_IDENTIFIABLE(Bar, Base); + +struct Foo : public Base +{ + DECLARE_IDENTIFIABLE(Foo); + Bar _objMember; + Baz _objMember2; + Baz *_objPtr; + std::vector<Bar> _list; + std::vector<IdentifiablePtr<Base> > _list2; + + Foo() : _objMember(), _objMember2(), _objPtr(0), _list(), _list2() { + _list.push_back(Bar()); + _list.push_back(Bar()); + _list.push_back(Bar()); + _list2.push_back(Bar()); + _list2.push_back(Baz()); + } + virtual Foo *clone() const { return new Foo(*this); } + + virtual void visitMembers(ObjectVisitor &v) const { + visit(v, "_objMember", _objMember); + visit(v, "_objMember2", _objMember2); + visit(v, "_objPtr", _objPtr); + visit(v, "_list", _list); + visit(v, "_list2", _list2); + } +}; +IMPLEMENT_IDENTIFIABLE(Foo, Base); + +TEST_SETUP(Test); + +int +Test::Main() +{ + TEST_INIT("objectdump_test"); + Foo foo; + fprintf(stderr, "%s", foo.asString().c_str()); + TEST_DONE(); +} diff --git a/staging_vespalib/src/tests/objects/.gitignore b/staging_vespalib/src/tests/objects/.gitignore new file mode 100644 index 00000000000..2b10aff029c --- /dev/null +++ b/staging_vespalib/src/tests/objects/.gitignore @@ -0,0 +1,5 @@ +.depend +Makefile +asciistream_test +identifiable_test +staging_vespalib_identifiable_test_app diff --git a/staging_vespalib/src/tests/objects/CMakeLists.txt b/staging_vespalib/src/tests/objects/CMakeLists.txt new file mode 100644 index 00000000000..1ef21d0aaa5 --- /dev/null +++ b/staging_vespalib/src/tests/objects/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(staging_vespalib_identifiable_test_app + SOURCES + identifiable_test.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_identifiable_test_app COMMAND staging_vespalib_identifiable_test_app) diff --git a/staging_vespalib/src/tests/objects/DESC b/staging_vespalib/src/tests/objects/DESC new file mode 100644 index 00000000000..fe2ee1fa6f4 --- /dev/null +++ b/staging_vespalib/src/tests/objects/DESC @@ -0,0 +1,2 @@ +identifiable test. Take a look at identifiable.cpp for details. +asciistream test. Take a look at asciistream.cpp for details. diff --git a/staging_vespalib/src/tests/objects/FILES b/staging_vespalib/src/tests/objects/FILES new file mode 100644 index 00000000000..f50b9f9ca5a --- /dev/null +++ b/staging_vespalib/src/tests/objects/FILES @@ -0,0 +1,2 @@ +identifiable.cpp +asciistream.cpp diff --git a/staging_vespalib/src/tests/objects/identifiable_test.cpp b/staging_vespalib/src/tests/objects/identifiable_test.cpp new file mode 100644 index 00000000000..2fe793dae10 --- /dev/null +++ b/staging_vespalib/src/tests/objects/identifiable_test.cpp @@ -0,0 +1,339 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/fastos/fastos.h> +#include <vespa/log/log.h> +LOG_SETUP("identifiable_test"); +#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/objects/identifiable.h> +#include <vespa/vespalib/objects/namedobject.h> +#include <vespa/vespalib/util/exceptions.h> + +using namespace vespalib; + +class IdentifiableTest : public TestApp { + void requireThatIdentifiableCastCanCastPointers(); + void requireThatIdentifiableCastCanCastReferences(); + void testNamedObject(); + void testNboStream(); + template <typename T> + void testStream(const T & a); + void testNboSerializer(); + template <typename T> + void testSerializer(const T & a); +public: + int Main(); +}; + +#define CID_Abstract 0x700000 +#define CID_A 0x700001 +#define CID_B 0x700002 +#define CID_C 0x700003 + +class Abstract : public Identifiable +{ +public: + DECLARE_IDENTIFIABLE_ABSTRACT(Abstract); + virtual ~Abstract() { } + virtual void someAbstractVirtualMethod() = 0; +}; + +class A : public Abstract +{ +public: + DECLARE_IDENTIFIABLE(A); + A() { } + virtual void someAbstractVirtualMethod() { }; +}; + +class B : public A +{ +public: + DECLARE_IDENTIFIABLE(B); + B() { } +}; + +class C : public Identifiable +{ +private: + int _value; + +public: + DECLARE_IDENTIFIABLE(C); + C() : _value(0) {} + C(int value) : _value(value) {} + C *clone() const { return new C(*this); } + virtual int cmp(const Identifiable &rhs) const { + int result(cmpClassId(rhs)); + if (result == 0) { + result = _value - static_cast<const C &>(rhs)._value; + } + return result; + } +}; + +IMPLEMENT_IDENTIFIABLE_ABSTRACT(Abstract, Identifiable); +IMPLEMENT_IDENTIFIABLE(A, Abstract); +IMPLEMENT_IDENTIFIABLE(B, A); +IMPLEMENT_IDENTIFIABLE(C, Identifiable); + +void +IdentifiableTest::testNamedObject() +{ + NamedObject a("first"), b("second");; + nbostream os; + NBOSerializer nos(os); + nos << a << b; + EXPECT_EQUAL(27u,os.size()); + Identifiable::UP o1; + o1 = Identifiable::create(nos); + EXPECT_EQUAL(14u, os.size()); + ASSERT_TRUE(o1->inherits(NamedObject::classId)); + ASSERT_TRUE(o1->getClass().id() == NamedObject::classId); + EXPECT_TRUE(static_cast<const NamedObject &>(*o1).getName() == "first"); + o1 = Identifiable::create(nos); + EXPECT_EQUAL(0u, os.size()); + ASSERT_TRUE(o1->inherits(NamedObject::classId)); + ASSERT_TRUE(o1->getClass().id() == NamedObject::classId); + EXPECT_TRUE(static_cast<const NamedObject &>(*o1).getName() == "second"); +} + +template <typename T> +void IdentifiableTest::testStream(const T & a) +{ + nbostream s; + s << a; + T b; + s >> b; + EXPECT_TRUE(s.empty()); + EXPECT_EQUAL(a, b); + EXPECT_EQUAL(nbostream::ok, s.state()); + EXPECT_TRUE(s.good()); +} + +template <typename T> +void IdentifiableTest::testSerializer(const T & a) +{ + nbostream t; + NBOSerializer s(t); + s << a; + T b; + s >> b; + EXPECT_TRUE(s.getStream().empty()); + EXPECT_EQUAL(a, b); + EXPECT_EQUAL(nbostream::ok, s.getStream().state()); +} + +void IdentifiableTest::testNboSerializer() +{ + testSerializer(true); + testSerializer(false); + testSerializer(static_cast<int8_t>('a')); + testSerializer(static_cast<uint8_t>(156)); + testSerializer(static_cast<int16_t>(156)); + testSerializer(static_cast<int32_t>(156)); + testSerializer(static_cast<int64_t>(156)); + testSerializer(static_cast<uint16_t>(156)); + testSerializer(static_cast<uint32_t>(156)); + testSerializer(static_cast<uint64_t>(156)); + testSerializer(static_cast<float>(156)); + testSerializer(static_cast<double>(156)); + testSerializer(vespalib::string("abcdefgh")); +} + +void IdentifiableTest::testNboStream() +{ + testStream(true); + testStream(false); + testStream('a'); + testStream(static_cast<unsigned char>(156)); + testStream(static_cast<int16_t>(156)); + testStream(static_cast<int32_t>(156)); + testStream(static_cast<int64_t>(156)); + testStream(static_cast<uint16_t>(156)); + testStream(static_cast<uint32_t>(156)); + testStream(static_cast<uint64_t>(156)); + testStream(static_cast<float>(156)); + testStream(static_cast<double>(156)); + testStream(std::string("abcdefgh")); + testStream(vespalib::string("abcdefgh")); + { + nbostream s(4); + EXPECT_EQUAL(4u, s.capacity()); + s << "abcdef"; + EXPECT_EQUAL(nbostream::ok, s.state()); + EXPECT_EQUAL(10u, s.size()); + EXPECT_EQUAL(16u, s.capacity()); + EXPECT_EQUAL(0, strncmp(s.c_str()+4, "abcdef", 6)); + } + { + nbostream s(8); + EXPECT_EQUAL(0u, s.size()); + EXPECT_EQUAL(8u, s.capacity()); + const char * prev = s.c_str(); + s << "ABCD"; + EXPECT_EQUAL(8u, s.size()); + EXPECT_EQUAL(8u, s.capacity()); + EXPECT_EQUAL(prev, s.c_str()); + s << "A long string that will cause resizing"; + EXPECT_EQUAL(50u, s.size()); + EXPECT_EQUAL(64u, s.capacity()); + EXPECT_NOT_EQUAL(prev, s.c_str()); + } + { + nbostream s(8); + EXPECT_EQUAL(0u, s.size()); + EXPECT_EQUAL(8u, s.capacity()); + const char * prev = s.c_str(); + s << "ABCD"; + EXPECT_EQUAL(8u, s.size()); + EXPECT_EQUAL(8u, s.capacity()); + EXPECT_EQUAL(prev, s.c_str()); + s.reserve(50); + EXPECT_NOT_EQUAL(prev, s.c_str()); + EXPECT_EQUAL(8u, s.size()); + EXPECT_EQUAL(64u, s.capacity()); + prev = s.c_str(); + s << "A long string that will cause resizing"; + EXPECT_EQUAL(50u, s.size()); + EXPECT_EQUAL(64u, s.capacity()); + EXPECT_EQUAL(prev, s.c_str()); + } + { + nbostream s; + s << long(9); + EXPECT_EQUAL(8u, s.size()); + EXPECT_EQUAL(0u, s.rp()); + long a(7), b(1); + s >> a; + EXPECT_EQUAL(0u, s.size()); + EXPECT_EQUAL(8u, s.rp()); + EXPECT_TRUE(s.empty()); + EXPECT_TRUE(s.good()); + EXPECT_EQUAL(9, a); + try { + s >> b; + EXPECT_TRUE(false); + } catch (const IllegalStateException & e) { + EXPECT_EQUAL("Stream failed bufsize(1024), readp(8), writep(8)", e.getMessage()); + } + EXPECT_EQUAL(0u, s.size()); + EXPECT_EQUAL(8u, s.rp()); + EXPECT_TRUE(s.empty()); + EXPECT_FALSE(s.good()); + EXPECT_EQUAL(1, b); + EXPECT_EQUAL(nbostream::eof, s.state()); + } +} + +int +IdentifiableTest::Main() +{ + TEST_INIT("identifiable_test"); + + TEST_DO(requireThatIdentifiableCastCanCastPointers()); + TEST_DO(requireThatIdentifiableCastCanCastReferences()); + testNamedObject(); + testNboStream(); + testNboSerializer(); + + A a; + B b; + + const Identifiable::RuntimeClass & rtcA = a.getClass(); + EXPECT_EQUAL(rtcA.id(), static_cast<unsigned int>(A::classId)); + EXPECT_EQUAL(strcmp(rtcA.name(), "A"), 0); + + const Identifiable::RuntimeClass & rtcB = b.getClass(); + EXPECT_EQUAL(rtcB.id(), static_cast<unsigned int>(B::classId)); + EXPECT_EQUAL(strcmp(rtcB.name(), "B"), 0); + + const Identifiable::RuntimeClass * rt(Identifiable::classFromId(0x1ab76245)); + ASSERT_TRUE(rt == NULL); + rt = Identifiable::classFromId(Abstract::classId); + ASSERT_TRUE(rt != NULL); + Identifiable * u = rt->create(); + ASSERT_TRUE(u == NULL); + rt = Identifiable::classFromId(A::classId); + ASSERT_TRUE(rt != NULL); + rt = Identifiable::classFromId(B::classId); + ASSERT_TRUE(rt != NULL); + + Identifiable * o = rt->create(); + ASSERT_TRUE(o != NULL); + + const Identifiable::RuntimeClass & rtc = o->getClass(); + ASSERT_TRUE(rtc.id() == B::classId); + ASSERT_TRUE(strcmp(rtc.name(), "B") == 0); + ASSERT_TRUE(o->inherits(B::classId)); + ASSERT_TRUE(o->inherits(A::classId)); + ASSERT_TRUE(o->inherits(Abstract::classId)); + ASSERT_TRUE(o->inherits(Identifiable::classId)); + ASSERT_TRUE(o->getClass().id() == B::classId); + nbostream os; + NBOSerializer nos(os); + nos << *o; + EXPECT_EQUAL(os.size(), 4u); + Identifiable::UP o2 = Identifiable::create(nos); + EXPECT_TRUE(os.empty()); + ASSERT_TRUE(o->inherits(B::classId)); + ASSERT_TRUE(o->getClass().id() == B::classId); + delete o; + + rt = Identifiable::classFromName("NotBNorA"); + ASSERT_TRUE(rt == NULL); + rt = Identifiable::classFromName("B"); + ASSERT_TRUE(rt != NULL); + o = rt->create(); + ASSERT_TRUE(o != NULL); + const Identifiable::RuntimeClass & rtc2 = o->getClass(); + ASSERT_TRUE(rtc2.id() == B::classId); + ASSERT_TRUE(strcmp(rtc2.name(), "B") == 0); + ASSERT_TRUE(o->inherits(B::classId)); + ASSERT_TRUE(o->inherits(A::classId)); + ASSERT_TRUE(o->inherits(Abstract::classId)); + ASSERT_TRUE(o->inherits(Identifiable::classId)); + ASSERT_TRUE(o->getClass().id() == B::classId); + delete o; + + IdentifiablePtr<C> c0(NULL); + IdentifiablePtr<C> c1(new C(10)); + IdentifiablePtr<C> c2(new C(20)); + + EXPECT_LESS(c0.cmp(c1), 0); + EXPECT_EQUAL(c0.cmp(c0), 0); + EXPECT_GREATER(c1.cmp(c0), 0); + + EXPECT_LESS(c1.cmp(c2), 0); + EXPECT_EQUAL(c1.cmp(c1), 0); + EXPECT_GREATER(c2.cmp(c1), 0); + + TEST_DONE(); +} + +void IdentifiableTest::requireThatIdentifiableCastCanCastPointers() { + A a; + B b; + EXPECT_TRUE(Identifiable::cast<A *>(&a)); + EXPECT_TRUE(Identifiable::cast<A *>(&b)); + EXPECT_TRUE(!Identifiable::cast<B *>(&a)); + EXPECT_TRUE(Identifiable::cast<B *>(&b)); + EXPECT_TRUE(Identifiable::cast<Abstract *>(&a)); + EXPECT_TRUE(Identifiable::cast<Abstract *>(&b)); +} + +void IdentifiableTest::requireThatIdentifiableCastCanCastReferences() { + A a; + B b; + try { + // These should not throw. + Identifiable::cast<A &>(a); + Identifiable::cast<A &>(b); + Identifiable::cast<B &>(b); + Identifiable::cast<Abstract &>(a); + Identifiable::cast<Abstract &>(b); + } catch (std::bad_cast &e) { + TEST_FATAL(e.what()); + } + EXPECT_EXCEPTION(Identifiable::cast<B &>(a), std::bad_cast, "bad_cast"); +} + +TEST_APPHOOK(IdentifiableTest) diff --git a/staging_vespalib/src/tests/objectselection/.gitignore b/staging_vespalib/src/tests/objectselection/.gitignore new file mode 100644 index 00000000000..3dece3fbbfe --- /dev/null +++ b/staging_vespalib/src/tests/objectselection/.gitignore @@ -0,0 +1,4 @@ +.depend +Makefile +objectselection_test +staging_vespalib_objectselection_test_app diff --git a/staging_vespalib/src/tests/objectselection/CMakeLists.txt b/staging_vespalib/src/tests/objectselection/CMakeLists.txt new file mode 100644 index 00000000000..53453035267 --- /dev/null +++ b/staging_vespalib/src/tests/objectselection/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(staging_vespalib_objectselection_test_app + SOURCES + objectselection.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_objectselection_test_app COMMAND staging_vespalib_objectselection_test_app) diff --git a/staging_vespalib/src/tests/objectselection/DESC b/staging_vespalib/src/tests/objectselection/DESC new file mode 100644 index 00000000000..929fb82d99a --- /dev/null +++ b/staging_vespalib/src/tests/objectselection/DESC @@ -0,0 +1 @@ +objectselection test. Take a look at objectselection.cpp for details. diff --git a/staging_vespalib/src/tests/objectselection/FILES b/staging_vespalib/src/tests/objectselection/FILES new file mode 100644 index 00000000000..ebc80a4c647 --- /dev/null +++ b/staging_vespalib/src/tests/objectselection/FILES @@ -0,0 +1 @@ +objectselection.cpp diff --git a/staging_vespalib/src/tests/objectselection/objectselection.cpp b/staging_vespalib/src/tests/objectselection/objectselection.cpp new file mode 100644 index 00000000000..bc09d17fce5 --- /dev/null +++ b/staging_vespalib/src/tests/objectselection/objectselection.cpp @@ -0,0 +1,93 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/fastos/fastos.h> +#include <vespa/log/log.h> +LOG_SETUP("objectselection_test"); +#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/objects/identifiable.h> +#include <vespa/vespalib/objects/objectpredicate.h> +#include <vespa/vespalib/objects/objectoperation.h> + +using namespace vespalib; + +#define CID_Foo 60000005 +#define CID_Bar 60000010 + +struct Foo : public Identifiable +{ + typedef IdentifiablePtr<Foo> CP; + std::vector<CP> nodes; + + DECLARE_IDENTIFIABLE(Foo); + virtual Foo *clone() const { return new Foo(*this); } + virtual void selectMembers(const ObjectPredicate &p, ObjectOperation &o) { + for (uint32_t i = 0; i < nodes.size(); ++i) { + nodes[i]->select(p, o); + } + } +}; +IMPLEMENT_IDENTIFIABLE(Foo, Identifiable); + +struct Bar : public Foo +{ + int value; + + DECLARE_IDENTIFIABLE(Bar); + Bar() : value(0) {} + Bar(int v) { value = v; } + virtual Bar *clone() const { return new Bar(*this); } +}; +IMPLEMENT_IDENTIFIABLE(Bar, Identifiable); + +struct ObjectType : public ObjectPredicate +{ + uint32_t cid; + ObjectType(uint32_t id) : cid(id) {} + virtual bool check(const Identifiable &obj) const { + return (obj.getClass().id() == cid); + } +}; + +struct ObjectCollect : public ObjectOperation +{ + std::vector<Identifiable*> nodes; + virtual void execute(Identifiable &obj) { + nodes.push_back(&obj); + } +}; + +TEST_SETUP(Test); + +int +Test::Main() +{ + TEST_INIT("objectselection_test"); + { + Foo f1; + Foo f2; + Foo f3; + Bar b1(1); + Bar b2(2); + Bar b3(3); + Bar b4(4); + f2.nodes.push_back(b1); + f2.nodes.push_back(b2); + f3.nodes.push_back(b3); + f3.nodes.push_back(b4); + f1.nodes.push_back(f2); + f1.nodes.push_back(f3); + + ObjectType predicate(Bar::classId); + ObjectCollect operation; + f1.select(predicate, operation); + ASSERT_TRUE(operation.nodes.size() == 4); + ASSERT_TRUE(operation.nodes[0]->getClass().id() == Bar::classId); + ASSERT_TRUE(operation.nodes[1]->getClass().id() == Bar::classId); + ASSERT_TRUE(operation.nodes[2]->getClass().id() == Bar::classId); + ASSERT_TRUE(operation.nodes[3]->getClass().id() == Bar::classId); + ASSERT_TRUE(((Bar*)operation.nodes[0])->value == 1); + ASSERT_TRUE(((Bar*)operation.nodes[1])->value == 2); + ASSERT_TRUE(((Bar*)operation.nodes[2])->value == 3); + ASSERT_TRUE(((Bar*)operation.nodes[3])->value == 4); + } + TEST_DONE(); +} diff --git a/staging_vespalib/src/tests/polymorphicarray/.gitignore b/staging_vespalib/src/tests/polymorphicarray/.gitignore new file mode 100644 index 00000000000..b3a74390312 --- /dev/null +++ b/staging_vespalib/src/tests/polymorphicarray/.gitignore @@ -0,0 +1 @@ +staging_vespalib_polymorphicarray_test_app diff --git a/staging_vespalib/src/tests/polymorphicarray/CMakeLists.txt b/staging_vespalib/src/tests/polymorphicarray/CMakeLists.txt new file mode 100644 index 00000000000..929dd258cfe --- /dev/null +++ b/staging_vespalib/src/tests/polymorphicarray/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(staging_vespalib_polymorphicarray_test_app + SOURCES + polymorphicarray_test.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_polymorphicarray_test_app COMMAND staging_vespalib_polymorphicarray_test_app) diff --git a/staging_vespalib/src/tests/polymorphicarray/DESC b/staging_vespalib/src/tests/polymorphicarray/DESC new file mode 100644 index 00000000000..dd68c799d64 --- /dev/null +++ b/staging_vespalib/src/tests/polymorphicarray/DESC @@ -0,0 +1 @@ +Array for polymorphic types test. Take a look at polymorphicarray_test.cpp for details. diff --git a/staging_vespalib/src/tests/polymorphicarray/FILES b/staging_vespalib/src/tests/polymorphicarray/FILES new file mode 100644 index 00000000000..d61af365757 --- /dev/null +++ b/staging_vespalib/src/tests/polymorphicarray/FILES @@ -0,0 +1 @@ +polymorphicarray_test.cpp diff --git a/staging_vespalib/src/tests/polymorphicarray/polymorphicarray_test.cpp b/staging_vespalib/src/tests/polymorphicarray/polymorphicarray_test.cpp new file mode 100644 index 00000000000..9d549d3cc34 --- /dev/null +++ b/staging_vespalib/src/tests/polymorphicarray/polymorphicarray_test.cpp @@ -0,0 +1,123 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/fastos/fastos.h> +#include <vespa/vespalib/testkit/test_kit.h> +#include <vespa/vespalib/util/polymorphicarrays.h> + +using namespace vespalib; + +class A { +public: + virtual ~A() { } + virtual void assign(const A & rhs) { (void) rhs; assert(false); } // Required by the primitive array. + virtual A * clone() const { assert(false); return nullptr; } // Required for the complex array. + + // For testing + virtual bool operator == (const A & rhs) const = 0; + virtual void print(std::ostream & os) const = 0; +}; + +class Primitive : public A +{ +public: + Primitive(size_t v=11) : _v(v) { } + size_t value() const { return _v; } + bool operator == (const A & rhs) const override { + return dynamic_cast<const Primitive &>(rhs).value() == value(); + } + void assign(const A & rhs) override { + _v = dynamic_cast<const Primitive &>(rhs).value(); + } + void print(std::ostream & os) const override { + os << _v; + } +private: + size_t _v; +}; + + +class Complex : public A +{ +public: + Complex(size_t v=11) : _v(v) { } + size_t value() const { return _v; } + bool operator == (const A & rhs) const override { + return dynamic_cast<const Complex &>(rhs).value() == value(); + } + Complex * clone() const override { + return new Complex(_v); + } + void print(std::ostream & os) const override { + os << _v; + } +private: + size_t _v; +}; + +std::ostream & operator << (std::ostream & os, const A & v) { + v.print(os); + return os; +} + + +template <typename T> +void +verifyArray(IArrayT<A> & array) +{ + EXPECT_EQUAL(0u, array.size()); + for (size_t i(0); i < 10; i++) { + array.push_back(T(i)); + } + EXPECT_EQUAL(10u, array.size()); + for (size_t i(0); i < 10; i++) { + EXPECT_EQUAL(T(i), array[i]); + } + IArrayT<A>::UP copy(array.clone()); + array.clear(); + EXPECT_EQUAL(0u, array.size()); + + for (size_t i(0); i < copy->size(); i++) { + array.push_back((*copy)[i]); + } + + array.resize(19); + EXPECT_EQUAL(19u, array.size()); + for (size_t i(0); i < 10; i++) { + EXPECT_EQUAL(T(i), array[i]); + } + for (size_t i(10); i < array.size(); i++) { + EXPECT_EQUAL(T(11), array[i]); + } + array.resize(13); + EXPECT_EQUAL(13u, array.size()); + for (size_t i(0); i < 10; i++) { + EXPECT_EQUAL(T(i), array[i]); + } + for (size_t i(10); i < array.size(); i++) { + EXPECT_EQUAL(T(11), array[i]); + } + dynamic_cast<T &>(array[1]) = T(17); + EXPECT_EQUAL(T(0), array[0]); + EXPECT_EQUAL(T(17), array[1]); + EXPECT_EQUAL(T(2), array[2]); +} + + +TEST("require that primitive arrays conforms") { + PrimitiveArrayT<Primitive, A> a; + verifyArray<Primitive>(a); + EXPECT_EQUAL(7u, a[7].value()); +} + +class Factory : public ComplexArrayT<A>::Factory +{ +public: + A * create() { return new Complex(); } + virtual Factory * clone() const { return new Factory(*this); } +}; + +TEST("require that complex arrays conforms") { + ComplexArrayT<A> a(Factory::UP(new Factory())); + verifyArray<Complex>(a); +} + +TEST_MAIN() { TEST_RUN_ALL(); } diff --git a/staging_vespalib/src/tests/programoptions/.gitignore b/staging_vespalib/src/tests/programoptions/.gitignore new file mode 100644 index 00000000000..31f3aa61556 --- /dev/null +++ b/staging_vespalib/src/tests/programoptions/.gitignore @@ -0,0 +1,4 @@ +.depend +Makefile +programoptions_test +staging_vespalib_programoptions_test_app diff --git a/staging_vespalib/src/tests/programoptions/CMakeLists.txt b/staging_vespalib/src/tests/programoptions/CMakeLists.txt new file mode 100644 index 00000000000..7e436e7cee7 --- /dev/null +++ b/staging_vespalib/src/tests/programoptions/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(staging_vespalib_programoptions_test_app + SOURCES + programoptions_test.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_programoptions_test_app COMMAND staging_vespalib_programoptions_test_app) diff --git a/staging_vespalib/src/tests/programoptions/DESC b/staging_vespalib/src/tests/programoptions/DESC new file mode 100644 index 00000000000..6ec9a059c7d --- /dev/null +++ b/staging_vespalib/src/tests/programoptions/DESC @@ -0,0 +1 @@ +programoptions test. Take a look at programoptions.cpp for details. diff --git a/staging_vespalib/src/tests/programoptions/FILES b/staging_vespalib/src/tests/programoptions/FILES new file mode 100644 index 00000000000..468a6bfb10a --- /dev/null +++ b/staging_vespalib/src/tests/programoptions/FILES @@ -0,0 +1 @@ +programoptions.cpp diff --git a/staging_vespalib/src/tests/programoptions/programoptions_test.cpp b/staging_vespalib/src/tests/programoptions/programoptions_test.cpp new file mode 100644 index 00000000000..5dd27c1ce38 --- /dev/null +++ b/staging_vespalib/src/tests/programoptions/programoptions_test.cpp @@ -0,0 +1,362 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include <vespa/fastos/fastos.h> +#include <vespa/vespalib/util/programoptions.h> +#include <vespa/vespalib/util/programoptions_testutils.h> + +#include <iostream> +#include <vespa/log/log.h> +#include <vespa/vespalib/testkit/testapp.h> + +LOG_SETUP("programoptions_test"); + +namespace vespalib { + +class Test : public vespalib::TestApp +{ +public: + void testSyntaxPage(); + void testNormalUsage(); + void testFailures(); + void testVectorArgument(); + void testAllHiddenOption(); + void testOptionsAfterArguments(); + int Main(); +}; + +int +Test::Main() +{ + TEST_INIT("programoptions_test"); + srandom(1); + testSyntaxPage(); + testNormalUsage(); + testFailures(); + testVectorArgument(); + testAllHiddenOption(); + // Currently not supported + // testOptionsAfterArguments(); + TEST_DONE(); +} + +struct MyOptions : public ProgramOptions { + bool boolOpt; + bool boolWithDefOpt; + int intOpt; + uint32_t uintOpt; + float floatOpt; + std::string stringOpt; + std::string argString; + int argInt; + std::string argOptionalString; + std::map<std::string, std::string> properties; + int anotherOptionalArg; + + MyOptions(int argc, const char* const* argv) + : ProgramOptions(argc, argv) + { + // Required options + addOption("uintopt u", uintOpt, "Sets an unsigned int"); + // Optional options + addOption("b bool", boolOpt, "Enables a flag"); + addOption("boolwithdef", boolWithDefOpt, true, "If set turns to false"); + + addOption("intopt i", intOpt, 5, "Sets a signed int"); + addOption("floatopt", floatOpt, 4.0f, "Sets a float\nMultiline baby"); + addOption("string s", stringOpt, std::string("ballalaika"), + "Sets a string value. This is a very long description that " + "should be broken down into multiple lines in some sensible " + "way."); + addOptionHeader("Advanced options"); + addOption("p properties", properties, "Property map"); + addHiddenIdentifiers("prop"); + setArgumentTypeName("key"); + setArgumentTypeName("value", 1); + + addArgument("argString", argString, "Required string argument."); + addArgument("argInt", argInt, "Required int argument."); + addArgument("argOptionalString", argOptionalString, std::string("foo"), + "Optional string argument with a long description so we " + "can see that it will be broken correctly."); + addArgument("argSecondOptional", anotherOptionalArg, 3, + "Yet another optional argument"); + + setSyntaxMessage("A test program to see if this utility works."); + setSyntaxPageMaxLeftColumnSize(25); + } + +}; + +void Test::testSyntaxPage() { + AppOptions opts("myapp"); + MyOptions options(opts.getArgCount(), opts.getArguments()); + std::ostringstream actual; + options.writeSyntaxPage(actual); + + std::string expected( +"\nA test program to see if this utility works.\n\n" +"Usage: myapp [options] <argString> <argInt> [argOptionalString] [argSecondOptional]\n\n" +"Arguments:\n" +" argString (string) : Required string argument.\n" +" argInt (int) : Required int argument.\n" +" argOptionalString (string)\n" +" : Optional string argument with a long description so\n" +" we can see that it will be broken correctly.\n" +" (optional)\n" +" argSecondOptional (int) : Yet another optional argument (optional)\n\n" +"Options:\n" +" --uintopt -u <uint> : Sets an unsigned int (required)\n" +" -b --bool : Enables a flag\n" +" --boolwithdef : If set turns to false\n" +" --intopt -i <int> : Sets a signed int (default 5)\n" +" --floatopt <float> : Sets a float\n" +" Multiline baby (default 4)\n" +" --string -s <string> : Sets a string value. This is a very long description\n" +" that should be broken down into multiple lines in some\n" +" sensible way. (default \"ballalaika\")\n\n" +"Advanced options:\n" +" -p --properties <key> <value> : Property map (default empty)\n" + ); + EXPECT_EQUAL(expected, actual.str()); +} + +void Test::testNormalUsage() { + { + AppOptions opts("myapp -b --uintopt 4 -s foo tit 1 tei 6"); + MyOptions options(opts.getArgCount(), opts.getArguments()); + options.parse(); + EXPECT_EQUAL(true, options.boolOpt); + EXPECT_EQUAL(true, options.boolWithDefOpt); + EXPECT_EQUAL(5, options.intOpt); + EXPECT_EQUAL(4u, options.uintOpt); + EXPECT_APPROX(4, options.floatOpt, 0.00001); + EXPECT_EQUAL("foo", options.stringOpt); + EXPECT_EQUAL("tit", options.argString); + EXPECT_EQUAL(1, options.argInt); + EXPECT_EQUAL("tei", options.argOptionalString); + EXPECT_EQUAL(0u, options.properties.size()); + EXPECT_EQUAL(6, options.anotherOptionalArg); + } + { + AppOptions opts("myapp --uintopt 6 tit 1"); + MyOptions options(opts.getArgCount(), opts.getArguments()); + options.parse(); + EXPECT_EQUAL(false, options.boolOpt); + EXPECT_EQUAL(true, options.boolWithDefOpt); + EXPECT_EQUAL(5, options.intOpt); + EXPECT_EQUAL(6u, options.uintOpt); + EXPECT_APPROX(4, options.floatOpt, 0.00001); + EXPECT_EQUAL("ballalaika", options.stringOpt); + EXPECT_EQUAL("tit", options.argString); + EXPECT_EQUAL(1, options.argInt); + EXPECT_EQUAL("foo", options.argOptionalString); + EXPECT_EQUAL(0u, options.properties.size()); + EXPECT_EQUAL(3, options.anotherOptionalArg); + } + // Arguments coming after options. + // (Required for nesting of short options) + { + AppOptions opts("myapp --uintopt --intopt 6 -8 tit 1 tei"); + MyOptions options(opts.getArgCount(), opts.getArguments()); + options.parse(); + EXPECT_EQUAL(false, options.boolOpt); + EXPECT_EQUAL(true, options.boolWithDefOpt); + EXPECT_EQUAL(-8, options.intOpt); + EXPECT_EQUAL(6u, options.uintOpt); + EXPECT_APPROX(4, options.floatOpt, 0.00001); + EXPECT_EQUAL("ballalaika", options.stringOpt); + EXPECT_EQUAL("tit", options.argString); + EXPECT_EQUAL(1, options.argInt); + EXPECT_EQUAL("tei", options.argOptionalString); + EXPECT_EQUAL(0u, options.properties.size()); + } + { + AppOptions opts( "myapp -uib 6 -8 --boolwithdef tit 1 tei"); + MyOptions options(opts.getArgCount(), opts.getArguments()); + options.parse(); + EXPECT_EQUAL(true, options.boolOpt); + EXPECT_EQUAL(false, options.boolWithDefOpt); + EXPECT_EQUAL(-8, options.intOpt); + EXPECT_EQUAL(6u, options.uintOpt); + EXPECT_APPROX(4, options.floatOpt, 0.00001); + EXPECT_EQUAL("ballalaika", options.stringOpt); + EXPECT_EQUAL("tit", options.argString); + EXPECT_EQUAL(1, options.argInt); + EXPECT_EQUAL("tei", options.argOptionalString); + EXPECT_EQUAL(0u, options.properties.size()); + } + // Properties + { + AppOptions opts("myapp -u 6 -p foo bar --prop hmm brr tit 1 tei"); + MyOptions options(opts.getArgCount(), opts.getArguments()); + options.parse(); + EXPECT_EQUAL(false, options.boolOpt); + EXPECT_EQUAL(true, options.boolWithDefOpt); + EXPECT_EQUAL(5, options.intOpt); + EXPECT_EQUAL(6u, options.uintOpt); + EXPECT_APPROX(4, options.floatOpt, 0.00001); + EXPECT_EQUAL("ballalaika", options.stringOpt); + EXPECT_EQUAL("tit", options.argString); + EXPECT_EQUAL(1, options.argInt); + EXPECT_EQUAL("tei", options.argOptionalString); + EXPECT_EQUAL(2u, options.properties.size()); + EXPECT_EQUAL("bar", options.properties["foo"]); + EXPECT_EQUAL("brr", options.properties["hmm"]); + } +} + +void Test::testFailures() { + // Non-existing long option + { + AppOptions opts("myapp -b --uintopt 4 -s foo --none"); + MyOptions options(opts.getArgCount(), opts.getArguments()); + try{ + options.parse(); + TEST_FATAL("Expected exception"); + } catch (InvalidCommandLineArgumentsException& e) { + EXPECT_EQUAL("Invalid option 'none'.", e.getMessage()); + } + } + // Non-existing short option + { + AppOptions opts("myapp -b --uintopt 4 -s foo -q"); + MyOptions options(opts.getArgCount(), opts.getArguments()); + try{ + options.parse(); + TEST_FATAL("Expected exception"); + } catch (InvalidCommandLineArgumentsException& e) { + EXPECT_EQUAL("Invalid option 'q'.", e.getMessage()); + } + } + // Lacking option argument + { + AppOptions opts("myapp -b --uintopt 4 -s"); + MyOptions options(opts.getArgCount(), opts.getArguments()); + try{ + options.parse(); + TEST_FATAL("Expected exception"); + } catch (InvalidCommandLineArgumentsException& e) { + EXPECT_EQUAL("Option 's' needs 1 arguments. Only 0 available.", + e.getMessage()); + } + } + // Out of signed ranged + { + AppOptions opts("myapp -b --uintopt 4 -intopt 3000000000"); + MyOptions options(opts.getArgCount(), opts.getArguments()); + try{ + options.parse(); + TEST_FATAL("Expected exception"); + } catch (InvalidCommandLineArgumentsException& e) { + EXPECT_EQUAL("The argument '3000000000' can not be interpreted as a " + "number of type int.", e.getMessage()); + } + } + // Negative value to unsigned var (Currently doesnt fail) +/* + { + AppOptions opts("myapp -b --uintopt -1 foo 0"); + MyOptions options(opts.getArgCount(), opts.getArguments()); + try{ + options.parse(); + TEST_FATAL("Expected exception"); + } catch (InvalidCommandLineArgumentsException& e) { + EXPECT_EQUAL("The argument '-1' can not be interpreted as a " + "number of type uint.", e.getMessage()); + } + } + */ + // Lacking required option + { + AppOptions opts("myapp -b"); + MyOptions options(opts.getArgCount(), opts.getArguments()); + try{ + options.parse(); + TEST_FATAL("Expected exception"); + } catch (InvalidCommandLineArgumentsException& e) { + EXPECT_EQUAL("Option 'uintopt' has no default and must be set.", + e.getMessage()); + } + } + // Lacking required argument + { + AppOptions opts("myapp --uintopt 1 tit"); + MyOptions options(opts.getArgCount(), opts.getArguments()); + try{ + options.parse(); + TEST_FATAL("Expected exception"); + } catch (InvalidCommandLineArgumentsException& e) { + EXPECT_EQUAL("Insufficient data is given to set required argument " + "'argInt'.", + e.getMessage()); + } + } + // Argument of wrong type + { + AppOptions opts("myapp --uintopt 1 tit en"); + MyOptions options(opts.getArgCount(), opts.getArguments()); + try{ + options.parse(); + TEST_FATAL("Expected exception"); + } catch (InvalidCommandLineArgumentsException& e) { + EXPECT_EQUAL("The argument 'en' can not be interpreted as a number " + "of type int.", + e.getMessage()); + } + } +} + +void Test::testVectorArgument() +{ + AppOptions opts("myapp foo bar baz"); + std::vector<std::string> args; + ProgramOptions options(opts.getArgCount(), opts.getArguments()); + options.addListArgument("ids", args, "Vector element"); + std::ostringstream actual; + options.writeSyntaxPage(actual); + std::string expected( +"\nUsage: myapp [ids...]\n\n" +"Arguments:\n" +" ids (string[]) : Vector element\n" + ); + EXPECT_EQUAL(expected, actual.str()); + + options.parse(); + EXPECT_EQUAL(3u, args.size()); + EXPECT_EQUAL("foo", args[0]); + EXPECT_EQUAL("bar", args[1]); + EXPECT_EQUAL("baz", args[2]); +} + +void Test::testAllHiddenOption() +{ + AppOptions opts("myapp --foo bar"); + std::string option; + ProgramOptions options(opts.getArgCount(), opts.getArguments()); + options.addOption("", option, "Description"); + options.addHiddenIdentifiers("foo"); + std::ostringstream actual; + options.writeSyntaxPage(actual); + std::string expected("\nUsage: myapp\n"); + EXPECT_EQUAL(expected, actual.str()); + + options.parse(); + EXPECT_EQUAL("bar", option); +} + +void Test::testOptionsAfterArguments() +{ + AppOptions opts("myapp bar --foo baz"); + std::string option; + std::string argument; + ProgramOptions options(opts.getArgCount(), opts.getArguments()); + options.addOption("foo", option, "Description"); + options.addArgument("arg", argument, "Description"); + options.parse(); + EXPECT_EQUAL("baz", option); + EXPECT_EQUAL("bar", argument); +} + +} // vespalib + +TEST_APPHOOK(vespalib::Test) diff --git a/staging_vespalib/src/tests/rusage/.gitignore b/staging_vespalib/src/tests/rusage/.gitignore new file mode 100644 index 00000000000..195922a9ced --- /dev/null +++ b/staging_vespalib/src/tests/rusage/.gitignore @@ -0,0 +1 @@ +staging_vespalib_rusage_test_app diff --git a/staging_vespalib/src/tests/rusage/CMakeLists.txt b/staging_vespalib/src/tests/rusage/CMakeLists.txt new file mode 100644 index 00000000000..b927110179e --- /dev/null +++ b/staging_vespalib/src/tests/rusage/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(staging_vespalib_rusage_test_app + SOURCES + rusage_test.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_rusage_test_app COMMAND staging_vespalib_rusage_test_app) diff --git a/staging_vespalib/src/tests/rusage/DESC b/staging_vespalib/src/tests/rusage/DESC new file mode 100644 index 00000000000..957ed92a119 --- /dev/null +++ b/staging_vespalib/src/tests/rusage/DESC @@ -0,0 +1 @@ +rusage test. Take a look at rusage_test.cpp for details. diff --git a/staging_vespalib/src/tests/rusage/FILES b/staging_vespalib/src/tests/rusage/FILES new file mode 100644 index 00000000000..bea76c6f532 --- /dev/null +++ b/staging_vespalib/src/tests/rusage/FILES @@ -0,0 +1 @@ +rusage_test.cpp diff --git a/staging_vespalib/src/tests/rusage/rusage_test.cpp b/staging_vespalib/src/tests/rusage/rusage_test.cpp new file mode 100644 index 00000000000..3da7f1d0b54 --- /dev/null +++ b/staging_vespalib/src/tests/rusage/rusage_test.cpp @@ -0,0 +1,76 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/fastos/fastos.h> +#include <stddef.h> +#include <vespa/log/log.h> +LOG_SETUP("alloc_test"); +#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/util/rusage.h> + +using namespace vespalib; + +class Test : public TestApp +{ +public: + int Main(); + void testRUsage(); +}; + +int +Test::Main() +{ + TEST_INIT("rusage_test"); + testRUsage(); + TEST_DONE(); +} + +void +Test::testRUsage() +{ + RUsage r1; + EXPECT_EQUAL("", r1.toString()); + RUsage r2; + EXPECT_EQUAL(r2.toString(), r1.toString()); + RUsage diff = r2-r1; + EXPECT_EQUAL(diff.toString(), r2.toString()); + { + RUsage then = RUsage::createSelf(17765895674); + RUsage now = RUsage::createSelf(); + EXPECT_NOT_EQUAL(now.toString(), then.toString()); + } + { + RUsage then = RUsage::createChildren(1337583); + RUsage now = RUsage::createChildren(); + EXPECT_NOT_EQUAL(now.toString(), then.toString()); + } + { + timeval a, b, c, d, r; + a.tv_usec = 7; + a.tv_sec = 7; + b.tv_usec = 7; + b.tv_sec = 7; + c.tv_usec = 1; + c.tv_sec = 8; + d.tv_usec = 9; + d.tv_sec = 4; + r = a - b; + EXPECT_EQUAL(0, r.tv_sec); + EXPECT_EQUAL(0, r.tv_usec); + r = b - a; + EXPECT_EQUAL(0, r.tv_sec); + EXPECT_EQUAL(0, r.tv_usec); + r = a - c; + EXPECT_EQUAL(-1, r.tv_sec); + EXPECT_EQUAL( 6, r.tv_usec); + r = c - a; + EXPECT_EQUAL(0, r.tv_sec); + EXPECT_EQUAL(999994, r.tv_usec); + r = a - d; + EXPECT_EQUAL(2, r.tv_sec); + EXPECT_EQUAL(999998, r.tv_usec); + r = d - a; + EXPECT_EQUAL(-3, r.tv_sec); + EXPECT_EQUAL( 2, r.tv_usec); + } +} + +TEST_APPHOOK(Test) diff --git a/staging_vespalib/src/tests/shutdownguard/.gitignore b/staging_vespalib/src/tests/shutdownguard/.gitignore new file mode 100644 index 00000000000..a596164ac7b --- /dev/null +++ b/staging_vespalib/src/tests/shutdownguard/.gitignore @@ -0,0 +1 @@ +staging_vespalib_shutdownguard_test_app diff --git a/staging_vespalib/src/tests/shutdownguard/CMakeLists.txt b/staging_vespalib/src/tests/shutdownguard/CMakeLists.txt new file mode 100644 index 00000000000..75093312cd3 --- /dev/null +++ b/staging_vespalib/src/tests/shutdownguard/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(staging_vespalib_shutdownguard_test_app + SOURCES + shutdownguard_test.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_shutdownguard_test_app NO_VALGRIND COMMAND staging_vespalib_shutdownguard_test_app) diff --git a/staging_vespalib/src/tests/shutdownguard/DESC b/staging_vespalib/src/tests/shutdownguard/DESC new file mode 100644 index 00000000000..869fc61d80f --- /dev/null +++ b/staging_vespalib/src/tests/shutdownguard/DESC @@ -0,0 +1 @@ +shutdown guard test. Take a look at shutdownguard_test.cpp for details. diff --git a/staging_vespalib/src/tests/shutdownguard/FILES b/staging_vespalib/src/tests/shutdownguard/FILES new file mode 100644 index 00000000000..0c040a71f20 --- /dev/null +++ b/staging_vespalib/src/tests/shutdownguard/FILES @@ -0,0 +1 @@ +suicide_test.cpp diff --git a/staging_vespalib/src/tests/shutdownguard/shutdownguard_test.cpp b/staging_vespalib/src/tests/shutdownguard/shutdownguard_test.cpp new file mode 100644 index 00000000000..c31e34afe76 --- /dev/null +++ b/staging_vespalib/src/tests/shutdownguard/shutdownguard_test.cpp @@ -0,0 +1,40 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/fastos/fastos.h> +#include <vespa/log/log.h> +LOG_SETUP("shutdownguard_test"); +#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/util/shutdownguard.h> + +using namespace vespalib; + +TEST_SETUP(Test); + +int +Test::Main() +{ + TEST_INIT("shutdownguard_test"); + { + ShutdownGuard farFuture(123456789); + FastOS_Thread::Sleep(20); + } + EXPECT_TRUE(true); + pid_t child = fork(); + if (child == 0) { + ShutdownGuard soon(30); + for (int i = 0; i < 1000; ++i) { + FastOS_Thread::Sleep(20); + } + exit(0); + } + for (int i = 0; i < 1000; ++i) { + FastOS_Thread::Sleep(20); + int stat = 0; + if (waitpid(child, &stat, WNOHANG) == child) { + EXPECT_TRUE(WIFEXITED(stat)); + EXPECT_EQUAL(1, WEXITSTATUS(stat)); + break; + } + EXPECT_TRUE(i < 800); + } + TEST_DONE(); +} diff --git a/staging_vespalib/src/tests/state_server/.gitignore b/staging_vespalib/src/tests/state_server/.gitignore new file mode 100644 index 00000000000..b1884d4e060 --- /dev/null +++ b/staging_vespalib/src/tests/state_server/.gitignore @@ -0,0 +1 @@ +staging_vespalib_state_server_test_app diff --git a/staging_vespalib/src/tests/state_server/CMakeLists.txt b/staging_vespalib/src/tests/state_server/CMakeLists.txt new file mode 100644 index 00000000000..a62549a563b --- /dev/null +++ b/staging_vespalib/src/tests/state_server/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(staging_vespalib_state_server_test_app + SOURCES + state_server_test.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_state_server_test_app NO_VALGRIND NO_VALGRIND COMMAND staging_vespalib_state_server_test_app) diff --git a/staging_vespalib/src/tests/state_server/FILES b/staging_vespalib/src/tests/state_server/FILES new file mode 100644 index 00000000000..2328b597e56 --- /dev/null +++ b/staging_vespalib/src/tests/state_server/FILES @@ -0,0 +1 @@ +state_server_test.cpp diff --git a/staging_vespalib/src/tests/state_server/state_server_test.cpp b/staging_vespalib/src/tests/state_server/state_server_test.cpp new file mode 100644 index 00000000000..79236523694 --- /dev/null +++ b/staging_vespalib/src/tests/state_server/state_server_test.cpp @@ -0,0 +1,444 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/fastos/fastos.h> +#include <vespa/vespalib/testkit/test_kit.h> +#include <vespa/vespalib/net/state_server.h> +#include <vespa/vespalib/net/simple_health_producer.h> +#include <vespa/vespalib/net/simple_metrics_producer.h> +#include <vespa/vespalib/net/simple_component_config_producer.h> +#include <vespa/vespalib/util/stringfmt.h> +#include <vespa/vespalib/util/slaveproc.h> +#include <vespa/vespalib/net/state_explorer.h> +#include <vespa/vespalib/net/slime_explorer.h> +#include <vespa/vespalib/net/generic_state_handler.h> + +using namespace vespalib; + +//----------------------------------------------------------------------------- + +vespalib::string root_path = "/state/v1/"; +vespalib::string short_root_path = "/state/v1"; +vespalib::string metrics_path = "/state/v1/metrics"; +vespalib::string health_path = "/state/v1/health"; +vespalib::string config_path = "/state/v1/config"; + +vespalib::string total_metrics_path = "/metrics/total"; + +vespalib::string unknown_path = "/this/path/is/not/known"; +vespalib::string unknown_state_path = "/state/v1/this/path/is/not/known"; +vespalib::string my_path = "/my/path"; + +vespalib::string host_tag = "HOST"; +std::map<vespalib::string,vespalib::string> empty_params; + +//----------------------------------------------------------------------------- + +vespalib::string run_cmd(const vespalib::string &cmd) { + std::string out; + ASSERT_TRUE(SlaveProc::run(cmd.c_str(), out)); + return out; +} + +vespalib::string getPage(int port, const vespalib::string &path, const vespalib::string &extra_params = "") { + vespalib::string result = run_cmd(make_string("curl -s %s http://localhost:%d%s", extra_params.c_str(), port, path.c_str())); + vespalib::string chunked_result = run_cmd(make_string("curl -H transfer-encoding:chunked -s %s http://localhost:%d%s", extra_params.c_str(), port, path.c_str())); + ASSERT_EQUAL(result, chunked_result); + return result; +} + +vespalib::string getFull(int port, const vespalib::string &path) { return getPage(port, path, "-D -"); } + +//----------------------------------------------------------------------------- + +struct DummyHandler : JsonGetHandler { + vespalib::string result; + DummyHandler(const vespalib::string &result_in) : result(result_in) {} + virtual vespalib::string get(const vespalib::string &, + const vespalib::string &, + const std::map<vespalib::string,vespalib::string> &) const + { + return result; + } +}; + +//----------------------------------------------------------------------------- + +TEST_F("require that unknown url returns 404 response", HttpServer(0)) { + f1.start(); + std::string expect("HTTP/1.1 404 Not Found\r\n" + "Connection: close\r\n" + "\r\n"); + std::string actual = getFull(f1.port(), unknown_path); + EXPECT_EQUAL(expect, actual); +} + +TEST_FF("require that empty known url returns 404 response", DummyHandler(""), HttpServer(0)) { + auto token = f2.repo().bind(my_path, f1); + f2.start(); + std::string expect("HTTP/1.1 404 Not Found\r\n" + "Connection: close\r\n" + "\r\n"); + std::string actual = getFull(f2.port(), my_path); + EXPECT_EQUAL(expect, actual); +} + +TEST_FF("require that non-empty known url returns expected headers", DummyHandler("[123]"), HttpServer(0)) { + auto token = f2.repo().bind(my_path, f1); + f2.start(); + vespalib::string expect("HTTP/1.1 200 OK\r\n" + "Connection: close\r\n" + "Content-Type: application/json\r\n" + "\r\n" + "[123]"); + std::string actual = getFull(f2.port(), my_path); + EXPECT_EQUAL(expect, actual); +} + +TEST_FFFF("require that handler is selected based on longest matching url prefix", + DummyHandler("[1]"), DummyHandler("[2]"), DummyHandler("[3]"), + HttpServer(0)) +{ + auto token2 = f4.repo().bind("/foo/bar", f2); + auto token1 = f4.repo().bind("/foo", f1); + auto token3 = f4.repo().bind("/foo/bar/baz", f3); + f4.start(); + int port = f4.port(); + EXPECT_EQUAL("", getPage(port, "/fox")); + EXPECT_EQUAL("[1]", getPage(port, "/foo")); + EXPECT_EQUAL("[1]", getPage(port, "/foo/fox")); + EXPECT_EQUAL("[2]", getPage(port, "/foo/bar")); + EXPECT_EQUAL("[2]", getPage(port, "/foo/bar/fox")); + EXPECT_EQUAL("[3]", getPage(port, "/foo/bar/baz")); + EXPECT_EQUAL("[3]", getPage(port, "/foo/bar/baz/fox")); +} + +struct EchoHost : JsonGetHandler { + virtual vespalib::string get(const vespalib::string &host, + const vespalib::string &, + const std::map<vespalib::string,vespalib::string> &) const + { + return "[\"" + host + "\"]"; + } +}; + +TEST_FF("require that host is passed correctly", EchoHost(), HttpServer(0)) { + auto token = f2.repo().bind(my_path, f1); + f2.start(); + EXPECT_EQUAL(make_string("%s:%d", run_cmd("hostname").c_str(), f2.port()), f2.host()); + vespalib::string default_result = make_string("[\"%s\"]", f2.host().c_str()); + vespalib::string localhost_result = make_string("[\"%s:%d\"]", "localhost", f2.port()); + vespalib::string silly_result = "[\"sillyserver\"]"; + EXPECT_EQUAL(localhost_result, run_cmd(make_string("curl -s http://localhost:%d/my/path", f2.port()))); + EXPECT_EQUAL(silly_result, run_cmd(make_string("curl -s http://localhost:%d/my/path -H \"Host: sillyserver\"", f2.port()))); + EXPECT_EQUAL(default_result, run_cmd(make_string("curl -s http://localhost:%d/my/path -H \"Host:\"", f2.port()))); +} + +//----------------------------------------------------------------------------- + +TEST_FFFF("require that the state server wires the appropriate url prefixes", + SimpleHealthProducer(), SimpleMetricsProducer(), SimpleComponentConfigProducer(), + StateServer(0, f1, f2, f3)) +{ + f2.setTotalMetrics("{}"); // avoid empty result + int port = f4.getListenPort(); + EXPECT_TRUE(getFull(port, short_root_path).find("HTTP/1.1 200 OK") == 0); + EXPECT_TRUE(getFull(port, total_metrics_path).find("HTTP/1.1 200 OK") == 0); + EXPECT_TRUE(getFull(port, unknown_path).find("HTTP/1.1 404 Not Found") == 0); +} + +TEST_FFFF("require that the state server exposes the state api handler repo", + SimpleHealthProducer(), SimpleMetricsProducer(), SimpleComponentConfigProducer(), + StateServer(0, f1, f2, f3)) +{ + int port = f4.getListenPort(); + vespalib::string page1 = getPage(port, root_path); + auto token = f4.repo().add_root_resource("state/v1/custom"); + vespalib::string page2 = getPage(port, root_path); + EXPECT_NOT_EQUAL(page1, page2); + token.reset(); + vespalib::string page3 = getPage(port, root_path); + EXPECT_EQUAL(page3, page1); +} + +//----------------------------------------------------------------------------- + +TEST_FFFF("require that json handlers can be removed from repo", + DummyHandler("[1]"), DummyHandler("[2]"), DummyHandler("[3]"), + JsonHandlerRepo()) +{ + auto token1 = f4.bind("/foo", f1); + auto token2 = f4.bind("/foo/bar", f2); + auto token3 = f4.bind("/foo/bar/baz", f3); + std::map<vespalib::string,vespalib::string> params; + EXPECT_EQUAL("[1]", f4.get("", "/foo", params)); + EXPECT_EQUAL("[2]", f4.get("", "/foo/bar", params)); + EXPECT_EQUAL("[3]", f4.get("", "/foo/bar/baz", params)); + token2.reset(); + EXPECT_EQUAL("[1]", f4.get("", "/foo", params)); + EXPECT_EQUAL("[1]", f4.get("", "/foo/bar", params)); + EXPECT_EQUAL("[3]", f4.get("", "/foo/bar/baz", params)); +} + +TEST_FFFF("require that json handlers can be shadowed", + DummyHandler("[1]"), DummyHandler("[2]"), DummyHandler("[3]"), + JsonHandlerRepo()) +{ + auto token1 = f4.bind("/foo", f1); + auto token2 = f4.bind("/foo/bar", f2); + std::map<vespalib::string,vespalib::string> params; + EXPECT_EQUAL("[1]", f4.get("", "/foo", params)); + EXPECT_EQUAL("[2]", f4.get("", "/foo/bar", params)); + auto token3 = f4.bind("/foo/bar", f3); + EXPECT_EQUAL("[3]", f4.get("", "/foo/bar", params)); + token3.reset(); + EXPECT_EQUAL("[2]", f4.get("", "/foo/bar", params)); +} + +TEST_F("require that root resources can be tracked", JsonHandlerRepo()) +{ + EXPECT_TRUE(std::vector<vespalib::string>({}) == f1.get_root_resources()); + auto token1 = f1.add_root_resource("/health"); + EXPECT_TRUE(std::vector<vespalib::string>({"/health"}) == f1.get_root_resources()); + auto token2 = f1.add_root_resource("/config"); + EXPECT_TRUE(std::vector<vespalib::string>({"/health", "/config"}) == f1.get_root_resources()); + auto token3 = f1.add_root_resource("/custom/foo"); + EXPECT_TRUE(std::vector<vespalib::string>({"/health", "/config", "/custom/foo"}) == f1.get_root_resources()); + token2.reset(); + EXPECT_TRUE(std::vector<vespalib::string>({"/health", "/custom/foo"}) == f1.get_root_resources()); +} + +//----------------------------------------------------------------------------- + +TEST_FFFF("require that state api responds to the expected paths", + SimpleHealthProducer(), SimpleMetricsProducer(), SimpleComponentConfigProducer(), + StateApi(f1, f2, f3)) +{ + f2.setTotalMetrics("{}"); // avoid empty result + EXPECT_TRUE(!f4.get(host_tag, short_root_path, empty_params).empty()); + EXPECT_TRUE(!f4.get(host_tag, root_path, empty_params).empty()); + EXPECT_TRUE(!f4.get(host_tag, health_path, empty_params).empty()); + EXPECT_TRUE(!f4.get(host_tag, metrics_path, empty_params).empty()); + EXPECT_TRUE(!f4.get(host_tag, config_path, empty_params).empty()); + EXPECT_TRUE(!f4.get(host_tag, total_metrics_path, empty_params).empty()); + EXPECT_TRUE(f4.get(host_tag, unknown_path, empty_params).empty()); + EXPECT_TRUE(f4.get(host_tag, unknown_state_path, empty_params).empty()); +} + +TEST_FFFF("require that top-level urls are generated correctly", + SimpleHealthProducer(), SimpleMetricsProducer(), SimpleComponentConfigProducer(), + StateApi(f1, f2, f3)) +{ + EXPECT_EQUAL("{\"resources\":[" + "{\"url\":\"http://HOST/state/v1/health\"}," + "{\"url\":\"http://HOST/state/v1/metrics\"}," + "{\"url\":\"http://HOST/state/v1/config\"}]}", + f4.get(host_tag, root_path, empty_params)); + EXPECT_EQUAL(f4.get(host_tag, root_path, empty_params), + f4.get(host_tag, short_root_path, empty_params)); +} + +TEST_FFFF("require that top-level resource list can be extended", + SimpleHealthProducer(), SimpleMetricsProducer(), SimpleComponentConfigProducer(), + StateApi(f1, f2, f3)) +{ + auto token = f4.repo().add_root_resource("/state/v1/custom"); + EXPECT_EQUAL("{\"resources\":[" + "{\"url\":\"http://HOST/state/v1/health\"}," + "{\"url\":\"http://HOST/state/v1/metrics\"}," + "{\"url\":\"http://HOST/state/v1/config\"}," + "{\"url\":\"http://HOST/state/v1/custom\"}]}", + f4.get(host_tag, root_path, empty_params)); +} + +TEST_FFFF("require that health resource works as expected", + SimpleHealthProducer(), SimpleMetricsProducer(), SimpleComponentConfigProducer(), + StateApi(f1, f2, f3)) +{ + EXPECT_EQUAL("{\"status\":{\"code\":\"up\"}}", + f4.get(host_tag, health_path, empty_params)); + f1.setFailed("FAIL MSG"); + EXPECT_EQUAL("{\"status\":{\"code\":\"down\",\"message\":\"FAIL MSG\"}}", + f4.get(host_tag, health_path, empty_params)); +} + +TEST_FFFF("require that metrics resource works as expected", + SimpleHealthProducer(), SimpleMetricsProducer(), SimpleComponentConfigProducer(), + StateApi(f1, f2, f3)) +{ + EXPECT_EQUAL("{\"status\":{\"code\":\"up\"}}", + f4.get(host_tag, metrics_path, empty_params)); + f1.setFailed("FAIL MSG"); + EXPECT_EQUAL("{\"status\":{\"code\":\"down\",\"message\":\"FAIL MSG\"}}", + f4.get(host_tag, metrics_path, empty_params)); + f1.setOk(); + f2.setMetrics("{\"foo\":\"bar\"}"); + EXPECT_EQUAL("{\"status\":{\"code\":\"up\"},\"metrics\":{\"foo\":\"bar\"}}", + f4.get(host_tag, metrics_path, empty_params)); +} + +TEST_FFFF("require that config resource works as expected", + SimpleHealthProducer(), SimpleMetricsProducer(), SimpleComponentConfigProducer(), + StateApi(f1, f2, f3)) +{ + EXPECT_EQUAL("{\"config\":{}}", + f4.get(host_tag, config_path, empty_params)); + f3.addConfig(SimpleComponentConfigProducer::Config("foo", 3)); + EXPECT_EQUAL("{\"config\":{\"generation\":3,\"foo\":{\"generation\":3}}}", + f4.get(host_tag, config_path, empty_params)); + f3.addConfig(SimpleComponentConfigProducer::Config("foo", 4)); + f3.addConfig(SimpleComponentConfigProducer::Config("bar", 4, "error")); + EXPECT_EQUAL("{\"config\":{\"generation\":4,\"bar\":{\"generation\":4,\"message\":\"error\"},\"foo\":{\"generation\":4}}}", + f4.get(host_tag, config_path, empty_params)); + f3.removeConfig("bar"); + EXPECT_EQUAL("{\"config\":{\"generation\":4,\"foo\":{\"generation\":4}}}", + f4.get(host_tag, config_path, empty_params)); +} + +TEST_FFFF("require that state api also can return total metric", + SimpleHealthProducer(), SimpleMetricsProducer(), SimpleComponentConfigProducer(), + StateApi(f1, f2, f3)) +{ + f2.setTotalMetrics("{\"foo\":\"bar\"}"); + EXPECT_EQUAL("{\"foo\":\"bar\"}", + f4.get(host_tag, total_metrics_path, empty_params)); +} + +TEST_FFFFF("require that custom handlers can be added to the state server", + SimpleHealthProducer(), SimpleMetricsProducer(), SimpleComponentConfigProducer(), + StateApi(f1, f2, f3), DummyHandler("[123]")) +{ + EXPECT_EQUAL("", f4.get(host_tag, my_path, empty_params)); + auto token = f4.repo().bind(my_path, f5); + EXPECT_EQUAL("[123]", f4.get(host_tag, my_path, empty_params)); + token.reset(); + EXPECT_EQUAL("", f4.get(host_tag, my_path, empty_params)); +} + +struct EchoConsumer : MetricsProducer { + virtual vespalib::string getMetrics(const vespalib::string &consumer) { + return "[\"" + consumer + "\"]"; + } + virtual vespalib::string getTotalMetrics(const vespalib::string &consumer) { + return "[\"" + consumer + "\"]"; + } +}; + +TEST_FFFF("require that metrics consumer is passed correctly", + SimpleHealthProducer(), EchoConsumer(), SimpleComponentConfigProducer(), + StateApi(f1, f2, f3)) +{ + std::map<vespalib::string,vespalib::string> my_params; + my_params["consumer"] = "ME"; + EXPECT_EQUAL("{\"status\":{\"code\":\"up\"},\"metrics\":[\"\"]}", f4.get(host_tag, metrics_path, empty_params)); + EXPECT_EQUAL("{\"status\":{\"code\":\"up\"},\"metrics\":[\"ME\"]}", f4.get(host_tag, metrics_path, my_params)); + EXPECT_EQUAL("[\"\"]", f4.get(host_tag, total_metrics_path, empty_params)); + EXPECT_EQUAL("[\"ME\"]", f4.get(host_tag, total_metrics_path, my_params)); +} + +void check_json(const vespalib::string &expect_json, const vespalib::string &actual_json) { + Slime expect_slime; + Slime actual_slime; + EXPECT_TRUE(slime::JsonFormat::decode(expect_json, expect_slime) > 0); + EXPECT_TRUE(slime::JsonFormat::decode(actual_json, actual_slime) > 0); + EXPECT_EQUAL(expect_slime, actual_slime); +} + +TEST("require that generic state can be explored") { + vespalib::string json_model = + "{" + " foo: 'bar'," + " cnt: 123," + " engine: {" + " up: 'yes'," + " stats: {" + " latency: 5," + " qps: 100" + " }" + " }," + " list: {" + " one: {" + " size: {" + " value: 1" + " }" + " }," + " two: {" + " size: 2" + " }" + " }" + "}"; + vespalib::string json_root = + "{" + " full: true," + " foo: 'bar'," + " cnt: 123," + " engine: {" + " up: 'yes'," + " url: 'http://HOST/state/v1/engine'" + " }," + " list: {" + " one: {" + " size: {" + " value: 1," + " url: 'http://HOST/state/v1/list/one/size'" + " }" + " }," + " two: {" + " size: 2," + " url: 'http://HOST/state/v1/list/two'" + " }" + " }" + "}"; + vespalib::string json_engine = + "{" + " full: true," + " up: 'yes'," + " stats: {" + " latency: 5," + " qps: 100," + " url: 'http://HOST/state/v1/engine/stats'" + " }" + "}"; + vespalib::string json_engine_stats = + "{" + " full: true," + " latency: 5," + " qps: 100" + "}"; + vespalib::string json_list = + "{" + " one: {" + " size: {" + " value: 1," + " url: 'http://HOST/state/v1/list/one/size'" + " }" + " }," + " two: {" + " size: 2," + " url: 'http://HOST/state/v1/list/two'" + " }" + "}"; + vespalib::string json_list_one = + "{" + " size: {" + " value: 1," + " url: 'http://HOST/state/v1/list/one/size'" + " }" + "}"; + vespalib::string json_list_one_size = "{ full: true, value: 1 }"; + vespalib::string json_list_two = "{ full: true, size: 2 }"; + //------------------------------------------------------------------------- + Slime slime_state; + EXPECT_TRUE(slime::JsonFormat::decode(json_model, slime_state) > 0); + SlimeExplorer slime_explorer(slime_state.get()); + GenericStateHandler state_handler(short_root_path, slime_explorer); + EXPECT_EQUAL("", state_handler.get(host_tag, unknown_path, empty_params)); + EXPECT_EQUAL("", state_handler.get(host_tag, unknown_state_path, empty_params)); + check_json(json_root, state_handler.get(host_tag, root_path, empty_params)); + check_json(json_engine, state_handler.get(host_tag, root_path + "engine", empty_params)); + check_json(json_engine_stats, state_handler.get(host_tag, root_path + "engine/stats", empty_params)); + check_json(json_list, state_handler.get(host_tag, root_path + "list", empty_params)); + check_json(json_list_one, state_handler.get(host_tag, root_path + "list/one", empty_params)); + check_json(json_list_one_size, state_handler.get(host_tag, root_path + "list/one/size", empty_params)); + check_json(json_list_two, state_handler.get(host_tag, root_path + "list/two", empty_params)); +} + +TEST_MAIN_WITH_PROCESS_PROXY() { TEST_RUN_ALL(); } diff --git a/staging_vespalib/src/tests/stllike/.gitignore b/staging_vespalib/src/tests/stllike/.gitignore new file mode 100644 index 00000000000..268b9e88393 --- /dev/null +++ b/staging_vespalib/src/tests/stllike/.gitignore @@ -0,0 +1,6 @@ +.depend +Makefile +lrucache_test +cache_test +staging_vespalib_cache_test_app +staging_vespalib_lrucache_test_app diff --git a/staging_vespalib/src/tests/stllike/CMakeLists.txt b/staging_vespalib/src/tests/stllike/CMakeLists.txt new file mode 100644 index 00000000000..690582676ad --- /dev/null +++ b/staging_vespalib/src/tests/stllike/CMakeLists.txt @@ -0,0 +1,15 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(staging_vespalib_lrucache_test_app + SOURCES + lrucache.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_lrucache_test_app COMMAND staging_vespalib_lrucache_test_app) +vespa_add_executable(staging_vespalib_cache_test_app + SOURCES + cache_test.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_cache_test_app COMMAND staging_vespalib_cache_test_app) diff --git a/staging_vespalib/src/tests/stllike/DESC b/staging_vespalib/src/tests/stllike/DESC new file mode 100644 index 00000000000..ec13a79916b --- /dev/null +++ b/staging_vespalib/src/tests/stllike/DESC @@ -0,0 +1 @@ +hash test. Take a look at hash.cpp for details. diff --git a/staging_vespalib/src/tests/stllike/FILES b/staging_vespalib/src/tests/stllike/FILES new file mode 100644 index 00000000000..eb3794b4a28 --- /dev/null +++ b/staging_vespalib/src/tests/stllike/FILES @@ -0,0 +1,3 @@ +hash.cpp +uniq_by_sort_map_hash.cpp +lrucache.cpp diff --git a/staging_vespalib/src/tests/stllike/avl.cpp b/staging_vespalib/src/tests/stllike/avl.cpp new file mode 100644 index 00000000000..53df03319d7 --- /dev/null +++ b/staging_vespalib/src/tests/stllike/avl.cpp @@ -0,0 +1,265 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/fastos/fastos.h> +#include <vespa/log/log.h> +LOG_SETUP("memory_test"); +#include <vespa/vespalib/testkit/testapp.h> +#include <vespalib/stllike/avl_set.h> +#include <vespa/vespalib/stllike/avl_map.h> + +using namespace vespalib; +using std::make_pair; + +class Test : public TestApp +{ +public: + int Main(); + void testAvlTreeSet(); + void testAvlTreeSet2(); + void testAvlTreeMap(); + void testAvlTreeFind(); +}; + +int +Test::Main() +{ + TEST_INIT("avl_test"); + testAvlTreeSet(); + testAvlTreeSet2(); + testAvlTreeMap(); + testAvlTreeFind(); + TEST_DONE(); +} + +namespace { + struct Foo { + int i; + + Foo() : i(0) {} + Foo(int i_) : i(i_) {} + + bool operator<(const Foo& f) const + { return (i < f.i); } + friend std::ostream & operator << (std::ostream & os, const Foo & f) { return os << f.i; } + }; +} + +void Test::testAvlTreeSet2() +{ + const size_t testSize(2000); + avl_set<Foo> set(100); + // Verfify start conditions. + EXPECT_TRUE(set.size() == 0); + EXPECT_TRUE(set.begin() == set.end()); + EXPECT_TRUE(set.find(7) == set.end()); + // Insert one element + set.insert(Foo(7)); + EXPECT_TRUE(set.size() == 1); + EXPECT_TRUE(set.begin() != set.end()); + EXPECT_TRUE(set.find(Foo(7)) != set.end()); + EXPECT_TRUE(*set.find(Foo(7)) == Foo(7)); + EXPECT_TRUE(set.find(Foo(8)) == set.end()); + // erase non existing + set.erase(Foo(8)); + EXPECT_TRUE(set.size() == 1); + EXPECT_TRUE(set.begin() != set.end()); + EXPECT_TRUE(set.find(Foo(7)) != set.end()); + EXPECT_TRUE(*set.find(Foo(7)) == Foo(7)); + EXPECT_TRUE(set.find(Foo(8)) == set.end()); + // erase existing + set.erase(Foo(7)); + EXPECT_TRUE(set.size() == 0); + EXPECT_TRUE(set.begin() == set.end()); + EXPECT_TRUE(set.find(Foo(7)) == set.end()); + for (size_t i(0); i < testSize; i++) { + set.insert(Foo(i)); + avl_set<Foo, Foo::avl>::iterator it = set.find(Foo(i)); + ASSERT_TRUE(it != set.end()); + for (size_t j=0; j < i; j++) { + it = set.find(Foo(j)); + ASSERT_TRUE(it != set.end()); + } + } + EXPECT_TRUE(set.size() == testSize); + avl_set<Foo, Foo::avl>::iterator it = set.find(Foo((testSize/2)-1)); + ASSERT_TRUE(it != set.end()); + EXPECT_EQUAL(*it, Foo((testSize/2)-1)); + for (size_t i(0); i < testSize/2; i++) { + set.erase(Foo(i*2)); + } + ASSERT_TRUE(it != set.end()); + EXPECT_EQUAL(*it, Foo((testSize/2)-1)); + EXPECT_TRUE(set.find(Foo(testSize/2)) == set.end()); + EXPECT_TRUE(set.size() == testSize/2); + for (size_t i(0); i < testSize; i++) { + set.insert(Foo(i)); + } + EXPECT_EQUAL(set.size(), testSize); + EXPECT_TRUE(*set.find(Foo(7)) == Foo(7)); + EXPECT_TRUE(*set.find(Foo(0)) == Foo(0)); + EXPECT_TRUE(*set.find(Foo(1)) == Foo(1)); + EXPECT_TRUE(*set.find(Foo(testSize-1)) == Foo(testSize-1)); + EXPECT_TRUE(set.find(Foo(testSize)) == set.end()); + + set.clear(); + + EXPECT_EQUAL(set.size(), 0u); + EXPECT_TRUE(set.find(Foo(7)) == set.end()); +} + +void Test::testAvlTreeSet() +{ + avl_set<int> set(1000); + // Verfify start conditions. + EXPECT_TRUE(set.size() == 0); + EXPECT_TRUE(set.begin() == set.end()); + EXPECT_TRUE(set.find(7) == set.end()); + // Insert one element + set.insert(7); + EXPECT_TRUE(set.size() == 1); + EXPECT_TRUE(set.begin() != set.end()); + EXPECT_TRUE(set.find(7) != set.end()); + EXPECT_TRUE(*set.find(7) == 7); + EXPECT_TRUE(set.find(8) == set.end()); + // erase non existing + set.erase(8); + EXPECT_TRUE(set.size() == 1); + EXPECT_TRUE(set.begin() != set.end()); + EXPECT_TRUE(set.find(7) != set.end()); + EXPECT_TRUE(*set.find(7) == 7); + EXPECT_TRUE(set.find(8) == set.end()); + // erase existing + set.erase(7); + EXPECT_TRUE(set.size() == 0); + EXPECT_TRUE(set.begin() == set.end()); + EXPECT_TRUE(set.find(7) == set.end()); + for (size_t i(0); i < 10000; i++) { + set.insert(i); + } + EXPECT_TRUE(set.size() == 10000); + for (size_t i(0); i < 5000; i++) { + set.erase(i*2); + } + EXPECT_TRUE(*set.find(4999) == 4999); + EXPECT_TRUE(set.find(5000) == set.end()); + EXPECT_TRUE(set.size() == 5000); + for (size_t i(0); i < 10000; i++) { + set.insert(i); + } + EXPECT_EQUAL(set.size(), 10000u); + EXPECT_TRUE(*set.find(7) == 7); + EXPECT_TRUE(*set.find(0) == 0); + EXPECT_TRUE(*set.find(1) == 1); + EXPECT_TRUE(*set.find(9999) == 9999); + EXPECT_TRUE(set.find(10000) == set.end()); + + set.clear(); + + EXPECT_EQUAL(set.size(), 0u); + EXPECT_TRUE(set.find(7) == set.end()); +} + +void Test::testAvlTreeMap() +{ + avl_map<int, int> set(1000); + // Verfify start conditions. + EXPECT_TRUE(set.size() == 0); + EXPECT_TRUE(set.begin() == set.end()); + EXPECT_TRUE(set.find(7) == set.end()); + // Insert one element + set.insert(make_pair(7, 70)); + EXPECT_TRUE(set.size() == 1); + EXPECT_TRUE(set.begin() != set.end()); + EXPECT_TRUE(set.find(7) != set.end()); + EXPECT_TRUE(set.find(7)->first == 7); + EXPECT_TRUE(set.find(7)->second == 70); + EXPECT_TRUE(set.find(8) == set.end()); + // erase non existing + set.erase(8); + EXPECT_TRUE(set.size() == 1); + EXPECT_TRUE(set.begin() != set.end()); + EXPECT_TRUE(set.find(7) != set.end()); + EXPECT_TRUE(set.find(7)->first == 7); + EXPECT_TRUE(set.find(7)->second == 70); + EXPECT_TRUE(set.find(8) == set.end()); + // erase existing + set.erase(7); + EXPECT_TRUE(set.size() == 0); + EXPECT_TRUE(set.begin() == set.end()); + EXPECT_TRUE(set.find(7) == set.end()); + for (size_t i(0); i < 10000; i++) { + set.insert(make_pair(i,i*10)); + } + EXPECT_TRUE(set.size() == 10000); + for (size_t i(0); i < 5000; i++) { + set.erase(i*2); + } + EXPECT_TRUE(set.find(4999)->first == 4999); + EXPECT_TRUE(set.find(4999)->second == 49990); + EXPECT_TRUE(set.find(5000) == set.end()); + EXPECT_TRUE(set.size() == 5000); + for (size_t i(0); i < 10000; i++) { + set.insert(make_pair(i,i*10)); + } + EXPECT_EQUAL(set.size(), 10000u); + EXPECT_TRUE(set.find(7)->first == 7); + EXPECT_TRUE(set.find(7)->second == 70); + EXPECT_TRUE(set.find(0)->first == 0); + EXPECT_TRUE(set.find(0)->second == 0); + EXPECT_TRUE(set.find(1)->first == 1); + EXPECT_TRUE(set.find(1)->second == 10); + EXPECT_TRUE(set.find(9999)->first == 9999); + EXPECT_TRUE(set.find(9999)->second == 99990); + EXPECT_TRUE(set.find(10000) == set.end()); + + avl_map<int, int> set2(7); + set.swap(set2); + EXPECT_EQUAL(set2.size(), 10000u); + EXPECT_TRUE(set2.find(7)->first == 7); + EXPECT_TRUE(set2.find(7)->second == 70); + + EXPECT_EQUAL(set.size(), 0u); + EXPECT_TRUE(set.find(7) == set.end()); + for (int i=0; i < 100; i++) { + set.insert(make_pair(i,i*10)); + } + for (int i=0; i < 100; i++) { + EXPECT_TRUE(set.find(i)->second == i*10); + } + + avl_map<int, int> set3; + set3.insert(set.begin(), set.end()); + for (int i=0; i < 100; i++) { + EXPECT_EQUAL(i*10, set.find(i)->second); + } +} + +class S { +public: + explicit S(uint64_t l=0) : _a(l&0xfffffffful), _b(l>>32) { } + uint32_t avl() const { return _a; } + uint32_t a() const { return _a; } + friend bool operator == (const S & a, const S & b) { return a._a == b._a && a._b == b._b; } +private: + uint32_t _a, _b; +}; + +struct myavl { + size_t operator() (const S & arg) const { return arg.avl(); } +}; + +struct myextract { + uint32_t operator() (const S & arg) const { return arg.a(); } +}; + +void Test::testAvlTreeFind() +{ + avl_set<S, myavl> set(1000); + for (size_t i(0); i < 10000; i++) { + set.insert(S(i)); + } + EXPECT_TRUE(*set.find(S(1)) == S(1)); + avl_set<S, myavl>::iterator cit = set.find<uint32_t, myextract, vespalib::avl<uint32_t>, std::equal_to<uint32_t> >(7); + EXPECT_TRUE(*cit == S(7)); +} + +TEST_APPHOOK(Test) diff --git a/staging_vespalib/src/tests/stllike/cache_test.cpp b/staging_vespalib/src/tests/stllike/cache_test.cpp new file mode 100644 index 00000000000..288ef367be4 --- /dev/null +++ b/staging_vespalib/src/tests/stllike/cache_test.cpp @@ -0,0 +1,165 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/fastos/fastos.h> +#include <vespa/log/log.h> +LOG_SETUP("cache_test"); +#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/stllike/string.h> +#include <vespa/vespalib/stllike/cache.h> +#include <map> + +using namespace vespalib; + +template<typename K, typename V> +class Map : public std::map<K, V> { + typedef typename std::map<K, V>::const_iterator const_iterator; + typedef std::map<K, V> M; +public: + bool read(const K & k, V & v) const { + const_iterator found = M::find(k); + bool ok(found != this->end()); + if (ok) { + v = found->second; + } + return ok; + } + void write(const K & k, const V & v) { + (*this)[k] = v; + } + void erase(const K & k) { + M::erase(k); + } +}; + +class Test : public TestApp +{ +public: + int Main(); +private: + typedef LruParam<uint32_t, string> P; + typedef Map<uint32_t, string> B; + void testCache(); + void testCacheSize(); + void testCacheSizeDeep(); + void testCacheEntriesHonoured(); + void testCacheMaxSizeHonoured(); + void testThatMultipleRemoveOnOverflowIsFine(); +}; + +int +Test::Main() +{ + TEST_INIT("cache_test"); + testCache(); + testCacheSize(); + testCacheSizeDeep(); + testCacheEntriesHonoured(); + testCacheMaxSizeHonoured(); + testThatMultipleRemoveOnOverflowIsFine(); + TEST_DONE(); +} + +void Test::testCache() +{ + B m; + cache< CacheParam<P, B> > cache(m, -1); + // Verfify start conditions. + EXPECT_TRUE(cache.size() == 0); + EXPECT_TRUE( ! cache.hasKey(1) ); + cache.write(1, "First inserted string"); + EXPECT_TRUE( cache.hasKey(1) ); + m[2] = "String inserted beneath"; + EXPECT_TRUE( ! cache.hasKey(2) ); + EXPECT_EQUAL( cache.read(2), "String inserted beneath"); + EXPECT_TRUE( cache.hasKey(2) ); + cache.erase(1); + EXPECT_TRUE( ! cache.hasKey(1) ); + EXPECT_TRUE(cache.size() == 1); +} + +void Test::testCacheSize() +{ + B m; + cache< CacheParam<P, B> > cache(m, -1); + cache.write(1, "10 bytes string"); + EXPECT_EQUAL(80u, cache.sizeBytes()); +} + +void Test::testCacheSizeDeep() +{ + B m; + cache< CacheParam<P, B, zero<uint32_t>, size<string> > > cache(m, -1); + cache.write(1, "15 bytes string"); + EXPECT_EQUAL(95u, cache.sizeBytes()); +} + +void Test::testCacheEntriesHonoured() +{ + B m; + cache< CacheParam<P, B, zero<uint32_t>, size<string> > > cache(m, -1); + cache.maxElements(1); + cache.write(1, "15 bytes string"); + EXPECT_EQUAL(1u, cache.size()); + EXPECT_EQUAL(95u, cache.sizeBytes()); + cache.write(2, "16 bytes stringg"); + EXPECT_EQUAL(1u, cache.size()); + EXPECT_TRUE( cache.hasKey(2) ); + EXPECT_FALSE( cache.hasKey(1) ); + EXPECT_EQUAL(96u, cache.sizeBytes()); +} + +void Test::testCacheMaxSizeHonoured() +{ + B m; + cache< CacheParam<P, B, zero<uint32_t>, size<string> > > cache(m, 200); + cache.write(1, "15 bytes string"); + EXPECT_EQUAL(1u, cache.size()); + EXPECT_EQUAL(95u, cache.sizeBytes()); + cache.write(2, "16 bytes stringg"); + EXPECT_EQUAL(2u, cache.size()); + EXPECT_EQUAL(191u, cache.sizeBytes()); + cache.write(3, "17 bytes stringgg"); + EXPECT_EQUAL(3u, cache.size()); + EXPECT_EQUAL(288u, cache.sizeBytes()); + cache.write(4, "18 bytes stringggg"); + EXPECT_EQUAL(3u, cache.size()); + EXPECT_EQUAL(291u, cache.sizeBytes()); +} + +void Test::testThatMultipleRemoveOnOverflowIsFine() +{ + B m; + cache< CacheParam<P, B, zero<uint32_t>, size<string> > > cache(m, 2000); + + for (size_t j(0); j < 5; j++) { + for (size_t i(0); cache.size() == i; i++) { + cache.write(j*53+i, "a"); + } + } + EXPECT_EQUAL(25u, cache.size()); + EXPECT_EQUAL(2025u, cache.sizeBytes()); + EXPECT_FALSE( cache.hasKey(0) ); + string ls("long string aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); + string vls=ls+ls+ls+ls+ls+ls; + cache.write(53+5, ls); + EXPECT_EQUAL(25u, cache.size()); + EXPECT_EQUAL(2498u, cache.sizeBytes()); + EXPECT_FALSE( cache.hasKey(1) ); + cache.write(53*7+5, ls); + EXPECT_EQUAL(19u, cache.size()); + EXPECT_EQUAL(2485u, cache.sizeBytes()); + EXPECT_FALSE( cache.hasKey(2) ); + cache.write(53*8+5, vls); + EXPECT_EQUAL(14u, cache.size()); + EXPECT_EQUAL(4923u, cache.sizeBytes()); + cache.write(53*9+6, vls); + EXPECT_EQUAL(1u, cache.size()); + EXPECT_EQUAL(2924u, cache.sizeBytes()); +} + + +TEST_APPHOOK(Test) diff --git a/staging_vespalib/src/tests/stllike/lrucache.cpp b/staging_vespalib/src/tests/stllike/lrucache.cpp new file mode 100644 index 00000000000..de5bcb8a365 --- /dev/null +++ b/staging_vespalib/src/tests/stllike/lrucache.cpp @@ -0,0 +1,192 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/fastos/fastos.h> +#include <vespa/log/log.h> +LOG_SETUP("lrucache_test"); +#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/stllike/string.h> +#include <vespa/vespalib/stllike/lrucache_map.h> + +using namespace vespalib; + +TEST("testCache") { + lrucache_map< LruParam<int, string> > cache(7); + // Verfify start conditions. + EXPECT_TRUE(cache.size() == 0); + cache.insert(1, "First inserted string"); + EXPECT_TRUE(cache.verifyInternals()); + EXPECT_TRUE(cache.size() == 1); + EXPECT_TRUE(cache.hasKey(1)); + cache.insert(2, "Second inserted string"); + EXPECT_TRUE(cache.verifyInternals()); + EXPECT_TRUE(cache.size() == 2); + EXPECT_TRUE(cache.hasKey(1)); + EXPECT_TRUE(cache.hasKey(2)); + cache.insert(3, "Third inserted string"); + EXPECT_TRUE(cache.verifyInternals()); + EXPECT_TRUE(cache.size() == 3); + EXPECT_TRUE(cache.hasKey(1)); + EXPECT_TRUE(cache.hasKey(2)); + EXPECT_TRUE(cache.hasKey(3)); + cache.insert(4, "Fourth inserted string"); + EXPECT_TRUE(cache.verifyInternals()); + EXPECT_TRUE(cache.size() == 4); + EXPECT_TRUE(cache.hasKey(1)); + EXPECT_TRUE(cache.hasKey(2)); + EXPECT_TRUE(cache.hasKey(3)); + EXPECT_TRUE(cache.hasKey(4)); + cache.insert(5, "Fifth inserted string"); + EXPECT_TRUE(cache.verifyInternals()); + EXPECT_TRUE(cache.size() == 5); + EXPECT_TRUE(cache.hasKey(1)); + EXPECT_TRUE(cache.hasKey(2)); + EXPECT_TRUE(cache.hasKey(3)); + EXPECT_TRUE(cache.hasKey(4)); + EXPECT_TRUE(cache.hasKey(5)); + cache.insert(6, "Sixt inserted string"); + EXPECT_TRUE(cache.verifyInternals()); + EXPECT_TRUE(cache.size() == 6); + EXPECT_TRUE(cache.hasKey(1)); + EXPECT_TRUE(cache.hasKey(2)); + EXPECT_TRUE(cache.hasKey(3)); + EXPECT_TRUE(cache.hasKey(4)); + EXPECT_TRUE(cache.hasKey(5)); + EXPECT_TRUE(cache.hasKey(6)); + cache.insert(7, "Seventh inserted string"); + EXPECT_TRUE(cache.verifyInternals()); + EXPECT_EQUAL(cache.size(), 7u); + EXPECT_TRUE(cache.hasKey(1)); + EXPECT_TRUE(cache.hasKey(2)); + EXPECT_TRUE(cache.hasKey(3)); + EXPECT_TRUE(cache.hasKey(4)); + EXPECT_TRUE(cache.hasKey(5)); + EXPECT_TRUE(cache.hasKey(6)); + EXPECT_TRUE(cache.hasKey(7)); + cache.insert(8, "Eighth inserted string"); + EXPECT_TRUE(cache.verifyInternals()); + EXPECT_EQUAL(cache.size(), 7u); + EXPECT_TRUE(cache.hasKey(2)); + EXPECT_TRUE(cache.hasKey(3)); + EXPECT_TRUE(cache.hasKey(4)); + EXPECT_TRUE(cache.hasKey(5)); + EXPECT_TRUE(cache.hasKey(6)); + EXPECT_TRUE(cache.hasKey(7)); + EXPECT_TRUE(cache.hasKey(8)); + cache.insert(15, "Eighth inserted string"); + EXPECT_TRUE(cache.verifyInternals()); + EXPECT_EQUAL(cache.size(), 7u); + EXPECT_TRUE(cache.hasKey(3)); + EXPECT_TRUE(cache.hasKey(4)); + EXPECT_TRUE(cache.hasKey(5)); + EXPECT_TRUE(cache.hasKey(6)); + EXPECT_TRUE(cache.hasKey(7)); + EXPECT_TRUE(cache.hasKey(8)); + EXPECT_TRUE(cache.hasKey(15)); + // Test get and erase + cache.get(3); + EXPECT_TRUE(cache.verifyInternals()); + cache.erase(3); + EXPECT_TRUE(cache.verifyInternals()); + EXPECT_TRUE(!cache.hasKey(3)); +} + +typedef std::shared_ptr<std::string> MyKey; +typedef std::shared_ptr<std::string> MyData; + +struct SharedEqual : public std::binary_function<MyKey, MyKey, bool> { + bool operator()(const MyKey & a, const MyKey & b) { + return ((*a) == (*b)); + } +}; + +struct SharedHash { + size_t operator() (const MyKey & arg) const { return arg->size(); } +}; + + +TEST("testCacheInsertOverResize") { + typedef vespalib::LinkedPtr<std::string> LS; + typedef lrucache_map< LruParam<int, LS> > Cache; + + Cache cache(100); + size_t sum(0); + for (size_t i(0); i < cache.capacity()*10; i++) { + LS s(new std::string("abc")); + cache[random()] = s; + sum += strlen(s->c_str()); + EXPECT_EQUAL(strlen(s->c_str()), s->size()); + } + EXPECT_EQUAL(sum, cache.capacity()*10*3); +} + +TEST("testCacheErase") { + lrucache_map< LruParam<MyKey, MyData, SharedHash, SharedEqual> > cache(4); + + MyData d(new std::string("foo")); + MyKey k(new std::string("barlol")); + // Verfify start conditions. + EXPECT_TRUE(cache.size() == 0); + EXPECT_TRUE(d.use_count() == 1); + EXPECT_TRUE(k.use_count() == 1); + cache.insert(k, d); + EXPECT_TRUE(d.use_count() == 2); + EXPECT_TRUE(k.use_count() == 2); + cache.erase(k); + EXPECT_TRUE(d.use_count() == 1); + EXPECT_TRUE(k.use_count() == 1); +} + +TEST("testCacheIterator") { + typedef lrucache_map< LruParam<int, string> > Cache; + Cache cache(3); + cache.insert(1, "first"); + cache.insert(2, "second"); + cache.insert(3, "third"); + Cache::iterator it(cache.begin()); + Cache::iterator mt(cache.end()); + ASSERT_TRUE(it != mt); + ASSERT_EQUAL("third", *it); + ASSERT_TRUE(it != mt); + ASSERT_EQUAL("second", *(++it)); + ASSERT_TRUE(it != mt); + ASSERT_EQUAL("second", *it++); + ASSERT_TRUE(it != mt); + ASSERT_EQUAL("first", *it); + ASSERT_TRUE(it != mt); + it++; + ASSERT_TRUE(it == mt); + cache.insert(4, "fourth"); + Cache::iterator it2(cache.begin()); + Cache::iterator it3(cache.begin()); + ASSERT_EQUAL("fourth", *it2); + ASSERT_TRUE(it2 == it3); + it2++; + ASSERT_TRUE(it2 != it3); + it2++; + it2++; + ASSERT_TRUE(it2 == mt); + Cache::iterator it4 = cache.erase(it3); + ASSERT_EQUAL("third", *it4); + ASSERT_EQUAL("third", *cache.begin()); + Cache::iterator it5(cache.erase(cache.end())); + ASSERT_TRUE(it5 == cache.end()); +} + +TEST("testCacheIteratorErase") { + typedef lrucache_map< LruParam<int, string> > Cache; + Cache cache(3); + cache.insert(1, "first"); + cache.insert(8, "second"); + cache.insert(15, "third"); + cache.insert(15, "third"); + cache.insert(8, "second"); + cache.insert(1, "first"); + Cache::iterator it(cache.begin()); + ASSERT_EQUAL("first", *it); + it++; + ASSERT_EQUAL("second", *it); + it = cache.erase(it); + ASSERT_EQUAL("third", *it); + cache.erase(it); +} + +TEST_MAIN() { TEST_RUN_ALL(); } diff --git a/staging_vespalib/src/tests/timer/.gitignore b/staging_vespalib/src/tests/timer/.gitignore new file mode 100644 index 00000000000..9031e40152a --- /dev/null +++ b/staging_vespalib/src/tests/timer/.gitignore @@ -0,0 +1 @@ +staging_vespalib_timer_test_app diff --git a/staging_vespalib/src/tests/timer/CMakeLists.txt b/staging_vespalib/src/tests/timer/CMakeLists.txt new file mode 100644 index 00000000000..ab16cc236c4 --- /dev/null +++ b/staging_vespalib/src/tests/timer/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(staging_vespalib_timer_test_app + SOURCES + timer_test.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_timer_test_app COMMAND staging_vespalib_timer_test_app) diff --git a/staging_vespalib/src/tests/timer/timer_test.cpp b/staging_vespalib/src/tests/timer/timer_test.cpp new file mode 100644 index 00000000000..de2f081f48a --- /dev/null +++ b/staging_vespalib/src/tests/timer/timer_test.cpp @@ -0,0 +1,60 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/fastos/fastos.h> +#include <vespa/log/log.h> +LOG_SETUP("timer_test"); +#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/util/timer.h> +#include <vespa/vespalib/util/executor.h> + +using namespace vespalib; +using vespalib::Executor; +typedef Executor::Task Task; + +class Test : public TestApp +{ +public: + int Main(); + void testScheduling(); + void testReset(); +}; + +class TestTask : public Task { +private: + vespalib::CountDownLatch &_latch; +public: + TestTask(vespalib::CountDownLatch & latch) : _latch(latch) { } + void run() { _latch.countDown(); } +}; + +int +Test::Main() +{ + TEST_INIT("timer_test"); + testScheduling(); + testReset(); + TEST_DONE(); +} + +void Test::testScheduling() +{ + vespalib::CountDownLatch latch1(3); + vespalib::CountDownLatch latch2(2); + Timer timer; + timer.scheduleAtFixedRate(Task::UP(new TestTask(latch1)), 0.1, 0.2); + timer.scheduleAtFixedRate(Task::UP(new TestTask(latch2)), 0.5, 0.5); + EXPECT_TRUE(latch1.await(60000)); + EXPECT_TRUE(latch2.await(60000)); +} + +void Test::testReset() +{ + vespalib::CountDownLatch latch1(2); + Timer timer; + timer.scheduleAtFixedRate(Task::UP(new TestTask(latch1)), 2.0, 3.0); + timer.reset(); + EXPECT_TRUE(!latch1.await(3000)); + timer.scheduleAtFixedRate(Task::UP(new TestTask(latch1)), 0.2, 0.3); + EXPECT_TRUE(latch1.await(60000)); +} + +TEST_APPHOOK(Test) diff --git a/staging_vespalib/src/tests/trace/.gitignore b/staging_vespalib/src/tests/trace/.gitignore new file mode 100644 index 00000000000..14ed55a124e --- /dev/null +++ b/staging_vespalib/src/tests/trace/.gitignore @@ -0,0 +1 @@ +staging_vespalib_trace_test_app diff --git a/staging_vespalib/src/tests/trace/CMakeLists.txt b/staging_vespalib/src/tests/trace/CMakeLists.txt new file mode 100644 index 00000000000..cb381733bff --- /dev/null +++ b/staging_vespalib/src/tests/trace/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(staging_vespalib_trace_test_app + SOURCES + trace.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_trace_test_app COMMAND staging_vespalib_trace_test_app) diff --git a/staging_vespalib/src/tests/trace/trace.cpp b/staging_vespalib/src/tests/trace/trace.cpp new file mode 100644 index 00000000000..a7896d43338 --- /dev/null +++ b/staging_vespalib/src/tests/trace/trace.cpp @@ -0,0 +1,110 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/fastos/fastos.h> +#include <vespa/log/log.h> +LOG_SETUP("trace_test"); +#include <vespa/vespalib/testkit/test_kit.h> +#include <vespa/vespalib/trace/tracenode.h> +#include <vespa/vespalib/trace/slime_trace_serializer.h> +#include <vespa/vespalib/trace/slime_trace_deserializer.h> + +using namespace vespalib; +using namespace vespalib::slime; + +TEST("that a single trace node is serialized") { + TraceNode node; + Slime slime; + SlimeTraceSerializer serializer(slime.setObject()); + node.accept(serializer); + Inspector & i(slime.get()); + EXPECT_TRUE(i["timestamp"].valid()); + EXPECT_EQUAL(0l, i["timestamp"].asLong()); + EXPECT_FALSE(i["payload"].valid()); +} + +TEST("that a trace node with children is serialized") { + TraceNode node; + node.addChild("foo", 1234); + node.addChild("bar", 1235); + Slime slime; + SlimeTraceSerializer serializer(slime.setObject()); + node.accept(serializer); + Inspector & i(slime.get()); + EXPECT_TRUE(i["timestamp"].valid()); + EXPECT_EQUAL(0l, i["timestamp"].asLong()); + EXPECT_TRUE(i["children"].valid()); + Inspector & iBar(i["children"][0]); + Inspector & iFoo(i["children"][1]); + EXPECT_TRUE(iFoo.valid()); + EXPECT_TRUE(iBar.valid()); + EXPECT_EQUAL(1234, iFoo["timestamp"].asLong()); + EXPECT_EQUAL("foo", iFoo["payload"].asString().make_string()); + EXPECT_EQUAL(1235, iBar["timestamp"].asLong()); + EXPECT_EQUAL("bar", iBar["payload"].asString().make_string()); +} + +TEST("that an empty root trace node can be deserialized") { + Slime slime; + Cursor & root(slime.setObject()); + SlimeTraceDeserializer deserializer(root); + TraceNode node(deserializer.deserialize()); + EXPECT_FALSE(node.hasNote()); + EXPECT_EQUAL(0, node.getTimestamp()); +} + + +TEST("that a single trace node can be deserialized") { + Slime slime; + Cursor & root(slime.setObject()); + root.setLong("timestamp", 1234); + root.setString("payload", "hello"); + SlimeTraceDeserializer deserializer(root); + TraceNode node(deserializer.deserialize()); + EXPECT_EQUAL(1234, node.getTimestamp()); + EXPECT_TRUE(node.hasNote()); + EXPECT_EQUAL("hello", node.getNote()); +} + +TEST("that a trace node with children can be deserialized") { + Slime slime; + Cursor & root(slime.setObject()); + Cursor & rootChildren(root.setArray("children")); + Cursor & foo(rootChildren.addObject()); + foo.setLong("timestamp", 123); + Cursor &fooArray(foo.setArray("children")); + Cursor &foobar(fooArray.addObject()); + foobar.setLong("timestamp", 45); + foobar.setString("payload", "world"); + Cursor & bar(rootChildren.addObject()); + bar.setLong("timestamp", 67); + bar.setString("payload", "!"); + + vespalib::slime::SimpleBuffer buf; + vespalib::slime::JsonFormat::encode(slime, buf, false); + + SlimeTraceDeserializer deserializer(root); + TraceNode node(deserializer.deserialize()); + EXPECT_FALSE(node.hasNote()); + ASSERT_EQUAL(2u, node.getNumChildren()); + TraceNode fooNode(node.getChild(0)); + ASSERT_EQUAL(1u, fooNode.getNumChildren()); + TraceNode fooBarNode(fooNode.getChild(0)); + EXPECT_EQUAL("world", fooBarNode.getNote()); + TraceNode barNode(node.getChild(1)); + EXPECT_EQUAL("!", barNode.getNote()); + ASSERT_EQUAL(0u, barNode.getNumChildren()); +} + +TEST("test serialization and deserialization") { + TraceNode root; + root.addChild("foo", 45); + root.addChild("bar"); + root.addChild(TraceNode()); + Slime slime; + SlimeTraceSerializer s(slime.setObject()); + root.accept(s); + SlimeTraceDeserializer d(slime.get()); + TraceNode root2(d.deserialize()); + ASSERT_EQUAL(3u, root2.getNumChildren()); +} + +TEST_MAIN() { TEST_RUN_ALL(); } diff --git a/staging_vespalib/src/tests/util/process_memory_stats/.gitignore b/staging_vespalib/src/tests/util/process_memory_stats/.gitignore new file mode 100644 index 00000000000..e32e9f22dd3 --- /dev/null +++ b/staging_vespalib/src/tests/util/process_memory_stats/.gitignore @@ -0,0 +1,2 @@ +mapfile +staging_vespalib_process_memory_stats_test_app diff --git a/staging_vespalib/src/tests/util/process_memory_stats/CMakeLists.txt b/staging_vespalib/src/tests/util/process_memory_stats/CMakeLists.txt new file mode 100644 index 00000000000..a9c23944575 --- /dev/null +++ b/staging_vespalib/src/tests/util/process_memory_stats/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(staging_vespalib_process_memory_stats_test_app + SOURCES + process_memory_stats_test.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_process_memory_stats_test_app COMMAND sh process_memory_stats_test.sh) diff --git a/staging_vespalib/src/tests/util/process_memory_stats/DESC b/staging_vespalib/src/tests/util/process_memory_stats/DESC new file mode 100644 index 00000000000..3f2b5fb571e --- /dev/null +++ b/staging_vespalib/src/tests/util/process_memory_stats/DESC @@ -0,0 +1 @@ +ProcessMemoryStats test. Take a look at process_memory_stats_test.cpp for details. diff --git a/staging_vespalib/src/tests/util/process_memory_stats/FILES b/staging_vespalib/src/tests/util/process_memory_stats/FILES new file mode 100644 index 00000000000..18ccce970a4 --- /dev/null +++ b/staging_vespalib/src/tests/util/process_memory_stats/FILES @@ -0,0 +1 @@ +process_memory_stats_test.cpp diff --git a/staging_vespalib/src/tests/util/process_memory_stats/process_memory_stats_test.cpp b/staging_vespalib/src/tests/util/process_memory_stats/process_memory_stats_test.cpp new file mode 100644 index 00000000000..43288d630cf --- /dev/null +++ b/staging_vespalib/src/tests/util/process_memory_stats/process_memory_stats_test.cpp @@ -0,0 +1,79 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include <vespa/fastos/fastos.h> +#include <vespa/vespalib/testkit/test_kit.h> +#include <vespa/vespalib/util/process_memory_stats.h> +#include <iostream> +#include <fstream> + + +using namespace vespalib; + +namespace { + +std::string toString(const ProcessMemoryStats &stats) +{ + std::ostringstream os; + os << "Mapped(" + << stats.getMappedVirt() << "," << stats.getMappedRss() << + "), Anonymous(" + << stats.getAnonymousVirt() << "," << stats.getAnonymousRss() << ")"; + return os.str(); +} + +} + +TEST("Simple stats") +{ + ProcessMemoryStats stats(ProcessMemoryStats::create()); + std::cout << toString(stats) << std::endl; + EXPECT_LESS(0u, stats.getMappedVirt()); + EXPECT_LESS(0u, stats.getMappedRss()); + EXPECT_LESS(0u, stats.getAnonymousVirt()); + EXPECT_LESS(0u, stats.getAnonymousRss()); +} + +TEST("grow anonymous memory") +{ + ProcessMemoryStats stats1(ProcessMemoryStats::create()); + std::cout << toString(stats1) << std::endl; + size_t mapLen = 64 * 1024; + void *mapAddr = mmap(nullptr, mapLen, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + EXPECT_NOT_EQUAL(reinterpret_cast<void *>(-1), mapAddr); + ProcessMemoryStats stats2(ProcessMemoryStats::create()); + std::cout << toString(stats2) << std::endl; + EXPECT_LESS_EQUAL(stats1.getAnonymousVirt() + mapLen, + stats2.getAnonymousVirt()); + memset(mapAddr, 1, mapLen); + ProcessMemoryStats stats3(ProcessMemoryStats::create()); + std::cout << toString(stats3) << std::endl; + // Cannot check that resident grows if swap is enabled and system loaded + munmap(mapAddr, mapLen); +} + +TEST("grow mapped memory") +{ + std::ofstream of("mapfile"); + size_t mapLen = 64 * 1024; + std::vector<char> buf(mapLen, 4); + of.write(&buf[0], buf.size()); + of.close(); + int mapfileFileDescriptor = open("mapfile", O_RDONLY, 0666); + EXPECT_LESS_EQUAL(0, mapfileFileDescriptor); + ProcessMemoryStats stats1(ProcessMemoryStats::create()); + std::cout << toString(stats1) << std::endl; + void *mapAddr = mmap(nullptr, mapLen, PROT_READ, MAP_SHARED, + mapfileFileDescriptor, 0); + EXPECT_NOT_EQUAL(reinterpret_cast<void *>(-1), mapAddr); + ProcessMemoryStats stats2(ProcessMemoryStats::create()); + std::cout << toString(stats2) << std::endl; + EXPECT_LESS_EQUAL(stats1.getMappedVirt() + mapLen, stats2.getMappedVirt()); + EXPECT_EQUAL(0, memcmp(mapAddr, &buf[0], mapLen)); + ProcessMemoryStats stats3(ProcessMemoryStats::create()); + std::cout << toString(stats3) << std::endl; + // Cannot check that resident grows if swap is enabled and system loaded + munmap(mapAddr, mapLen); +} + +TEST_MAIN() { TEST_RUN_ALL(); } diff --git a/staging_vespalib/src/tests/util/process_memory_stats/process_memory_stats_test.sh b/staging_vespalib/src/tests/util/process_memory_stats/process_memory_stats_test.sh new file mode 100755 index 00000000000..57b6c8cb613 --- /dev/null +++ b/staging_vespalib/src/tests/util/process_memory_stats/process_memory_stats_test.sh @@ -0,0 +1,4 @@ +#!/bin/sh +rm -f mapfile +$VALGRIND ./staging_vespalib_process_memory_stats_test_app +rm -f mapfile diff --git a/staging_vespalib/src/tests/xmlserializable/.gitignore b/staging_vespalib/src/tests/xmlserializable/.gitignore new file mode 100644 index 00000000000..d2910cb7407 --- /dev/null +++ b/staging_vespalib/src/tests/xmlserializable/.gitignore @@ -0,0 +1,4 @@ +*_test +.depend +Makefile +staging_vespalib_xmlserializable_test_app diff --git a/staging_vespalib/src/tests/xmlserializable/CMakeLists.txt b/staging_vespalib/src/tests/xmlserializable/CMakeLists.txt new file mode 100644 index 00000000000..9d351cec4d9 --- /dev/null +++ b/staging_vespalib/src/tests/xmlserializable/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(staging_vespalib_xmlserializable_test_app + SOURCES + xmlserializabletest.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_xmlserializable_test_app COMMAND staging_vespalib_xmlserializable_test_app) diff --git a/staging_vespalib/src/tests/xmlserializable/DESC b/staging_vespalib/src/tests/xmlserializable/DESC new file mode 100644 index 00000000000..7768b3e7b6d --- /dev/null +++ b/staging_vespalib/src/tests/xmlserializable/DESC @@ -0,0 +1 @@ +xmlserializable test. Take a look at xmlserializabletest.cpp for details. diff --git a/staging_vespalib/src/tests/xmlserializable/FILES b/staging_vespalib/src/tests/xmlserializable/FILES new file mode 100644 index 00000000000..e7c7d2397b7 --- /dev/null +++ b/staging_vespalib/src/tests/xmlserializable/FILES @@ -0,0 +1 @@ +xmlserializabletest.cpp diff --git a/staging_vespalib/src/tests/xmlserializable/xmlserializabletest.cpp b/staging_vespalib/src/tests/xmlserializable/xmlserializabletest.cpp new file mode 100644 index 00000000000..a44802735eb --- /dev/null +++ b/staging_vespalib/src/tests/xmlserializable/xmlserializabletest.cpp @@ -0,0 +1,165 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include <vespa/fastos/fastos.h> +#include <vespa/vespalib/util/xmlserializable.h> + +#include <vespa/vespalib/testkit/testapp.h> + +namespace vespalib { + +class Test : public vespalib::TestApp +{ +public: + void testNormalUsage(); + void testEscaping(); + void testNesting(); + void testIndent(); + + int Main(); +}; + +int +Test::Main() +{ + TEST_INIT("xmlserializables_test"); + srandom(1); + testNormalUsage(); + testEscaping(); + testNesting(); + testIndent(); + TEST_DONE(); +} + +void +Test::testNormalUsage() +{ + std::ostringstream ost; + XmlOutputStream xos(ost); + using namespace vespalib::xml; + xos << XmlTag("car") + << XmlTag("door") + << XmlAttribute("windowstate", "up") + << XmlEndTag() + << XmlTag("description") + << "This is a car description used to test" + << XmlEndTag() + << XmlEndTag(); + std::string expected = + "\n<car>\n" + "<door windowstate=\"up\"/>\n" + "<description>This is a car description used to test</description>\n" + "</car>"; + EXPECT_EQUAL(expected, "\n" + ost.str()); +} + +void +Test::testEscaping() +{ + std::ostringstream ost; + XmlOutputStream xos(ost); + using namespace vespalib::xml; + xos << XmlTag("!#trash%-", CONVERT_ILLEGAL_CHARACTERS) + << XmlTag("foo") + << XmlAttribute("bar", "<100%\" &\n>") + << XmlEndTag() + << XmlTag("escaped") + << XmlEscapedContent() + << XmlContentWrapper("<>&\"'% \r\n\t\f\0", 12) + << XmlEndTag() + << XmlTag("encoded") + << XmlBase64Content() + << XmlContentWrapper("<>&\"'% \t\f\0", 10) + << XmlEndTag() + << XmlTag("auto1") + << XmlContentWrapper("<>&\t\f\r\nfoo", 10) + << XmlEndTag() + << XmlTag("auto2") + << XmlContentWrapper("<>&\t\0\r\nfoo", 10) + << XmlEndTag() + << XmlEndTag(); + std::string expected = + "\n<__trash_->\n" + "<foo bar=\"<100%" & >\"/>\n" + "<escaped><>&\"'% \n	�</escaped>\n" + "<encoded binaryencoding=\"base64\">PD4mIiclIAkMAA==</encoded>\n" + "<auto1><>&	 \nfoo</auto1>\n" + "<auto2 binaryencoding=\"base64\">PD4mCQANCmZvbw==</auto2>\n" + "</__trash_->"; + EXPECT_EQUAL(expected, "\n" + ost.str()); +} + +namespace { + struct LookAndFeel : public XmlSerializable { + + LookAndFeel() {} + + void printXml(XmlOutputStream& out) const { + using namespace vespalib::xml; + out << XmlAttribute("color", "blue") + << XmlTag("other") + << XmlAttribute("count", 5) + << XmlTag("something") << "foo" << XmlEndTag() + << XmlTag("else") << "bar" << XmlEndTag() + << XmlEndTag(); + } + }; +} + +void +Test::testNesting() +{ + std::ostringstream ost; + XmlOutputStream xos(ost); + using namespace vespalib::xml; + xos << XmlTag("car") + << XmlTag("door") + << LookAndFeel() + << XmlEndTag() + << XmlTag("description") + << "This is a car description used to test" + << XmlEndTag() + << XmlEndTag(); + std::string expected = + "\n<car>\n" + "<door color=\"blue\">\n" + "<other count=\"5\">\n" + "<something>foo</something>\n" + "<else>bar</else>\n" + "</other>\n" + "</door>\n" + "<description>This is a car description used to test</description>\n" + "</car>"; + EXPECT_EQUAL(expected, "\n" + ost.str()); +} + +void +Test::testIndent() +{ + std::ostringstream ost; + XmlOutputStream xos(ost, " "); + using namespace vespalib::xml; + xos << XmlTag("foo") + << XmlTag("bar") << 2.14 << XmlEndTag() + << "Litt innhold" + << XmlTag("nytag") + << "Mer innhold" + << XmlTag("base") + << XmlBase64Content() << "foobar" + << XmlEndTag() + << XmlEndTag() + << XmlEndTag(); + std::string expected = "\n" + "<foo>\n" + " <bar>2.14</bar>\n" + " Litt innhold\n" + " <nytag>\n" + " Mer innhold\n" + " <base binaryencoding=\"base64\">Zm9vYmFy</base>\n" + " </nytag>\n" + "</foo>"; + EXPECT_EQUAL(expected, "\n" + ost.str()); +} + +} // vespalib + +TEST_APPHOOK(vespalib::Test) |