package org.mitre.rhex;
import edu.umd.cs.findbugs.annotations.NonNull;
import org.apache.commons.lang.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.FileEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.protocol.HTTP;
import org.mitre.test.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.List;
/**
* Test for document PUT operation
*
* <pre>
* 6.5 baseURL/sectionpath/documentname
*
* 6.5.2 PUT
*
* This operation is used to update a document by replacing it. The PUT operation
* MUST NOT be used to create a new document; new documents MUST be created by
* POSTing to the section. If the client attempts to create a new document this
* way [via PUT], the server MUST return a 404.
*
* The content MUST conform to the media type identified by the document metadata
* or the section content type. For media type application/xml, the document MUST
* also conform to the XML schema that corresponds to the content type identified
* by the document metadata or the section.
*
* If the parameter is incorrect or the content cannot be validated against
* the correct media type or the XML schema identified by the content type
* of this section, the server MUST return a status code of 400.
*
* If the request is successful, the [updated] section document MUST show up in the
* document feed for the section. The server returns a 200.
*
* Status Code: 200, 400, [404]
* </pre>
*
* @author Jason Mathews, MITRE Corp.
* Date: 2/20/12 10:45 AM
*/
public class DocumentPut extends BaseTest {
@NonNull
public String getId() {
return "6.5.2.3";
}
@Override
public boolean isRequired() {
return true;
}
@NonNull
public String getName() {
return "PUT operation to create a new document, server MUST return a 404";
}
@NonNull
public List<Class<? extends TestUnit>> getDependencyClasses() {
return Collections.<Class<? extends TestUnit>> singletonList(BaseSectionFromRootXml.class); // 6.4.1.1
}
public void execute() throws TestException {
// pre-conditions: for this test to be executed the prerequisite test BaseSectionFromRootXml
// must have passed with 200 HTTP and has a Map of all section ATOM DOMs and list of sections.
TestUnit baseTest = getDependency(BaseSectionFromRootXml.class);
if (baseTest == null) {
// assertion failed: this should never be null
log.error("Failed to retrieve prerequisite test");
setStatus(StatusEnumType.SKIPPED, "Failed to retrieve prerequisite test");
return;
}
List<String> sections = ((BaseSectionFromRootXml)baseTest).getSectionList();
if (sections.isEmpty()) {
log.error("Failed to retrieve prerequisite test");
setStatus(StatusEnumType.SKIPPED, "Failed to retrieve prerequisite test results");
return;
}
final Context context = Loader.getInstance().getContext();
String documentSection = context.getString("updateDocument.section");
if (StringUtils.isBlank(documentSection)) {
// check pre-conditions and setup
// e.g. documentSection=vital_signs
log.error("Failed to specify valid updateDocument/section property in configuration");
setStatus(StatusEnumType.SKIPPED, "Failed to specify valid updateDocument/section property in configuration");
return;
}
if (!sections.contains(documentSection)) {
// test pre-conditions
setStatus(StatusEnumType.SKIPPED, "Failed to find section in test results");
return;
}
File updateDocument = context.getPropertyAsFile("updateDocument.file");
if (updateDocument == null) {
log.error("Failed to specify valid updateDocument/file property in configuration");
setStatus(StatusEnumType.SKIPPED, "Failed to specify valid updateDocument/file property in configuration");
return;
}
log.debug("use file input: {}", updateDocument);
HttpClient client = null;
try {
// create a documentname URL for an existing section that does not already exist
String documentPath = Long.toHexString(System.currentTimeMillis());
URI baseUrl = context.getBaseURL(documentSection + "/" + documentPath);
if (log.isDebugEnabled()) {
System.out.println("\nURL: " + baseUrl);
System.out.println("documentPath=" + documentPath);
}
client = context.getHttpClient();
// note: section 6.5.2 does not list the PUT form parameter for the request body
// which is assumed to be of type �application/xwww- form-urlencoded as defined
// in 6.2.2 POST as Parameters:extensionID, path, name.
// List<NameValuePair> formParams = new ArrayList<NameValuePair>(2);
// TODO: what does a valid document look like ?? only have access to json presentation now ???
// formParams.add(new BasicNameValuePair("body", ""));
// formParams.add(new BasicNameValuePair("document", ""));
// request.setEntity(new UrlEncodedFormEntity(formParams));
HttpPut request = new HttpPut(baseUrl);
request.setEntity(new FileEntity(updateDocument, ContentType.APPLICATION_XML));
HttpResponse response = context.executeRequest(client, request);
int code = response.getStatusLine().getStatusCode();
if (code != 404 || log.isDebugEnabled()) {
dumpResponse(request, response, true);
/*
System.out.println("PUT Response status=" + code);
for (Header header : response.getAllHeaders()) {
System.out.println("\t" + header.getName() + ": " + header.getValue());
}
*/
}
if (code != 404) {
setStatus(StatusEnumType.FAILED, "Expected 404 HTTP status code but was: " + code);
return;
}
setStatus(StatusEnumType.SUCCESS);
} catch (URISyntaxException e) {
log.error("", e);
setStatus(StatusEnumType.SKIPPED, "Failed to construct valid URI for section");
} catch (IOException e) {
throw new TestException(e);
} finally {
if (client != null)
client.getConnectionManager().shutdown();
}
}
}