/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.rya.streams.client.command; import static org.junit.Assert.assertEquals; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.UUID; import java.util.concurrent.TimeUnit; import org.apache.kafka.clients.consumer.Consumer; import org.apache.kafka.clients.producer.Producer; import org.apache.kafka.common.serialization.StringDeserializer; import org.apache.kafka.common.serialization.StringSerializer; import org.apache.rya.api.model.VisibilityBindingSet; import org.apache.rya.api.model.VisibilityStatement; import org.apache.rya.streams.api.entity.StreamsQuery; import org.apache.rya.streams.api.interactor.LoadStatements; import org.apache.rya.streams.api.queries.InMemoryQueryRepository; import org.apache.rya.streams.api.queries.QueryChange; import org.apache.rya.streams.api.queries.QueryChangeLog; import org.apache.rya.streams.api.queries.QueryRepository; import org.apache.rya.streams.client.RyaStreamsCommand.ArgumentsException; import org.apache.rya.streams.client.RyaStreamsCommand.ExecutionException; import org.apache.rya.streams.kafka.KafkaTopics; import org.apache.rya.streams.kafka.interactor.KafkaLoadStatements; import org.apache.rya.streams.kafka.queries.KafkaQueryChangeLog; import org.apache.rya.streams.kafka.serialization.VisibilityBindingSetDeserializer; import org.apache.rya.streams.kafka.serialization.VisibilityStatementSerializer; import org.apache.rya.streams.kafka.serialization.queries.QueryChangeDeserializer; import org.apache.rya.streams.kafka.serialization.queries.QueryChangeSerializer; import org.apache.rya.test.kafka.KafkaTestInstanceRule; import org.apache.rya.test.kafka.KafkaTestUtil; import org.eclipse.rdf4j.model.ValueFactory; import org.eclipse.rdf4j.model.impl.SimpleValueFactory; import org.eclipse.rdf4j.query.impl.MapBindingSet; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import com.google.common.collect.Lists; import com.google.common.util.concurrent.AbstractScheduledService.Scheduler; /** * Integration tests the methods of {@link RunQueryCommand}. */ public class RunQueryCommandIT { private static final Path LUBM_FILE = Paths.get("src/test/resources/lubm-1uni-withschema.nt"); private static final String LUBM_PREFIX = "http://swat.cse.lehigh.edu/onto/univ-bench.owl#"; private static final int LUBM_EXPECTED_RESULTS_COUNT = 1874; private final String ryaInstance = UUID.randomUUID().toString(); private QueryRepository queryRepo; private Producer<String, VisibilityStatement> stmtProducer = null; private Consumer<String, VisibilityBindingSet> resultConsumer = null; @Rule public KafkaTestInstanceRule kafka = new KafkaTestInstanceRule(true); @Before public void setup() { // Make sure the topic that the change log uses exists. final String changeLogTopic = KafkaTopics.queryChangeLogTopic("" + ryaInstance); kafka.createTopic(changeLogTopic); // Setup the QueryRepository used by the test. final Producer<?, QueryChange> queryProducer = KafkaTestUtil.makeProducer(kafka, StringSerializer.class, QueryChangeSerializer.class); final Consumer<?, QueryChange> queryConsumer = KafkaTestUtil.fromStartConsumer(kafka, StringDeserializer.class, QueryChangeDeserializer.class); final QueryChangeLog changeLog = new KafkaQueryChangeLog(queryProducer, queryConsumer, changeLogTopic); queryRepo = new InMemoryQueryRepository(changeLog, Scheduler.newFixedRateSchedule(0L, 5, TimeUnit.SECONDS)); // Initialize the Statements Producer and the Results Consumer. stmtProducer = KafkaTestUtil.makeProducer(kafka, StringSerializer.class, VisibilityStatementSerializer.class); resultConsumer = KafkaTestUtil.fromStartConsumer(kafka, StringDeserializer.class, VisibilityBindingSetDeserializer.class); } @After public void cleanup() throws Exception { queryRepo.stopAndWait(); stmtProducer.close(); resultConsumer.close(); } @Test(expected = ExecutionException.class) public void runUnregisteredQuery() throws Exception { // Arguments that run a query that is not registered with Rya Streams. final String[] args = new String[] { "--ryaInstance", "" + ryaInstance, "--kafkaHostname", kafka.getKafkaHostname(), "--kafkaPort", kafka.getKafkaPort(), "--queryID", UUID.randomUUID().toString(), "--zookeepers", kafka.getZookeeperServers() }; // Run the test. This will throw an exception. final RunQueryCommand command = new RunQueryCommand(); command.execute(args); } @Test public void runQuery() throws Exception { // Register a query with the Query Repository. final StreamsQuery sQuery = queryRepo.add("SELECT * WHERE { ?person <urn:worksAt> ?business . }", true, false); // Arguments that run the query we just registered with Rya Streams. final String[] args = new String[] { "--ryaInstance", "" + ryaInstance, "--kafkaHostname", kafka.getKafkaHostname(), "--kafkaPort", kafka.getKafkaPort(), "--queryID", sQuery.getQueryId().toString(), "--zookeepers", kafka.getZookeeperServers() }; // Create a new Thread that runs the command. final Thread commandThread = new Thread() { @Override public void run() { final RunQueryCommand command = new RunQueryCommand(); try { command.execute(args); } catch (final ArgumentsException | ExecutionException e) { // Do nothing. Test will still fail because the expected results will be missing. } } }; // Create the statements that will be loaded. final ValueFactory vf = SimpleValueFactory.getInstance(); final List<VisibilityStatement> statements = new ArrayList<>(); statements.add(new VisibilityStatement(vf.createStatement( vf.createIRI("urn:Alice"), vf.createIRI("urn:worksAt"), vf.createIRI("urn:BurgerJoint")), "a")); statements.add(new VisibilityStatement(vf.createStatement( vf.createIRI("urn:Bob"), vf.createIRI("urn:worksAt"), vf.createIRI("urn:TacoShop")), "a")); statements.add(new VisibilityStatement(vf.createStatement( vf.createIRI("urn:Charlie"), vf.createIRI("urn:worksAt"), vf.createIRI("urn:TacoShop")), "a")); // Create the expected results. final List<VisibilityBindingSet> expected = new ArrayList<>(); MapBindingSet bs = new MapBindingSet(); bs.addBinding("person", vf.createIRI("urn:Alice")); bs.addBinding("business", vf.createIRI("urn:BurgerJoint")); expected.add(new VisibilityBindingSet(bs, "a")); bs = new MapBindingSet(); bs.addBinding("person", vf.createIRI("urn:Bob")); bs.addBinding("business", vf.createIRI("urn:TacoShop")); expected.add(new VisibilityBindingSet(bs, "a")); bs = new MapBindingSet(); bs.addBinding("person", vf.createIRI("urn:Charlie")); bs.addBinding("business", vf.createIRI("urn:TacoShop")); expected.add(new VisibilityBindingSet(bs, "a")); // Execute the test. This will result in a set of results that were read from the results topic. final List<VisibilityBindingSet> results; try { // Wait for the program to start. commandThread.start(); Thread.sleep(5000); // Write some statements to the program. final String statementsTopic = KafkaTopics.statementsTopic(ryaInstance); final LoadStatements loadStatements = new KafkaLoadStatements(statementsTopic, stmtProducer); loadStatements.fromCollection(statements); // Read the output of the streams program. final String resultsTopic = KafkaTopics.queryResultsTopic(ryaInstance, sQuery.getQueryId()); resultConsumer.subscribe( Lists.newArrayList(resultsTopic) ); results = KafkaTestUtil.pollForResults(500, 6, 3, resultConsumer); } finally { // Tear down the test. commandThread.interrupt(); commandThread.join(3000); } // Show the read results matched the expected ones. assertEquals(expected, results); } @Test public void runQueryFromFile() throws Exception { // NOTE: the order of the query statements previously led to join // issues. When "lubm:undergraduateDegreeFrom" was the first statement // in the where clause (as opposed to the last) the // KeyValueJoinStateStore blew up. // (This issue appears to have been resolved now though, but is tested // here) final String query = "PREFIX lubm: <" + LUBM_PREFIX + "> \n" + "SELECT * WHERE \n" + "{ \n" + " ?graduateStudent lubm:undergraduateDegreeFrom ?underGradUniversity . \n" + " ?graduateStudent a lubm:GraduateStudent . \n" + " ?underGradUniversity a lubm:University . \n" + "}"; // Register a query with the Query Repository. final StreamsQuery sQuery = queryRepo.add(query, true, true); // Arguments that run the query we just registered with Rya Streams. final String[] args = new String[] { "--ryaInstance", "" + ryaInstance, "--kafkaHostname", kafka.getKafkaHostname(), "--kafkaPort", kafka.getKafkaPort(), "--queryID", sQuery.getQueryId().toString(), "--zookeepers", kafka.getZookeeperServers() }; // Create a new Thread that runs the command. final Thread commandThread = new Thread() { @Override public void run() { final RunQueryCommand command = new RunQueryCommand(); try { command.execute(args); } catch (final ArgumentsException | ExecutionException e) { // Do nothing. Test will still fail because the expected results will be missing. } } }; // Execute the test. This will result in a set of results that were read from the results topic. final Set<VisibilityBindingSet> results = new HashSet<>(); try { // Wait for the program to start. commandThread.start(); Thread.sleep(5000); // Write some statements to the program. final String statementsTopic = KafkaTopics.statementsTopic(ryaInstance); final LoadStatements loadStatements = new KafkaLoadStatements(statementsTopic, stmtProducer); loadStatements.fromFile(LUBM_FILE, ""); // Read the output of the streams program. final String resultsTopic = KafkaTopics.queryResultsTopic(ryaInstance, sQuery.getQueryId()); resultConsumer.subscribe( Lists.newArrayList(resultsTopic) ); results.addAll(KafkaTestUtil.pollForResults(500, 2 * LUBM_EXPECTED_RESULTS_COUNT, LUBM_EXPECTED_RESULTS_COUNT, resultConsumer)); } finally { // Tear down the test. commandThread.interrupt(); commandThread.join(3000); } System.out.println("LUBM Query Results Count: " + results.size()); // Show the read results matched the expected ones. assertEquals(LUBM_EXPECTED_RESULTS_COUNT, results.size()); } }