aboutsummaryrefslogtreecommitdiffstats
path: root/searchcore/src/tests/proton/verify_ranksetup
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/verify_ranksetup
Publish
Diffstat (limited to 'searchcore/src/tests/proton/verify_ranksetup')
-rw-r--r--searchcore/src/tests/proton/verify_ranksetup/.cvsignore3
-rw-r--r--searchcore/src/tests/proton/verify_ranksetup/.gitignore5
-rw-r--r--searchcore/src/tests/proton/verify_ranksetup/CMakeLists.txt7
-rw-r--r--searchcore/src/tests/proton/verify_ranksetup/DESC1
-rw-r--r--searchcore/src/tests/proton/verify_ranksetup/FILES1
-rw-r--r--searchcore/src/tests/proton/verify_ranksetup/invalid_attr_name/.gitignore0
-rw-r--r--searchcore/src/tests/proton/verify_ranksetup/invalid_feature_name/.gitignore0
-rw-r--r--searchcore/src/tests/proton/verify_ranksetup/unsupported_collection_type/.gitignore0
-rw-r--r--searchcore/src/tests/proton/verify_ranksetup/valid/.gitignore0
-rw-r--r--searchcore/src/tests/proton/verify_ranksetup/verify_ranksetup_test.cpp250
-rwxr-xr-xsearchcore/src/tests/proton/verify_ranksetup/verify_ranksetup_test.sh4
11 files changed, 271 insertions, 0 deletions
diff --git a/searchcore/src/tests/proton/verify_ranksetup/.cvsignore b/searchcore/src/tests/proton/verify_ranksetup/.cvsignore
new file mode 100644
index 00000000000..a4848db32f8
--- /dev/null
+++ b/searchcore/src/tests/proton/verify_ranksetup/.cvsignore
@@ -0,0 +1,3 @@
+.depend
+Makefile
+verify_ranksetup_test
diff --git a/searchcore/src/tests/proton/verify_ranksetup/.gitignore b/searchcore/src/tests/proton/verify_ranksetup/.gitignore
new file mode 100644
index 00000000000..1142087d03d
--- /dev/null
+++ b/searchcore/src/tests/proton/verify_ranksetup/.gitignore
@@ -0,0 +1,5 @@
+*_test
+.depend
+Makefile
+generated
+searchcore_verify_ranksetup_test_app
diff --git a/searchcore/src/tests/proton/verify_ranksetup/CMakeLists.txt b/searchcore/src/tests/proton/verify_ranksetup/CMakeLists.txt
new file mode 100644
index 00000000000..2d74c323c1a
--- /dev/null
+++ b/searchcore/src/tests/proton/verify_ranksetup/CMakeLists.txt
@@ -0,0 +1,7 @@
+# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(searchcore_verify_ranksetup_test_app
+ SOURCES
+ verify_ranksetup_test.cpp
+ DEPENDS
+)
+vespa_add_test(NAME searchcore_verify_ranksetup_test_app COMMAND sh verify_ranksetup_test.sh)
diff --git a/searchcore/src/tests/proton/verify_ranksetup/DESC b/searchcore/src/tests/proton/verify_ranksetup/DESC
new file mode 100644
index 00000000000..700e2b1c2f9
--- /dev/null
+++ b/searchcore/src/tests/proton/verify_ranksetup/DESC
@@ -0,0 +1 @@
+verify_ranksetup test. Take a look at verify_ranksetup.cpp for details.
diff --git a/searchcore/src/tests/proton/verify_ranksetup/FILES b/searchcore/src/tests/proton/verify_ranksetup/FILES
new file mode 100644
index 00000000000..9c4a2ef3776
--- /dev/null
+++ b/searchcore/src/tests/proton/verify_ranksetup/FILES
@@ -0,0 +1 @@
+verify_ranksetup.cpp
diff --git a/searchcore/src/tests/proton/verify_ranksetup/invalid_attr_name/.gitignore b/searchcore/src/tests/proton/verify_ranksetup/invalid_attr_name/.gitignore
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/searchcore/src/tests/proton/verify_ranksetup/invalid_attr_name/.gitignore
diff --git a/searchcore/src/tests/proton/verify_ranksetup/invalid_feature_name/.gitignore b/searchcore/src/tests/proton/verify_ranksetup/invalid_feature_name/.gitignore
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/searchcore/src/tests/proton/verify_ranksetup/invalid_feature_name/.gitignore
diff --git a/searchcore/src/tests/proton/verify_ranksetup/unsupported_collection_type/.gitignore b/searchcore/src/tests/proton/verify_ranksetup/unsupported_collection_type/.gitignore
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/searchcore/src/tests/proton/verify_ranksetup/unsupported_collection_type/.gitignore
diff --git a/searchcore/src/tests/proton/verify_ranksetup/valid/.gitignore b/searchcore/src/tests/proton/verify_ranksetup/valid/.gitignore
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/searchcore/src/tests/proton/verify_ranksetup/valid/.gitignore
diff --git a/searchcore/src/tests/proton/verify_ranksetup/verify_ranksetup_test.cpp b/searchcore/src/tests/proton/verify_ranksetup/verify_ranksetup_test.cpp
new file mode 100644
index 00000000000..3db23380675
--- /dev/null
+++ b/searchcore/src/tests/proton/verify_ranksetup/verify_ranksetup_test.cpp
@@ -0,0 +1,250 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/vespalib/testkit/test_kit.h>
+#include <vespa/vespalib/util/slaveproc.h>
+#include <vespa/vespalib/util/stringfmt.h>
+#include <vespa/searchcommon/common/schema.h>
+#include <vespa/searchlib/fef/indexproperties.h>
+#include <string>
+#include <vector>
+#include <map>
+#include <initializer_list>
+
+const char *prog = "../../../apps/verify_ranksetup/verify_ranksetup-bin";
+const std::string gen_dir("generated");
+
+const char *valid_feature = "value(0)";
+const char *invalid_feature = "invalid_feature_name and format";
+
+using search::index::Schema;
+using namespace search::fef::indexproperties;
+
+struct Writer {
+ FILE *file;
+ Writer(const std::string &file_name) {
+ file = fopen(file_name.c_str(), "w");
+ ASSERT_TRUE(file != 0);
+ }
+ void fmt(const char *format, ...) const
+#ifdef __GNUC__
+ __attribute__ ((format (printf,2,3)))
+#endif
+ {
+ va_list ap;
+ va_start(ap, format);
+ vfprintf(file, format, ap);
+ va_end(ap);
+ }
+ ~Writer() { fclose(file); }
+};
+
+void verify_dir() {
+ std::string pwd(getenv("PWD"));
+ ASSERT_NOT_EQUAL(pwd.find("searchcore/src/tests/proton/verify_ranksetup"), pwd.npos);
+}
+
+//-----------------------------------------------------------------------------
+
+struct Model {
+ std::map<std::string,std::pair<std::string,std::string> > indexes;
+ std::map<std::string,std::pair<std::string,std::string> > attributes;
+ std::map<std::string,std::string> properties;
+ std::vector<bool> extra_profiles;
+ Model() : indexes(), attributes(), properties(), extra_profiles() {
+ verify_dir();
+ }
+ void index(const std::string &name, Schema::DataType data_type,
+ Schema::CollectionType collection_type)
+ {
+ indexes[name].first = Schema::getTypeName(data_type);
+ indexes[name].second = Schema::getTypeName(collection_type);
+ }
+ void attribute(const std::string &name, Schema::DataType data_type,
+ Schema::CollectionType collection_type)
+ {
+ attributes[name].first = Schema::getTypeName(data_type);
+ attributes[name].second = Schema::getTypeName(collection_type);
+ }
+ void property(const std::string &name, const std::string &val) {
+ properties[name] = val;
+ }
+ void first_phase(const std::string &feature) {
+ property(rank::FirstPhase::NAME, feature);
+ }
+ void second_phase(const std::string &feature) {
+ property(rank::SecondPhase::NAME, feature);
+ }
+ void summary_feature(const std::string &feature) {
+ property(summary::Feature::NAME, feature);
+ }
+ void dump_feature(const std::string &feature) {
+ property(dump::Feature::NAME, feature);
+ }
+ void good_profile() {
+ extra_profiles.push_back(true);
+ }
+ void bad_profile() {
+ extra_profiles.push_back(false);
+ }
+ void write_attributes(const Writer &out) {
+ out.fmt("attribute[%zu]\n", attributes.size());
+ std::map<std::string,std::pair<std::string,std::string> >::const_iterator pos = attributes.begin();
+ for (size_t i = 0; pos != attributes.end(); ++pos, ++i) {
+ out.fmt("attribute[%zu].name \"%s\"\n", i, pos->first.c_str());
+ out.fmt("attribute[%zu].datatype %s\n", i, pos->second.first.c_str());
+ out.fmt("attribute[%zu].collectiontype %s\n", i, pos->second.second.c_str());
+ }
+ }
+ void write_indexschema(const Writer &out) {
+ out.fmt("indexfield[%zu]\n", indexes.size());
+ std::map<std::string,std::pair<std::string,std::string> >::const_iterator pos = indexes.begin();
+ for (size_t i = 0; pos != indexes.end(); ++pos, ++i) {
+ out.fmt("indexfield[%zu].name \"%s\"\n", i, pos->first.c_str());
+ out.fmt("indexfield[%zu].datatype %s\n", i, pos->second.first.c_str());
+ out.fmt("indexfield[%zu].collectiontype %s\n", i, pos->second.second.c_str());
+ }
+ }
+ void write_rank_profiles(const Writer &out) {
+ out.fmt("rankprofile[%zu]\n", extra_profiles.size() + 1);
+ out.fmt("rankprofile[0].name \"default\"\n");
+ std::map<std::string,std::string>::const_iterator pos = properties.begin();
+ for (size_t i = 0; pos != properties.end(); ++pos, ++i) {
+ out.fmt("rankprofile[0].fef.property[%zu]\n", properties.size());
+ out.fmt("rankprofile[0].fef.property[%zu].name \"%s\"\n", i, pos->first.c_str());
+ out.fmt("rankprofile[0].fef.property[%zu].value \"%s\"\n", i, pos->second.c_str());
+ }
+ for (size_t i = 1; i < (extra_profiles.size() + 1); ++i) {
+ out.fmt("rankprofile[%zu].name \"extra_%zu\"\n", i, i);
+ out.fmt("rankprofile[%zu].fef.property[%zu].name \"%s\"\n", i, i, rank::FirstPhase::NAME.c_str());
+ out.fmt("rankprofile[%zu].fef.property[%zu].value \"%s\"\n", i, i, extra_profiles[i-1]?valid_feature:invalid_feature);
+ }
+ }
+ void generate() {
+ write_attributes(Writer(gen_dir + "/attributes.cfg"));
+ write_indexschema(Writer(gen_dir + "/indexschema.cfg"));
+ write_rank_profiles(Writer(gen_dir + "/rank-profiles.cfg"));
+ }
+ bool verify() {
+ generate();
+ return vespalib::SlaveProc::run(vespalib::make_string("%s dir:%s", prog, gen_dir.c_str()).c_str());
+ }
+ void verify_valid(std::initializer_list<std::string> features) {
+ for (const std::string &f: features) {
+ first_phase(f);
+ if (!EXPECT_TRUE(verify())) {
+ fprintf(stderr, "--> feature '%s' was invalid (should be valid)\n", f.c_str());
+ }
+ }
+ }
+ void verify_invalid(std::initializer_list<std::string> features) {
+ for (const std::string &f: features) {
+ first_phase(f);
+ if (!EXPECT_FALSE(verify())) {
+ fprintf(stderr, "--> feature '%s' was valid (should be invalid)\n", f.c_str());
+ }
+ }
+ }
+};
+
+//-----------------------------------------------------------------------------
+
+struct EmptyModel : Model {};
+
+struct SimpleModel : Model {
+ SimpleModel() : Model() {
+ index("title", Schema::STRING, Schema::SINGLE);
+ index("list", Schema::STRING, Schema::ARRAY);
+ index("keywords", Schema::STRING, Schema::WEIGHTEDSET);
+ attribute("date", Schema::INT32, Schema::SINGLE);
+ }
+};
+
+struct ShadowModel : Model {
+ ShadowModel() : Model() {
+ index("both", Schema::STRING, Schema::SINGLE);
+ attribute("both", Schema::STRING, Schema::SINGLE);
+ }
+};
+
+TEST_F("print usage", Model()) {
+ EXPECT_FALSE(vespalib::SlaveProc::run(vespalib::make_string("%s", prog).c_str()));
+}
+
+TEST_F("setup output directory", Model()) {
+ ASSERT_TRUE(vespalib::SlaveProc::run(vespalib::make_string("rm -rf %s", gen_dir.c_str()).c_str()));
+ ASSERT_TRUE(vespalib::SlaveProc::run(vespalib::make_string("mkdir %s", gen_dir.c_str()).c_str()));
+}
+
+//-----------------------------------------------------------------------------
+
+TEST_F("require that empty setup passes validation", EmptyModel()) {
+ EXPECT_TRUE(f.verify());
+}
+
+TEST_F("require that we can verify multiple rank profiles", SimpleModel()) {
+ f.first_phase(valid_feature);
+ f.good_profile();
+ EXPECT_TRUE(f.verify());
+ f.bad_profile();
+ EXPECT_FALSE(f.verify());
+}
+
+TEST_F("require that first phase can break validation", SimpleModel()) {
+ f.first_phase(invalid_feature);
+ EXPECT_FALSE(f.verify());
+}
+
+TEST_F("require that second phase can break validation", SimpleModel()) {
+ f.second_phase(invalid_feature);
+ EXPECT_FALSE(f.verify());
+}
+
+TEST_F("require that summary features can break validation", SimpleModel()) {
+ f.summary_feature(invalid_feature);
+ EXPECT_FALSE(f.verify());
+}
+
+TEST_F("require that dump features can break validation", SimpleModel()) {
+ f.dump_feature(invalid_feature);
+ EXPECT_FALSE(f.verify());
+}
+
+TEST_F("require that fieldMatch feature requires single value field", SimpleModel()) {
+ f.first_phase("fieldMatch(keywords)");
+ EXPECT_FALSE(f.verify());
+ f.first_phase("fieldMatch(list)");
+ EXPECT_FALSE(f.verify());
+ f.first_phase("fieldMatch(title)");
+ EXPECT_TRUE(f.verify());
+}
+
+TEST_F("require that age feature requires attribute parameter", SimpleModel()) {
+ f.first_phase("age(unknown)");
+ EXPECT_FALSE(f.verify());
+ f.first_phase("age(title)");
+ EXPECT_FALSE(f.verify());
+ f.first_phase("age(date)");
+ EXPECT_TRUE(f.verify());
+}
+
+TEST_F("require that nativeRank can be used on any valid field", SimpleModel()) {
+ f.verify_invalid({"nativeRank(unknown)"});
+ f.verify_valid({"nativeRank", "nativeRank(title)", "nativeRank(date)", "nativeRank(title,date)"});
+}
+
+TEST_F("require that nativeAttributeMatch requires attribute parameter", SimpleModel()) {
+ f.verify_invalid({"nativeAttributeMatch(unknown)", "nativeAttributeMatch(title)", "nativeAttributeMatch(title,date)"});
+ f.verify_valid({"nativeAttributeMatch", "nativeAttributeMatch(date)"});
+}
+
+TEST_F("require that shadowed attributes can be used", ShadowModel()) {
+ f.first_phase("attribute(both)");
+ EXPECT_TRUE(f.verify());
+}
+
+//-----------------------------------------------------------------------------
+
+TEST_F("cleanup files", Model()) {
+ ASSERT_TRUE(vespalib::SlaveProc::run(vespalib::make_string("rm -rf %s", gen_dir.c_str()).c_str()));
+}
+
+TEST_MAIN_WITH_PROCESS_PROXY() { TEST_RUN_ALL(); }
diff --git a/searchcore/src/tests/proton/verify_ranksetup/verify_ranksetup_test.sh b/searchcore/src/tests/proton/verify_ranksetup/verify_ranksetup_test.sh
new file mode 100755
index 00000000000..d03b6309ec9
--- /dev/null
+++ b/searchcore/src/tests/proton/verify_ranksetup/verify_ranksetup_test.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+export PWD=$(cd $(dirname "${BASH_SOURCE[0]}") && pwd)
+$VALGRIND ./searchcore_verify_ranksetup_test_app