aboutsummaryrefslogtreecommitdiffstats
path: root/searchcore/src/tests/proton/reprocessing
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@yahoo-inc.com>2016-06-15 23:09:44 +0200
committerJon Bratseth <bratseth@yahoo-inc.com>2016-06-15 23:09:44 +0200
commit72231250ed81e10d66bfe70701e64fa5fe50f712 (patch)
tree2728bba1131a6f6e5bdf95afec7d7ff9358dac50 /searchcore/src/tests/proton/reprocessing
Publish
Diffstat (limited to 'searchcore/src/tests/proton/reprocessing')
-rw-r--r--searchcore/src/tests/proton/reprocessing/attribute_reprocessing_initializer/.gitignore1
-rw-r--r--searchcore/src/tests/proton/reprocessing/attribute_reprocessing_initializer/CMakeLists.txt10
-rw-r--r--searchcore/src/tests/proton/reprocessing/attribute_reprocessing_initializer/DESC2
-rw-r--r--searchcore/src/tests/proton/reprocessing/attribute_reprocessing_initializer/FILES1
-rw-r--r--searchcore/src/tests/proton/reprocessing/attribute_reprocessing_initializer/attribute_reprocessing_initializer_test.cpp247
-rw-r--r--searchcore/src/tests/proton/reprocessing/document_reprocessing_handler/.gitignore1
-rw-r--r--searchcore/src/tests/proton/reprocessing/document_reprocessing_handler/CMakeLists.txt8
-rw-r--r--searchcore/src/tests/proton/reprocessing/document_reprocessing_handler/DESC2
-rw-r--r--searchcore/src/tests/proton/reprocessing/document_reprocessing_handler/FILES1
-rw-r--r--searchcore/src/tests/proton/reprocessing/document_reprocessing_handler/document_reprocessing_handler_test.cpp124
-rw-r--r--searchcore/src/tests/proton/reprocessing/reprocessing_runner/.gitignore1
-rw-r--r--searchcore/src/tests/proton/reprocessing/reprocessing_runner/CMakeLists.txt8
-rw-r--r--searchcore/src/tests/proton/reprocessing/reprocessing_runner/DESC1
-rw-r--r--searchcore/src/tests/proton/reprocessing/reprocessing_runner/FILES1
-rw-r--r--searchcore/src/tests/proton/reprocessing/reprocessing_runner/reprocessing_runner_test.cpp141
15 files changed, 549 insertions, 0 deletions
diff --git a/searchcore/src/tests/proton/reprocessing/attribute_reprocessing_initializer/.gitignore b/searchcore/src/tests/proton/reprocessing/attribute_reprocessing_initializer/.gitignore
new file mode 100644
index 00000000000..5d662ccaf21
--- /dev/null
+++ b/searchcore/src/tests/proton/reprocessing/attribute_reprocessing_initializer/.gitignore
@@ -0,0 +1 @@
+searchcore_attribute_reprocessing_initializer_test_app
diff --git a/searchcore/src/tests/proton/reprocessing/attribute_reprocessing_initializer/CMakeLists.txt b/searchcore/src/tests/proton/reprocessing/attribute_reprocessing_initializer/CMakeLists.txt
new file mode 100644
index 00000000000..5e17a1d6606
--- /dev/null
+++ b/searchcore/src/tests/proton/reprocessing/attribute_reprocessing_initializer/CMakeLists.txt
@@ -0,0 +1,10 @@
+# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(searchcore_attribute_reprocessing_initializer_test_app
+ SOURCES
+ attribute_reprocessing_initializer_test.cpp
+ DEPENDS
+ searchcore_reprocessing
+ searchcore_attribute
+ searchcore_pcommon
+)
+vespa_add_test(NAME searchcore_attribute_reprocessing_initializer_test_app COMMAND searchcore_attribute_reprocessing_initializer_test_app)
diff --git a/searchcore/src/tests/proton/reprocessing/attribute_reprocessing_initializer/DESC b/searchcore/src/tests/proton/reprocessing/attribute_reprocessing_initializer/DESC
new file mode 100644
index 00000000000..2ae1d0c8164
--- /dev/null
+++ b/searchcore/src/tests/proton/reprocessing/attribute_reprocessing_initializer/DESC
@@ -0,0 +1,2 @@
+Test for attribute reprocessing initializer. Take a look at attribute_reprocessing_initializer_test.cpp for details.
+
diff --git a/searchcore/src/tests/proton/reprocessing/attribute_reprocessing_initializer/FILES b/searchcore/src/tests/proton/reprocessing/attribute_reprocessing_initializer/FILES
new file mode 100644
index 00000000000..6c9084f176d
--- /dev/null
+++ b/searchcore/src/tests/proton/reprocessing/attribute_reprocessing_initializer/FILES
@@ -0,0 +1 @@
+attribute_reprocessing_initializer_test.cpp
diff --git a/searchcore/src/tests/proton/reprocessing/attribute_reprocessing_initializer/attribute_reprocessing_initializer_test.cpp b/searchcore/src/tests/proton/reprocessing/attribute_reprocessing_initializer/attribute_reprocessing_initializer_test.cpp
new file mode 100644
index 00000000000..4670719897a
--- /dev/null
+++ b/searchcore/src/tests/proton/reprocessing/attribute_reprocessing_initializer/attribute_reprocessing_initializer_test.cpp
@@ -0,0 +1,247 @@
+// 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("attribute_reprocessing_initializer_test");
+
+#include <vespa/searchcore/proton/attribute/attribute_populator.h>
+#include <vespa/searchcore/proton/attribute/attributemanager.h>
+#include <vespa/searchcore/proton/attribute/document_field_populator.h>
+#include <vespa/searchcore/proton/reprocessing/attribute_reprocessing_initializer.h>
+#include <vespa/searchcore/proton/reprocessing/i_reprocessing_handler.h>
+#include <vespa/searchcore/proton/test/attribute_utils.h>
+#include <vespa/searchcore/proton/test/directory_handler.h>
+#include <vespa/searchlib/index/dummyfileheadercontext.h>
+#include <vespa/vespalib/test/insertion_operators.h>
+#include <vespa/vespalib/testkit/testapp.h>
+#include <vespa/searchlib/common/foregroundtaskexecutor.h>
+
+using namespace proton;
+using namespace search;
+using namespace search::index;
+
+const vespalib::string TEST_DIR = "test_output";
+const SerialNum INIT_SERIAL_NUM = 10;
+typedef std::vector<vespalib::string> StringVector;
+typedef std::set<vespalib::string> StringSet;
+typedef AttributeReprocessingInitializer::Config ARIConfig;
+
+struct MyReprocessingHandler : public IReprocessingHandler
+{
+ IReprocessingReader::SP _reader;
+ std::vector<IReprocessingRewriter::SP> _rewriters;
+ MyReprocessingHandler() : _reader(), _rewriters() {}
+ virtual void addReader(const IReprocessingReader::SP &reader) {
+ _reader = reader;
+ }
+ virtual void addRewriter(const IReprocessingRewriter::SP &rewriter) {
+ _rewriters.push_back(rewriter);
+ }
+};
+
+struct MyDocTypeInspector : public IDocumentTypeInspector
+{
+ typedef std::shared_ptr<MyDocTypeInspector> SP;
+ std::set<vespalib::string> _fields;
+ MyDocTypeInspector() : _fields() {}
+ virtual bool hasField(const vespalib::string &name) const {
+ return _fields.count(name) > 0;
+ }
+};
+
+struct MyConfig
+{
+ DummyFileHeaderContext _fileHeaderContext;
+ ForegroundTaskExecutor _attributeFieldWriter;
+ AttributeManager::SP _mgr;
+ search::index::Schema _schema;
+ MyDocTypeInspector::SP _inspector;
+ MyConfig()
+ : _fileHeaderContext(),
+ _attributeFieldWriter(),
+ _mgr(new AttributeManager(TEST_DIR, "test.subdb", TuneFileAttributes(),
+ _fileHeaderContext,
+ _attributeFieldWriter)),
+ _schema(),
+ _inspector(new MyDocTypeInspector())
+ {
+ }
+ void addFields(const StringVector &fields) {
+ for (auto field : fields) {
+ _inspector->_fields.insert(field);
+ }
+ }
+ void addAttrs(const StringVector &attrs) {
+ for (auto attr : attrs) {
+ if (attr == "tensor") {
+ _mgr->addAttribute(attr, test::AttributeUtils::getTensorConfig(), 1);
+ _schema.addAttributeField(Schema::AttributeField(attr, Schema::TENSOR));
+ } else if (attr == "predicate") {
+ _mgr->addAttribute(attr, test::AttributeUtils::getPredicateConfig(), 1);
+ _schema.addAttributeField(Schema::AttributeField(attr, Schema::BOOLEANTREE));
+ } else {
+ _mgr->addAttribute(attr, test::AttributeUtils::getStringConfig(), 1);
+ _schema.addAttributeField(Schema::AttributeField(attr, Schema::STRING));
+ }
+ }
+ }
+ void addIndexField(const vespalib::string &name) {
+ _schema.addIndexField(Schema::IndexField(name, Schema::STRING));
+ }
+};
+
+struct Fixture
+{
+ test::DirectoryHandler _dirHandler;
+ DummyFileHeaderContext _fileHeaderContext;
+ ForegroundTaskExecutor _attributeFieldWriter;
+ AttributeManager::SP _mgr;
+ MyConfig _oldCfg;
+ MyConfig _newCfg;
+ AttributeReprocessingInitializer::UP _initializer;
+ MyReprocessingHandler _handler;
+ Fixture()
+ : _dirHandler(TEST_DIR),
+ _fileHeaderContext(),
+ _attributeFieldWriter(),
+ _mgr(new AttributeManager(TEST_DIR, "test.subdb", TuneFileAttributes(),
+ _fileHeaderContext,
+ _attributeFieldWriter)),
+ _initializer(),
+ _handler()
+ {
+ }
+ void init() {
+ _initializer.reset(new AttributeReprocessingInitializer
+ (ARIConfig(_newCfg._mgr, _newCfg._schema, _newCfg._inspector),
+ ARIConfig(_oldCfg._mgr, _oldCfg._schema, _oldCfg._inspector), "test"));
+ _initializer->initialize(_handler);
+ }
+ Fixture &addOldConfig(const StringVector &fields,
+ const StringVector &attrs) {
+ return addConfig(fields, attrs, _oldCfg);
+ }
+ Fixture &addNewConfig(const StringVector &fields,
+ const StringVector &attrs) {
+ return addConfig(fields, attrs, _newCfg);
+ }
+ Fixture &addConfig(const StringVector &fields,
+ const StringVector &attrs,
+ MyConfig &cfg) {
+ cfg.addFields(fields);
+ cfg.addAttrs(attrs);
+ return *this;
+ }
+ bool assertAttributes(const StringSet &expAttrs) {
+ if (expAttrs.empty()) {
+ if (!EXPECT_TRUE(_handler._reader.get() == nullptr)) return false;
+ } else {
+ const AttributePopulator &populator =
+ dynamic_cast<const AttributePopulator &>(*_handler._reader);
+ std::vector<search::AttributeVector *> attrList =
+ populator.getWriter().getWritableAttributes();
+ std::set<vespalib::string> actAttrs;
+ for (const auto attr : attrList) {
+ actAttrs.insert(attr->getName());
+ }
+ if (!EXPECT_EQUAL(expAttrs, actAttrs)) return false;
+ }
+ return true;
+ }
+ bool assertFields(const StringSet &expFields) {
+ if (expFields.empty()) {
+ if (!EXPECT_EQUAL(0u, _handler._rewriters.size())) return false;
+ } else {
+ StringSet actFields;
+ for (auto rewriter : _handler._rewriters) {
+ const DocumentFieldPopulator &populator =
+ dynamic_cast<const DocumentFieldPopulator &>(*rewriter);
+ actFields.insert(populator.getAttribute().getName());
+ }
+ if (!EXPECT_EQUAL(expFields, actFields)) return false;
+ }
+ return true;
+ }
+};
+
+TEST_F("require that new field does NOT require attribute populate", Fixture)
+{
+ f.addOldConfig({}, {}).addNewConfig({"a"}, {"a"}).init();
+ EXPECT_TRUE(f.assertAttributes({}));
+}
+
+TEST_F("require that added attribute aspect does require attribute populate", Fixture)
+{
+ f.addOldConfig({"a"}, {}).addNewConfig({"a"}, {"a"}).init();
+ EXPECT_TRUE(f.assertAttributes({"a"}));
+}
+
+TEST_F("require that initializer can setup populate of several attributes", Fixture)
+{
+ f.addOldConfig({"a", "b", "c", "d"}, {"a", "b"}).
+ addNewConfig({"a", "b", "c", "d"}, {"a", "b", "c", "d"}).init();
+ EXPECT_TRUE(f.assertAttributes({"c", "d"}));
+}
+
+TEST_F("require that new field does NOT require document field populate", Fixture)
+{
+ f.addOldConfig({}, {}).addNewConfig({"a"}, {"a"}).init();
+ EXPECT_TRUE(f.assertFields({}));
+}
+
+TEST_F("require that removed field does NOT require document field populate", Fixture)
+{
+ f.addOldConfig({"a"}, {"a"}).addNewConfig({}, {}).init();
+ EXPECT_TRUE(f.assertFields({}));
+}
+
+TEST_F("require that removed attribute aspect does require document field populate", Fixture)
+{
+ f.addOldConfig({"a"}, {"a"}).addNewConfig({"a"}, {}).init();
+ EXPECT_TRUE(f.assertFields({"a"}));
+}
+
+TEST_F("require that removed attribute aspect (when also index field) does NOT require document field populate",
+ Fixture)
+{
+ f.addOldConfig({"a"}, {"a"}).addNewConfig({"a"}, {});
+ f._oldCfg.addIndexField("a");
+ f._newCfg.addIndexField("a");
+ f.init();
+ EXPECT_TRUE(f.assertFields({}));
+}
+
+TEST_F("require that initializer can setup populate of several document fields", Fixture)
+{
+ f.addOldConfig({"a", "b", "c", "d"}, {"a", "b", "c", "d"}).
+ addNewConfig({"a", "b", "c", "d"}, {"a", "b"}).init();
+ EXPECT_TRUE(f.assertFields({"c", "d"}));
+}
+
+TEST_F("require that initializer can setup both attribute and document field populate", Fixture)
+{
+ f.addOldConfig({"a", "b"}, {"a"}).
+ addNewConfig({"a", "b"}, {"b"}).init();
+ EXPECT_TRUE(f.assertAttributes({"b"}));
+ EXPECT_TRUE(f.assertFields({"a"}));
+}
+
+TEST_F("require that tensor fields are not populated from attribute", Fixture)
+{
+ f.addOldConfig({"a", "b", "c", "d", "tensor"},
+ {"a", "b", "c", "d", "tensor"}).
+ addNewConfig({"a", "b", "c", "d", "tensor"}, {"a", "b"}).init();
+ EXPECT_TRUE(f.assertFields({"c", "d"}));
+}
+
+TEST_F("require that predicate fields are not populated from attribute", Fixture)
+{
+ f.addOldConfig({"a", "b", "c", "d", "predicate"},
+ {"a", "b", "c", "d", "predicate"}).
+ addNewConfig({"a", "b", "c", "d", "predicate"}, {"a", "b"}).init();
+ EXPECT_TRUE(f.assertFields({"c", "d"}));
+}
+
+TEST_MAIN()
+{
+ TEST_RUN_ALL();
+}
diff --git a/searchcore/src/tests/proton/reprocessing/document_reprocessing_handler/.gitignore b/searchcore/src/tests/proton/reprocessing/document_reprocessing_handler/.gitignore
new file mode 100644
index 00000000000..50e203b78e8
--- /dev/null
+++ b/searchcore/src/tests/proton/reprocessing/document_reprocessing_handler/.gitignore
@@ -0,0 +1 @@
+searchcore_document_reprocessing_handler_test_app
diff --git a/searchcore/src/tests/proton/reprocessing/document_reprocessing_handler/CMakeLists.txt b/searchcore/src/tests/proton/reprocessing/document_reprocessing_handler/CMakeLists.txt
new file mode 100644
index 00000000000..170e381c99c
--- /dev/null
+++ b/searchcore/src/tests/proton/reprocessing/document_reprocessing_handler/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(searchcore_document_reprocessing_handler_test_app
+ SOURCES
+ document_reprocessing_handler_test.cpp
+ DEPENDS
+ searchcore_reprocessing
+)
+vespa_add_test(NAME searchcore_document_reprocessing_handler_test_app COMMAND searchcore_document_reprocessing_handler_test_app)
diff --git a/searchcore/src/tests/proton/reprocessing/document_reprocessing_handler/DESC b/searchcore/src/tests/proton/reprocessing/document_reprocessing_handler/DESC
new file mode 100644
index 00000000000..663b2304d37
--- /dev/null
+++ b/searchcore/src/tests/proton/reprocessing/document_reprocessing_handler/DESC
@@ -0,0 +1,2 @@
+Test for document reprocessing handler. Take a look at document_reprocessing_handler_test.cpp for details.
+
diff --git a/searchcore/src/tests/proton/reprocessing/document_reprocessing_handler/FILES b/searchcore/src/tests/proton/reprocessing/document_reprocessing_handler/FILES
new file mode 100644
index 00000000000..2301fc01844
--- /dev/null
+++ b/searchcore/src/tests/proton/reprocessing/document_reprocessing_handler/FILES
@@ -0,0 +1 @@
+document_reprocessing_handler_test.cpp
diff --git a/searchcore/src/tests/proton/reprocessing/document_reprocessing_handler/document_reprocessing_handler_test.cpp b/searchcore/src/tests/proton/reprocessing/document_reprocessing_handler/document_reprocessing_handler_test.cpp
new file mode 100644
index 00000000000..f22762a56bb
--- /dev/null
+++ b/searchcore/src/tests/proton/reprocessing/document_reprocessing_handler/document_reprocessing_handler_test.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/log/log.h>
+LOG_SETUP("document_reprocessing_handler_test");
+
+#include <vespa/searchcore/proton/reprocessing/document_reprocessing_handler.h>
+#include <vespa/searchlib/index/docbuilder.h>
+#include <vespa/vespalib/testkit/testapp.h>
+
+using namespace document;
+using namespace proton;
+using namespace search::index;
+
+template <typename ReprocessingType, typename DocumentType>
+struct MyProcessor : public ReprocessingType
+{
+ typedef std::shared_ptr<MyProcessor<ReprocessingType, DocumentType> > SP;
+ uint32_t _lid;
+ DocumentId _docId;
+
+ MyProcessor() : _lid(0), _docId() {}
+ virtual void handleExisting(uint32_t lid, DocumentType doc) {
+ _lid = lid;
+ _docId = doc.getId();
+ }
+};
+
+typedef MyProcessor<IReprocessingReader, const Document &> MyReader;
+typedef MyProcessor<IReprocessingRewriter, Document &> MyRewriter;
+
+const vespalib::string DOC_ID = "id:test:searchdocument::0";
+
+struct FixtureBase
+{
+ DocumentReprocessingHandler _handler;
+ DocBuilder _docBuilder;
+ FixtureBase(uint32_t docIdLimit)
+ : _handler(docIdLimit),
+ _docBuilder(Schema())
+ {
+ }
+ Document::UP createDoc() {
+ return _docBuilder.startDocument(DOC_ID).endDocument();
+ }
+};
+
+struct ReaderFixture : public FixtureBase
+{
+ MyReader::SP _reader1;
+ MyReader::SP _reader2;
+ ReaderFixture()
+ : ReaderFixture(std::numeric_limits<uint32_t>::max())
+ {
+ }
+ ReaderFixture(uint32_t docIdLimit)
+ : FixtureBase(docIdLimit),
+ _reader1(new MyReader()),
+ _reader2(new MyReader())
+ {
+ _handler.addReader(_reader1);
+ _handler.addReader(_reader2);
+ }
+};
+
+struct RewriterFixture : public FixtureBase
+{
+ MyRewriter::SP _rewriter1;
+ MyRewriter::SP _rewriter2;
+ RewriterFixture()
+ : RewriterFixture(std::numeric_limits<uint32_t>::max())
+ {
+ }
+ RewriterFixture(uint32_t docIdLimit)
+ : FixtureBase(docIdLimit),
+ _rewriter1(new MyRewriter()),
+ _rewriter2(new MyRewriter())
+ {
+ _handler.addRewriter(_rewriter1);
+ _handler.addRewriter(_rewriter2);
+ }
+};
+
+TEST_F("require that handler propagates visit of existing document to readers", ReaderFixture)
+{
+ f._handler.visit(23u, *f.createDoc());
+ EXPECT_EQUAL(23u, f._reader1->_lid);
+ EXPECT_EQUAL(DOC_ID, f._reader1->_docId.toString());
+ EXPECT_EQUAL(23u, f._reader2->_lid);
+ EXPECT_EQUAL(DOC_ID, f._reader2->_docId.toString());
+}
+
+TEST_F("require that handler propagates visit of existing document to rewriters", RewriterFixture)
+{
+ f._handler.getRewriteVisitor().visit(23u, *f.createDoc());
+ EXPECT_EQUAL(23u, f._rewriter1->_lid);
+ EXPECT_EQUAL(DOC_ID, f._rewriter1->_docId.toString());
+ EXPECT_EQUAL(23u, f._rewriter2->_lid);
+ EXPECT_EQUAL(DOC_ID, f._rewriter2->_docId.toString());
+}
+
+TEST_F("require that handler skips out of range visit to readers",
+ ReaderFixture(10))
+{
+ f._handler.visit(23u, *f.createDoc());
+ EXPECT_EQUAL(0u, f._reader1->_lid);
+ EXPECT_EQUAL(DocumentId().toString(), f._reader1->_docId.toString());
+ EXPECT_EQUAL(0u, f._reader2->_lid);
+ EXPECT_EQUAL(DocumentId().toString(), f._reader2->_docId.toString());
+}
+
+TEST_F("require that handler skips out of range visit to rewriters",
+ RewriterFixture(10))
+{
+ f._handler.getRewriteVisitor().visit(23u, *f.createDoc());
+ EXPECT_EQUAL(0u, f._rewriter1->_lid);
+ EXPECT_EQUAL(DocumentId().toString(), f._rewriter1->_docId.toString());
+ EXPECT_EQUAL(0u, f._rewriter2->_lid);
+ EXPECT_EQUAL(DocumentId().toString(), f._rewriter2->_docId.toString());
+}
+
+TEST_MAIN()
+{
+ TEST_RUN_ALL();
+}
diff --git a/searchcore/src/tests/proton/reprocessing/reprocessing_runner/.gitignore b/searchcore/src/tests/proton/reprocessing/reprocessing_runner/.gitignore
new file mode 100644
index 00000000000..ecb260d2c0e
--- /dev/null
+++ b/searchcore/src/tests/proton/reprocessing/reprocessing_runner/.gitignore
@@ -0,0 +1 @@
+searchcore_reprocessing_runner_test_app
diff --git a/searchcore/src/tests/proton/reprocessing/reprocessing_runner/CMakeLists.txt b/searchcore/src/tests/proton/reprocessing/reprocessing_runner/CMakeLists.txt
new file mode 100644
index 00000000000..f5eff73f9f0
--- /dev/null
+++ b/searchcore/src/tests/proton/reprocessing/reprocessing_runner/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(searchcore_reprocessing_runner_test_app
+ SOURCES
+ reprocessing_runner_test.cpp
+ DEPENDS
+ searchcore_reprocessing
+)
+vespa_add_test(NAME searchcore_reprocessing_runner_test_app COMMAND searchcore_reprocessing_runner_test_app)
diff --git a/searchcore/src/tests/proton/reprocessing/reprocessing_runner/DESC b/searchcore/src/tests/proton/reprocessing/reprocessing_runner/DESC
new file mode 100644
index 00000000000..ffa0db7ae9e
--- /dev/null
+++ b/searchcore/src/tests/proton/reprocessing/reprocessing_runner/DESC
@@ -0,0 +1 @@
+Test reprocessing runner.
diff --git a/searchcore/src/tests/proton/reprocessing/reprocessing_runner/FILES b/searchcore/src/tests/proton/reprocessing/reprocessing_runner/FILES
new file mode 100644
index 00000000000..091769d58cb
--- /dev/null
+++ b/searchcore/src/tests/proton/reprocessing/reprocessing_runner/FILES
@@ -0,0 +1 @@
+reprocessing_runner_test.cpp
diff --git a/searchcore/src/tests/proton/reprocessing/reprocessing_runner/reprocessing_runner_test.cpp b/searchcore/src/tests/proton/reprocessing/reprocessing_runner/reprocessing_runner_test.cpp
new file mode 100644
index 00000000000..c4c462ecfa1
--- /dev/null
+++ b/searchcore/src/tests/proton/reprocessing/reprocessing_runner/reprocessing_runner_test.cpp
@@ -0,0 +1,141 @@
+// 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("reprocessing_runner_test");
+
+#include <vespa/searchcore/proton/reprocessing/i_reprocessing_task.h>
+#include <vespa/searchcore/proton/reprocessing/reprocessingrunner.h>
+#include <vespa/vespalib/testkit/testapp.h>
+
+using namespace proton;
+
+struct Fixture
+{
+ ReprocessingRunner _runner;
+ Fixture()
+ : _runner()
+ {
+ }
+};
+
+typedef ReprocessingRunner::ReprocessingTasks TaskList;
+
+struct MyTask : public IReprocessingTask
+{
+ ReprocessingRunner &_runner;
+ double _initProgress;
+ double _middleProgress;
+ double _finalProgress;
+ double _myProgress;
+ double _weight;
+
+ MyTask(ReprocessingRunner &runner,
+ double initProgress,
+ double middleProgress,
+ double finalProgress,
+ double weight)
+ : _runner(runner),
+ _initProgress(initProgress),
+ _middleProgress(middleProgress),
+ _finalProgress(finalProgress),
+ _myProgress(0.0),
+ _weight(weight)
+ {
+ }
+
+ virtual void
+ run()
+ {
+ ASSERT_EQUAL(_initProgress, _runner.getProgress());
+ _myProgress = 0.5;
+ ASSERT_EQUAL(_middleProgress, _runner.getProgress());
+ _myProgress = 1.0;
+ ASSERT_EQUAL(_finalProgress, _runner.getProgress());
+ }
+
+ virtual Progress
+ getProgress(void) const
+ {
+ return Progress(_myProgress, _weight);
+ }
+
+ static std::shared_ptr<MyTask>
+ create(ReprocessingRunner &runner,
+ double initProgress,
+ double middleProgress,
+ double finalProgress,
+ double weight)
+ {
+ return std::make_shared<MyTask>(runner,
+ initProgress,
+ middleProgress,
+ finalProgress,
+ weight);
+ }
+};
+
+TEST_F("require that progress is calculated when tasks are executed", Fixture)
+{
+ TaskList tasks;
+ EXPECT_EQUAL(0.0, f._runner.getProgress());
+ tasks.push_back(MyTask::create(f._runner,
+ 0.0,
+ 0.1,
+ 0.2,
+ 1.0));
+ tasks.push_back(MyTask::create(f._runner,
+ 0.2,
+ 0.6,
+ 1.0,
+ 4.0));
+ f._runner.addTasks(tasks);
+ tasks.clear();
+ EXPECT_EQUAL(0.0, f._runner.getProgress());
+ f._runner.run();
+ EXPECT_EQUAL(1.0, f._runner.getProgress());
+}
+
+
+TEST_F("require that runner can be reset", Fixture)
+{
+ TaskList tasks;
+ EXPECT_EQUAL(0.0, f._runner.getProgress());
+ tasks.push_back(MyTask::create(f._runner,
+ 0.0,
+ 0.5,
+ 1.0,
+ 1.0));
+ f._runner.addTasks(tasks);
+ tasks.clear();
+ EXPECT_EQUAL(0.0, f._runner.getProgress());
+ f._runner.run();
+ EXPECT_EQUAL(1.0, f._runner.getProgress());
+ f._runner.reset();
+ EXPECT_EQUAL(0.0, f._runner.getProgress());
+ tasks.push_back(MyTask::create(f._runner,
+ 0.0,
+ 0.5,
+ 1.0,
+ 1.0));
+ f._runner.addTasks(tasks);
+ tasks.clear();
+ EXPECT_EQUAL(0.0, f._runner.getProgress());
+ f._runner.reset();
+ EXPECT_EQUAL(0.0, f._runner.getProgress());
+ tasks.push_back(MyTask::create(f._runner,
+ 0.0,
+ 0.5,
+ 1.0,
+ 4.0));
+ f._runner.addTasks(tasks);
+ tasks.clear();
+ EXPECT_EQUAL(0.0, f._runner.getProgress());
+ f._runner.run();
+ EXPECT_EQUAL(1.0, f._runner.getProgress());
+}
+
+
+TEST_MAIN()
+{
+ TEST_RUN_ALL();
+}