OverviewFilesCommitsIssuesDocsReleasesPeers

opencog-atomspace-cog / tests / persist / cog-simple / SimpleQueryPersistUTest.cxxtest

282 lines · cxxtest ref:
/*
 * tests/persist/cog-simple/SimpleQueryPersistUTest.cxxtest
 *
 * Test persistance queries.  Assumes PerisistUTest and ValueSaveUTest
 * are passing.
 *
 * Copyright (C) 2008, 2009, 2013, 2020 Linas Vepstas <linasvepstas@gmail.com>
 * All Rights Reserved
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <cstdio>

#include <opencog/atoms/atom_types/atom_types.h>
#include <opencog/persist/cog-types/atom_types.h>
#include <opencog/atoms/base/Atom.h>
#include <opencog/atoms/base/Link.h>
#include <opencog/atoms/base/Node.h>
#include <opencog/atomspace/AtomSpace.h>
#include <opencog/atoms/value/FloatValue.h>
#include <opencog/atoms/value/LinkValue.h>
#include <opencog/atoms/value/VoidValue.h>
#include <opencog/persist/cog-simple/CogSimpleStorage.h>

#include <opencog/util/Logger.h>
#include "../TestCogServer.h"

using namespace opencog;

class SimpleQueryPersistUTest :  public CxxTest::TestSuite
{
	private:
		AtomSpacePtr _as;
		std::string uri;
		DECLARE_TEST_COGSERVER

	public:

		SimpleQueryPersistUTest(void);
		~SimpleQueryPersistUTest()
		{
			STOP_TEST_COGSERVER

			logger().flush();

			// erase the log file if no assertions failed
			if (!CxxTest::TestTracker::tracker().suiteFailed())
				std::remove(logger().get_filename().c_str());
		}

		void setUp(void);
		void tearDown(void);
		void kill_data(void);

		void setup_data(void);
		void test_meet(void);
		void test_join(void);
};

SimpleQueryPersistUTest:: SimpleQueryPersistUTest(void)
{
	// logger().set_level(Logger::DEBUG);
	logger().set_level(Logger::INFO);
	logger().set_print_to_stdout_flag(true);

	uri = "cog://localhost:16313";

	INIT_TEST_COGSERVER(16313);
	printf("Started CogServer\n");
}

/*
 * This is called once before each test, for each test (!!)
 */
void SimpleQueryPersistUTest::setUp(void)
{
	_as = nullptr;
}

void SimpleQueryPersistUTest::tearDown(void)
{
	kill_data();
}

// ============================================================

void SimpleQueryPersistUTest::kill_data(void)
{
	CogSimpleStorage *astore = new CogSimpleStorage(uri);
	astore->open();
	TS_ASSERT(astore->connected())

	// Selectively clear test data (preserves CogServerNode)
	::kill_data(astore, _test_asp.get());

	// Destructor also logs out of database
	delete astore;
}

// ============================================================
#define an _as->add_node
#define al _as->add_link
#define CONCEPT CONCEPT_NODE
#define VARIABLE VARIABLE_NODE

void SimpleQueryPersistUTest::setup_data(void)
{
	kill_data();

	_as = createAtomSpace();
	Handle hsn = _as->add_node(COG_SIMPLE_STORAGE_NODE, std::string(uri));
	StorageNodePtr store = StorageNodeCast(hsn);
	store->setValue(_as->add_node(PREDICATE_NODE, "*-open-*"), createVoidValue());
	TS_ASSERT(store->connected())

	/* Populate the Storage with stuff that we will later query. */
	al(EVALUATION_LINK, {an(PREDICATE_NODE, "is-a"),
		al(LIST_LINK, {an(CONCEPT, "car"), an(CONCEPT, "vehicle")})});
	al(EVALUATION_LINK, {an(PREDICATE_NODE, "has-a"),
		al(LIST_LINK, {an(CONCEPT, "car"), an(CONCEPT, "wheel")})});
	al(EVALUATION_LINK, {an(PREDICATE_NODE, "has-a"),
		al(LIST_LINK, {an(CONCEPT, "car"), an(CONCEPT, "battery")})});

	al(EVALUATION_LINK, {an(PREDICATE_NODE, "is-a"),
		al(LIST_LINK, {an(CONCEPT, "bicycle"), an(CONCEPT, "vehicle")})});
	al(EVALUATION_LINK, {an(PREDICATE_NODE, "has-a"),
		al(LIST_LINK, {an(CONCEPT, "bicycle"), an(CONCEPT, "wheel")})});
	al(EVALUATION_LINK, {an(PREDICATE_NODE, "has-a"),
		al(LIST_LINK, {an(CONCEPT, "bicycle"), an(CONCEPT, "derailleur")})});

	al(EVALUATION_LINK, {an(PREDICATE_NODE, "is-a"),
		al(LIST_LINK, {an(CONCEPT, "airplane"), an(CONCEPT, "vehicle")})});
	al(EVALUATION_LINK, {an(PREDICATE_NODE, "has-a"),
		al(LIST_LINK, {an(CONCEPT, "airplane"), an(CONCEPT, "wings")})});

	// Sprinkle in some TruthValues
	an(CONCEPT, "airplane") ->
		setValue(truth_key(), createFloatValue(std::vector<double>({0.11, 100})));

	an(CONCEPT, "bicycle") ->
		setValue(truth_key(), createFloatValue(std::vector<double>({0.22, 100})));

	an(CONCEPT, "car") ->
		setValue(truth_key(), createFloatValue(std::vector<double>({0.33, 300})));

	/* Push all atoms out to the server */
	store->store_atomspace();
	store->barrier();
}

