Skip to content

Commit

Permalink
[CORE-95] Adding validation endpoints and tests for all server endpoi…
Browse files Browse the repository at this point in the history
…nts.
  • Loading branch information
TelicentPaul committed Jul 2, 2024
1 parent 3865a81 commit 4f8c4c9
Show file tree
Hide file tree
Showing 19 changed files with 1,280 additions and 105 deletions.
6 changes: 5 additions & 1 deletion graphql-fuseki-module/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${ver.mockito}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<scope>test</scope>
</dependency>

Expand Down
7 changes: 6 additions & 1 deletion graphql-jena-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<groupId>io.telicent.jena.graphql</groupId>
<artifactId>parent</artifactId>
<version>0.7.0-SNAPSHOT</version>
<relativePath>..</relativePath>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>graphql-jena-core</artifactId>
<name>Telicent - GraphQL for Apache Jena - Core API</name>
Expand Down Expand Up @@ -36,6 +36,11 @@
<artifactId>jackson-databind</artifactId>
</dependency>

<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import graphql.ExecutionInput;
import graphql.ExecutionResult;
import graphql.GraphQL;
import graphql.*;
import graphql.execution.preparsed.PreparsedDocumentEntry;
import graphql.execution.preparsed.PreparsedDocumentProvider;
import graphql.schema.GraphQLSchema;
Expand Down Expand Up @@ -210,4 +208,27 @@ public final ExecutionResult execute(DatasetGraph dsg, String query, String oper
protected Object createLocalContext(DatasetGraph dsg, Map<String, Object> extensions) {
return dsg;
}


/**
* Validate the given Graph QL query
* @param query Query to validate
* @param operationName Operation name indicating an operation within the query document to execute
* @param variables Variables to make available to the query
* @param extensions Vendor extensions to make available to the query
* @return Parsing results
*/
@Override
public ParseAndValidateResult validate(String query, String operationName, Map<String, Object> variables,
Map<String, Object> extensions){
Objects.requireNonNull(dsg, "DatasetGraph to validate against cannot be null");
ExecutionInput input =
ExecutionInput.newExecutionInput(query)
.localContext(createLocalContext(dsg, extensions))
.operationName(operationName)
.variables(variables)
.extensions(extensions)
.build();
return ParseAndValidate.parseAndValidate(schema, input);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package io.telicent.jena.graphql.execution;

import graphql.ExecutionResult;
import graphql.ParseAndValidateResult;
import io.telicent.jena.graphql.server.model.GraphQLRequest;

import java.util.Map;
Expand Down Expand Up @@ -57,4 +58,15 @@ ExecutionResult execute(String query, String operationName, Map<String, Object>
* @return Execution result
*/
ExecutionResult execute(GraphQLRequest request);

/**
* Validates the provided request
* @param query Query
* @param operationName Operation name indicating an operation within the query document to execute
* @param variables Variables to make available to the query
* @param extensions Vendor extensions to make available to the query
* @return Validation Result
*/
ParseAndValidateResult validate(String query, String operationName, Map<String, Object> variables,
Map<String, Object> extensions);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* Copyright (C) Telicent Ltd
*
* Licensed 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 io.telicent.jena.graphql.utils;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Class for excluding code from coverage as it is unsuitable.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExcludeFromJacocoGeneratedReport {
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import graphql.ErrorType;
import graphql.ExecutionResult;
import graphql.GraphQLError;
import graphql.ParseAndValidateResult;
import io.telicent.jena.graphql.schemas.models.NodeKind;
import io.telicent.jena.graphql.schemas.models.WrappedNode;
import io.telicent.jena.graphql.server.model.GraphQLRequest;
Expand Down Expand Up @@ -98,6 +101,92 @@ protected static ExecutionResult verifyExecution(GraphQLExecutor execution, Grap
return result;
}

/**
* Verifies that the given query is valid
*
* @param execution Execution to validate the query against
* @param query Raw GraphQL Query
* @return Validation result
*/
protected static ParseAndValidateResult verifyValidationSuccess(GraphQLExecutor execution, String query) {
return verifyValidationSuccess(execution, query, Collections.emptyMap());
}

/**
* Verifies that the given query is valid
*
* @param execution Execution to validate the query against
* @param query Raw GraphQL Query
* @param variables Variables for use by the query
* @return Validation result
*/
protected static ParseAndValidateResult verifyValidationSuccess(GraphQLExecutor execution, String query,
Map<String, Object> variables) {
return verifyValidationSuccess(execution, query, variables, Collections.emptyMap());
}

/**
* Verifies that the given query is valid
*
* @param execution Execution to validate the query against
* @param query Raw GraphQL Query
* @param variables Variables for use by the query
* @param extensions Extensions for use by the query
* @return Validation result
*/
protected static ParseAndValidateResult verifyValidationSuccess(GraphQLExecutor execution, String query,
Map<String, Object> variables, Map<String,Object> extensions) {
ParseAndValidateResult result = execution.validate(query, "test", variables, extensions);
Assert.assertFalse(result.isFailure());
Assert.assertTrue(result.getErrors().isEmpty());
return result;
}

/**
* Verifies that the given query is invalid
*
* @param execution Execution to validate the query against
* @param query Raw GraphQL Query
* @return Validation result
*/
protected static ParseAndValidateResult verifyValidationFailure(GraphQLExecutor execution, String query) {
return verifyValidationFailure(execution, query, Collections.emptyMap());
}

/**
* Verifies that the given query is invalid
*
* @param execution Execution to validate the query against
* @param query Raw GraphQL Query
* @param variables Variables for use by the query
* @return Validation result
*/
protected static ParseAndValidateResult verifyValidationFailure(GraphQLExecutor execution, String query,
Map<String, Object> variables) {
return verifyValidationFailure(execution, query, variables, Collections.emptyMap());
}
/**
* Verifies that the given query is invalid
*
* @param execution Execution to validate the query against
* @param query Raw GraphQL Query
* @param variables Variables for use by the query
* @param extensions Extensions for use by the query
* @return Validation result
*/
protected static ParseAndValidateResult verifyValidationFailure(GraphQLExecutor execution, String query,
Map<String, Object> variables, Map<String,Object> extensions) {
ParseAndValidateResult result = execution.validate(query, "test", variables, extensions);
Assert.assertTrue(result.isFailure());
Assert.assertFalse(result.getErrors().isEmpty());
List<GraphQLError> errors = result.getErrors();
Assert.assertEquals(errors.size(), 1);
GraphQLError error = errors.get(0);
Assert.assertEquals(error.getErrorType(), ErrorType.InvalidSyntax);
return result;
}


protected static void verifyNode(Map<String, Object> quad, String field, NodeKind kind, String expectedValue,
String expectedLang, String expectedDatatype) {
@SuppressWarnings("unchecked")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/**
* Copyright (C) Telicent Ltd
*
* Licensed 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 io.telicent.jena.graphql.execution;

import graphql.ErrorType;
import graphql.GraphQLError;
import graphql.ParseAndValidateResult;
import graphql.validation.ValidationError;
import io.telicent.jena.graphql.schemas.CoreSchema;
import io.telicent.jena.graphql.utils.NodeFilter;
import org.apache.jena.sparql.core.DatasetGraphFactory;
import org.apache.jena.vocabulary.RDFS;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import java.io.IOException;
import java.util.List;
import java.util.Map;

import static graphql.validation.ValidationErrorType.InvalidSyntax;

@SuppressWarnings("unchecked")
public class TestDatasetValidation extends AbstractExecutionTests {

private static final String QUERY_BASE = "/queries/dataset/";

private static String loadQuery(String queryResource) {
return loadQuery(QUERY_BASE, queryResource);
}

public static final String SIMPLE_QUADS_QUERY = loadQuery("simple-quads.graphql");

public static final String FILTERED_QUADS_QUERY = loadQuery("filtered-quads.graphql");

public static final String VARIABLE_QUADS_QUERY = loadQuery("variable-quads.graphql");

public static final String ALIASED_QUADS_QUERY = loadQuery("aliased-quads.graphql");

public static final String FRAGMENT_QUADS_QUERY = loadQuery("fragment-quads.graphql");


@DataProvider(name = "validQueries")
private static Object[] validQueryList() {
return new Object[] {
SIMPLE_QUADS_QUERY,
FILTERED_QUADS_QUERY,
ALIASED_QUADS_QUERY,
FRAGMENT_QUADS_QUERY,
VARIABLE_QUADS_QUERY
};
}


@DataProvider(name = "invalidQueries")
private static Object[] invalidQueryList() {
return new Object[] {
"",
"random",
"query={}",
"query={",
"query=query($subject: NodeFilter, $predicate: NodeFilter, $object: NodeFilter, $graph: NodeFilter) {}"
};
}

@Test(dataProvider = "validQueries")
public void dataset_valid_queries(String validQuery) throws IOException {
DatasetExecutor execution = new DatasetExecutor(DatasetGraphFactory.create());

verifyValidationSuccess(execution, validQuery);
}

@Test(dataProvider = "invalidQueries")
public void dataset_invalid_queries(String invalidQuery) throws IOException {
DatasetExecutor execution = new DatasetExecutor(DatasetGraphFactory.create());

verifyValidationFailure(execution, invalidQuery);
}

}
Loading

0 comments on commit 4f8c4c9

Please # to comment.