AtteanX-Query-Cache

 view release on metacpan or  search on metacpan

t/simple-sparql-planner.t  view on Meta::CPAN

=pod

=encoding utf-8

=head1 PURPOSE

Test that produced plans are correct.

=head1 SYNOPSIS

It may come in handy to enable logging for debugging purposes, e.g.:

  LOG_ADAPTER=Screen DEBUG=1 prove -lv t/idp_sparql_planner.t

This requires that L<Log::Any::Adapter::Screen> is installed.

=head1 AUTHOR

Kjetil Kjernsmo E<lt>kjetilk@cpan.orgE<gt>.

=head1 COPYRIGHT AND LICENCE

This software is copyright (c) 2015, 2016 by Kjetil Kjernsmo.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.


=cut

use v5.14;
use autodie;
use utf8;
use Test::Modern;

use CHI;

use Attean;
use Attean::RDF;
use AtteanX::QueryPlanner::Cache;
use AtteanX::Store::Memory;
#use Carp::Always;
use Data::Dumper;
use AtteanX::Store::SPARQL;
use AtteanX::Model::SPARQLCache;
use Log::Any::Adapter;
Log::Any::Adapter->set($ENV{LOG_ADAPTER} ) if ($ENV{LOG_ADAPTER});

my $cache = CHI->new( driver => 'Memory', global => 1 );

my $p	= AtteanX::QueryPlanner::Cache->new;
isa_ok($p, 'Attean::QueryPlanner');
isa_ok($p, 'AtteanX::QueryPlanner::Cache');
does_ok($p, 'Attean::API::CostPlanner');

{
	# These tests does not actually look up anything in a real store, it just simulates
	my $store	= Attean->get_store('SPARQL')->new('endpoint_url' => iri('http://test.invalid/'));
	isa_ok($store, 'AtteanX::Store::SPARQL');
	my $model	= AtteanX::Model::SPARQLCache->new( store => $store, cache => $cache );
	my $graph = iri('http://test.invalid/graph');
	my $t		= triplepattern(variable('s'), iri('p'), literal('1'));
	my $u		= triplepattern(variable('s'), iri('p'), variable('o'));
	my $v		= triplepattern(variable('s'), iri('q'), blank('xyz'));
	my $w		= triplepattern(variable('a'), iri('b'), iri('c'));
	my $x		= triplepattern(variable('s'), iri('q'), iri('a'));
	my $y		= triplepattern(variable('o'), iri('b'), literal('2'));
	my $z		= triplepattern(variable('a'), iri('c'), variable('s'));
	my $s		= triplepattern(iri('a'), variable('p'), variable('o'));

	subtest 'Empty BGP, to test basics' => sub {
		note("An empty BGP should produce the join identity table plan");
		my $bgp		= Attean::Algebra::BGP->new(triples => []);
		my $plan	= $p->plan_for_algebra($bgp, $model, [$graph]);
		does_ok($plan, 'Attean::API::Plan', 'Empty BGP');
		isa_ok($plan, 'Attean::Plan::Table');
		my $rows	= $plan->rows;
		is(scalar(@$rows), 1);
	};


	subtest '1-triple BGP single variable, with cache, not cached' => sub {
		note("A 1-triple BGP should produce a single Attean::Plan::Iterator plan object");
		$cache->set('?v001 <p> "1" .', ['<http://example.org/foo>', '<http://example.org/bar>']);
		$cache->set('?v001 <p> "dahut" .', ['<http://example.com/foo>', '<http://example.com/bar>']);
		$cache->set('?v001 <dahut> "1" .', ['<http://example.org/dahut>']);
		
		ok($model->is_cached(triplepattern(variable('foo'), iri('p'), literal('1'))->canonicalize->tuples_string), 'Cache has been set');
		ok(! $model->is_cached(triplepattern(variable('foo'), iri('q'), literal('1'))->canonicalize->tuples_string), 'Cache has not been set');
		my $bgp		= Attean::Algebra::BGP->new(triples => [$u]);
		my $plan	= $p->plan_for_algebra($bgp, $model, [$graph]);
		does_ok($plan, 'Attean::API::Plan', '1-triple BGP');
		isa_ok($plan, 'AtteanX::Plan::SPARQLBGP');
		is(scalar @{$plan->children}, 1, '1-triple BGP child');
		like($plan->as_string, qr|SPARQLBGP.*?Quad \{ \?s, <p>, \?o, <http://test.invalid/graph> }|s, 'Good plan');
		is($plan->plan_as_string, 'SPARQLBGP', 'Good plan_as_string');
	};

	subtest '4-triple BGP with join variable with cache one cached' => sub {
		my $bgp		= Attean::Algebra::BGP->new(triples => [$t, $u, $y, $x]);
		my @plans	= $p->plans_for_algebra($bgp, $model, [$graph]);
		is(scalar @plans, 5, 'Got 5 plans');
		my $plan = $plans[0];
		does_ok($plan, 'Attean::API::Plan::Join');
		my @c1plans = sort @{$plan->children};
		isa_ok($c1plans[0], 'Attean::Plan::Iterator', 'First child when sorted is an iterator');
		isa_ok($c1plans[1], 'AtteanX::Plan::SPARQLBGP', 'Second child when sorted is a BGP');
		is(scalar @{$c1plans[1]->children}, 3, '...with three children');
		foreach my $plan (@{$c1plans[1]->children}) {
			isa_ok($plan, 'Attean::Plan::Quad', 'All children are quads');
		}
	};


	subtest '1-triple BGP two variables, with cache' => sub {
		note("A 1-triple BGP should produce a single Attean::Plan::Iterator plan object");
		$cache->set('?v002 <p> ?v001 .', {'<http://example.org/foo>' => ['<http://example.org/bar>'],
													 '<http://example.com/foo>' => ['<http://example.org/baz>', '<http://example.org/foobar>']});



( run in 1.518 second using v1.01-cache-2.11-cpan-39bf76dae61 )