void SimpleQueryPersistUTest::test_meet(void)
{
	logger().info("BEGIN TEST: %s", __FUNCTION__);

	setup_data();

	_as = createAtomSpace();
	Handle hsn = _as->add_node(COG_SIMPLE_STORAGE_NODE, std::string(uri));
	StorageNodePtr store = StorageNodeCast(hsn);
	store->setValue(_as->add_node(PREDICATE_NODE, "*-open-*"), createVoidValue());
	TS_ASSERT(store->connected())

	// Create a query to find all things that have wheels.
	// We expect cars and bicycles, only.
	Handle qry =
	al(MEET_LINK, {
		al(TYPED_VARIABLE_LINK,
			{an(VARIABLE, "$transport"), an(TYPE_NODE, "Concept")}),
		al(EVALUATION_LINK, {an(PREDICATE_NODE, "has-a"),
			al(LIST_LINK, {an(VARIABLE, "$transport"), an(CONCEPT, "wheel")})})});

	// Create a key where the query results will arrive...
	Handle key = an(PREDICATE_NODE, "qkey");

	// Run the query
	store->fetch_query(qry, key);
	store->barrier();

	// Verify that only bicycles and cars were fetched
	ValuePtr results = qry->getValue(key);
	printf("Got: %s\n", results->to_string().c_str());

	TSM_ASSERT("Expecting a LinkValue",
		nameserver().isA(results->get_type(), LINK_VALUE));

	LinkValuePtr lvp = LinkValueCast(results);
	TSM_ASSERT_EQUALS("Expecting two results", lvp->size(), 2);

	HandleSet hset = lvp->to_handle_set();
	HandleSet expect;
	expect.insert(an(CONCEPT, "bicycle"));
	expect.insert(an(CONCEPT, "car"));
	TSM_ASSERT_EQUALS("Expecting bicycle and car", hset, expect);

	// Test key deletion.  Lack of a crash is a good thing.
	qry->setValue(key, nullptr);
	store->store_value(qry, key);
	ValuePtr nada = qry->getValue(key);
	TS_ASSERT(nullptr == nada);

	// Should get back the same results.
	store->fetch_query(qry, key);
	store->barrier();
	ValuePtr rtoo = qry->getValue(key);
	printf("Re-got: %s\n", rtoo->to_string().c_str());

	lvp = LinkValueCast(rtoo);
	HandleSet htoo = lvp->to_handle_set();
	TSM_ASSERT("Expect same results as before", hset == htoo);

	store->setValue(_as->add_node(PREDICATE_NODE, "*-close-*"), createVoidValue());

	logger().info("END TEST: %s", __FUNCTION__);
}

void SimpleQueryPersistUTest::test_join(void)
{
	logger().info("BEGIN TEST: %s", __FUNCTION__);

	setup_data();

	_as = createAtomSpace();
	Handle hsn = _as->add_node(COG_SIMPLE_STORAGE_NODE, std::string(uri));
	StorageNodePtr store = StorageNodeCast(hsn);
	store->setValue(_as->add_node(PREDICATE_NODE, "*-open-*"), createVoidValue());
	TS_ASSERT(store->connected())

	// Create a join to find all vehicles.
	Handle join = al(MAXIMAL_JOIN_LINK, an(CONCEPT, "vehicle"));

	// Create a key where the query results will arrive...
	Handle key = an(PREDICATE_NODE, "qkey");

	// Run the join
	store->fetch_query(join, key);
	store->barrier();

	// Verify that vehicles were fetched
	ValuePtr results = join->getValue(key);
	printf("Got: %s\n", results->to_string().c_str());

	TSM_ASSERT("Expecting a LinkValue",
		nameserver().isA(results->get_type(), LINK_VALUE));

	LinkValuePtr lvp = LinkValueCast(results);
	TSM_ASSERT_EQUALS("Expecting three results", lvp->size(), 3);

	HandleSet hset = lvp->to_handle_set();
	HandleSet expect;
	expect.insert(
		al(EVALUATION_LINK, {an(PREDICATE_NODE, "is-a"),
			al(LIST_LINK, {an(CONCEPT, "airplane"), an(CONCEPT, "vehicle")})}));
	expect.insert(
		al(EVALUATION_LINK, {an(PREDICATE_NODE, "is-a"),
			al(LIST_LINK, {an(CONCEPT, "bicycle"), an(CONCEPT, "vehicle")})}));
	expect.insert(
		al(EVALUATION_LINK, {an(PREDICATE_NODE, "is-a"),
			al(LIST_LINK, {an(CONCEPT, "car"), an(CONCEPT, "vehicle")})}));

	TSM_ASSERT_EQUALS("Expecting airplane, bicycle and car", hset, expect);

	store->setValue(_as->add_node(PREDICATE_NODE, "*-close-*"), createVoidValue());

	logger().info("END TEST: %s", __FUNCTION__);
}

/* ============================= END OF FILE ================= */