/*
* 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.stanbol.entityhub.test.query;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.stanbol.entityhub.servicesapi.defaults.NamespaceEnum;
public abstract class QueryTestCase {
/**
* Fields included for each result regardless of the configuration
*/
public static final Set<String> DEFAULT_RESULT_FIELDS =
Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(
NamespaceEnum.entityhubQuery+"score")));
public static final Map<? extends String,? extends String> DEFAULT_HEADER;
static {
Map<String,String> defaultHeader = new HashMap<String,String>();
defaultHeader.put("Accept", "application/json");
DEFAULT_HEADER = Collections.unmodifiableMap(defaultHeader);
}
private final Collection<String> expectedResultIds;
private Collection<String> prohibitedResultIds;
private final Collection<String> allowedFields;
private final int expectedStatus;
private Collection<String> requiredFields;
private Map<String,String> headers;
/**
* Creates a Query Test Case.
* @param expectedStatus the expected HTTP status code returned for this
* test case. If the value is not an 2xx it is not possible to define
* {@link #getExpectedResultIds()}, {@link #getAllowedFields()} and
* {@link #getRequiredFields()} for an test case.
* @param expectedResultIds Expected results for this test case.
* <code>null</code> indicates that there MUST BE no results. An empty
* collection indicates that there MUST BE results but does not test for
* specific results. Any item in the parsed collection MUST BE contained in
* the results of the test case, but this does not mean that there might not
* be other results within the result set of this query.
* @param prohibitedResultIds IDs that MUST NOT be part or the result. If
* <code>null</code> or empty this feature is deactivated
* @throws IllegalArgumentException if the {@link #getExpectedStatus()} is
* not an 2xx code and the expectedResultIds is not <code>null</code>.
*/
protected QueryTestCase(int expectedStatus,Collection<String> expectedResultIds,
Collection<String> prohibitedResultIds){
this.expectedStatus = expectedStatus;
if(!expectsSuccess() && expectedResultIds != null){
//note even an empty collection is not allowed, because this indicated
//that results are expected but to test for specific ids must be made
throw new IllegalArgumentException("Expected Results can only be parsed" +
"if the expected status of this test case has an 2xx code");
}
this.expectedResultIds = expectedResultIds;
if(expectsSuccess()){
this.allowedFields = new HashSet<String>();
this.allowedFields.addAll(DEFAULT_RESULT_FIELDS);
} else {
this.allowedFields = null;
}
headers = new HashMap<String,String>();
headers.putAll(DEFAULT_HEADER);
}
/**
* Setter for the required fields
* @param requiredFields
* @throws IllegalArgumentException In case the
* {@link #getExpectedStatus()} is not an 2xx code
*/
protected final void setRequiredFields(Collection<String> requiredFields) {
if(!expectsSuccess()){
throw new IllegalArgumentException("Required fields can only be set" +
"if the expected status of a test case has a 2xx code");
}
this.requiredFields = requiredFields;
}
/**
* Adds additional allowed fields to the {@link #DEFAULT_RESULT_FIELDS}.
* @param allowedFields
* @throws IllegalArgumentException if the
* {@link #getExpectedStatus()} is not an 2xx code
*/
protected final void addAllowedField(String allowedField) {
if(expectsSuccess()){
if(allowedField != null && !allowedField.isEmpty()){
this.allowedFields.add(allowedField);
}
} else {
throw new IllegalArgumentException("Allowed fields can only be set" +
"if the expected status of a test case has a 2xx code");
}
}
public final boolean expectesResults(){
return expectedResultIds != null;
}
public final Collection<String> getExpectedResultIds() {
return expectedResultIds;
}
/**
* @return the prohibitedResultIds
*/
public final Collection<String> getProhibitedResultIds() {
return prohibitedResultIds;
}
public final Collection<String> getRequiredFields() {
return requiredFields;
}
public final Collection<String> getAllowedFields() {
return allowedFields;
}
public final int getExpectedStatus() {
return expectedStatus;
}
/**
* If the {@link #getExpectedStatus()} is a 2xx
* @return if it is expected that this query test case returns a 2xx code
*/
public boolean expectsSuccess(){
return expectedStatus >= 200 && expectedStatus < 300;
}
/**
* Getter for the content (query) to be sent to the server
* @return the content (query string) to be sent to the entityhub
*/
public abstract String getContent();
/**
* The relative path from the service tested endpoint ("/entityhub", "/sites" or
* "/site/{siteId}") to the service ("/query" for field queries and "/find"
* for label based entity searches).
* @return the relative service path.
*/
public abstract String getServicePath();
/**
* Getter for the HTTP header field needed to execute this request
* @return
*/
public final Map<String,String> getHeaders(){
return headers;
}
/**
* Setter for an HTTP header. This headers are used for the request to the
* Server when execution this test case. If <code>null</code> is parsed as
* value this header is removed. Existing headers are overriden.
* @param key the key
* @param value the value or <code>null</code> to remove this header
*/
protected final void setHeader(String key, String value){
if(value == null){
headers.remove(key);
} else if(key != null){
headers.put(key, value);
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getClass().getSimpleName()).append(":\n");
sb.append(" query: ").append(getContent());
sb.append(" expected status: ").append(expectedStatus).append('\n');
sb.append(" expected results: ");
if(expectedResultIds == null){
sb.append("none");
} else if(expectedResultIds.isEmpty()){
sb.append("any");
} else {
sb.append(expectedResultIds);
}
if(allowedFields != null){
sb.append('\n');
sb.append(" result fields: [");
boolean first = true;
for(String field : allowedFields){
if(first){
first = false;
} else {
sb.append(',');
}
sb.append(field);
if(requiredFields != null && requiredFields.contains(field)){
sb.append(" (required)");
}
}
sb.append(']');
}
return sb.toString();
}
}