/*******************************************************************************
* Copyright (c) 2010, 2014 IBM Corporation and others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.orion.server.tests.servlets.files;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.orion.internal.server.core.metastore.SimpleMetaStore;
import org.eclipse.orion.internal.server.servlets.IFileStoreModificationListener.ChangeType;
import org.eclipse.orion.server.core.ProtocolConstants;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.Before;
import org.junit.Test;
import org.xml.sax.SAXException;
import com.meterware.httpunit.WebConversation;
import com.meterware.httpunit.WebRequest;
import com.meterware.httpunit.WebResponse;
public class AdvancedFilesTest extends FileSystemTest {
private JSONObject getFileMetadataObject(Boolean readonly, Boolean executable) throws JSONException {
Map<String, Object> attributes = new HashMap<String, Object>();
//only test attributes supported by the local file system of the test machine
int attrs = EFS.getLocalFileSystem().attributes();
if (readonly != null && ((attrs & EFS.ATTRIBUTE_READ_ONLY) != 0)) {
attributes.put("ReadOnly", String.valueOf(readonly));
}
if (executable != null && ((attrs & EFS.ATTRIBUTE_EXECUTABLE) != 0)) {
attributes.put("Executable", String.valueOf(executable));
}
JSONObject json = new JSONObject();
json.put("Attributes", attributes);
return json;
}
@Before
public void setUp() throws Exception {
webConversation = new WebConversation();
webConversation.setExceptionsThrownOnErrorStatus(false);
setUpAuthorization();
initializeWorkspaceLocation();
createWorkspace(SimpleMetaStore.DEFAULT_WORKSPACE_NAME);
createTestProject(testName.getMethodName());
}
@Test
public void testETagDeletedFile() throws JSONException, IOException, SAXException, CoreException {
String fileName = "testfile.txt";
//setup: create a file
WebRequest request = getPostFilesRequest("", getNewFileJSON(fileName).toString(), fileName);
WebResponse response = webConversation.getResponse(request);
assertEquals(HttpURLConnection.HTTP_CREATED, response.getResponseCode());
//obtain file metadata and ensure data is correct
request = getGetFilesRequest(fileName + "?parts=meta");
response = webConversation.getResponse(request);
assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
String etag = response.getHeaderField(ProtocolConstants.KEY_ETAG);
assertNotNull(etag);
//delete the file on disk
IFileStore fileStore = EFS.getStore(makeLocalPathAbsolute(fileName));
fileStore.delete(EFS.NONE, null);
//now a PUT should fail
request = getPutFileRequest(fileName, "something");
request.setHeaderField(ProtocolConstants.HEADER_IF_MATCH, etag);
try {
response = webConversation.getResponse(request);
} catch (IOException e) {
//inexplicably HTTPUnit throws IOException on PRECON_FAILED rather than just giving us response
assertTrue(e.getMessage().indexOf(Integer.toString(HttpURLConnection.HTTP_PRECON_FAILED)) > 0);
}
}
@Test
public void testETagPutNotMatch() throws JSONException, IOException, SAXException, CoreException {
String fileName = "testfile.txt";
//setup: create a file
WebRequest request = getPostFilesRequest("", getNewFileJSON(fileName).toString(), fileName);
WebResponse response = webConversation.getResponse(request);
assertEquals(HttpURLConnection.HTTP_CREATED, response.getResponseCode());
//obtain file metadata and ensure data is correct
request = getGetFilesRequest(fileName + "?parts=meta");
response = webConversation.getResponse(request);
assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
String etag = response.getHeaderField(ProtocolConstants.KEY_ETAG);
assertNotNull(etag);
//change the file on disk
IFileStore fileStore = EFS.getStore(makeLocalPathAbsolute(fileName));
OutputStream out = fileStore.openOutputStream(EFS.NONE, null);
out.write("New Contents".getBytes());
out.close();
//now a PUT should fail
request = getPutFileRequest(fileName, "something");
request.setHeaderField("If-Match", etag);
try {
response = webConversation.getResponse(request);
} catch (IOException e) {
//inexplicably HTTPUnit throws IOException on PRECON_FAILED rather than just giving us response
assertTrue(e.getMessage().indexOf(Integer.toString(HttpURLConnection.HTTP_PRECON_FAILED)) > 0);
}
}
/**
* Test commented out due to failure
*/
public void _testETagHandling() throws JSONException, IOException, SAXException {
String fileName = "testfile.txt";
//setup: create a file
WebRequest request = getPostFilesRequest("", getNewFileJSON(fileName).toString(), fileName);
WebResponse response = webConversation.getResponse(request);
assertEquals(HttpURLConnection.HTTP_CREATED, response.getResponseCode());
//obtain file metadata and ensure data is correct
request = getGetFilesRequest(fileName + "?parts=meta");
response = webConversation.getResponse(request);
assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
JSONObject responseObject = new JSONObject(response.getText());
assertNotNull("No file information in response", responseObject);
String etag1 = responseObject.getString(ProtocolConstants.KEY_ETAG);
assertEquals(etag1, response.getHeaderField(ProtocolConstants.KEY_ETAG));
//modify file
request = getPutFileRequest(fileName, "something");
request.setHeaderField("If-Match", etag1);
response = webConversation.getResponse(request);
assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
responseObject = new JSONObject(response.getText());
assertNotNull("No file information in response", responseObject);
String etag2 = responseObject.getString(ProtocolConstants.KEY_ETAG);
assertEquals(etag2, response.getHeaderField(ProtocolConstants.KEY_ETAG));
// should be different as file was modified
assertFalse(etag2.equals(etag1));
//fetch the metadata again and ensure it is changed and correct
request = getGetFilesRequest(fileName + "?parts=meta");
response = webConversation.getResponse(request);
assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
responseObject = new JSONObject(response.getText());
String etag3 = responseObject.getString(ProtocolConstants.KEY_ETAG);
assertEquals(etag3, response.getHeaderField(ProtocolConstants.KEY_ETAG));
assertEquals(etag2, etag3);
}
@Test
public void testGetNonExistingFile() throws IOException, SAXException {
WebRequest request = getGetFilesRequest("does/not/exists/directory");
WebResponse response = webConversation.getResponse(request);
assertEquals("Retriving non existing directory return wrong response code.", HttpURLConnection.HTTP_NOT_FOUND, response.getResponseCode());
request = getGetFilesRequest("does/not/exists/directory?depth=5");
response = webConversation.getResponse(request);
assertEquals("Retriving non existing directory return wrong response code.", HttpURLConnection.HTTP_NOT_FOUND, response.getResponseCode());
}
@Test
public void testMetadataHandling() throws JSONException, IOException, SAXException {
String fileName = "testMetadataHandling.txt";
//setup: create a file
WebRequest request = getPostFilesRequest("", getNewFileJSON(fileName).toString(), fileName);
WebResponse response = webConversation.getResponse(request);
assertEquals(HttpURLConnection.HTTP_CREATED, response.getResponseCode());
//obtain file metadata and ensure data is correct
request = getGetFilesRequest(fileName + "?parts=meta");
response = webConversation.getResponse(request);
assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
JSONObject responseObject = new JSONObject(response.getText());
assertNotNull("No file information in response", responseObject);
checkFileMetadata(responseObject, fileName, new Long(-1), null, null, request.getURL().getRef(), new Long(0), null, null, null);
//modify the metadata
request = getPutFileRequest(fileName + "?parts=meta", getFileMetadataObject(true, true).toString());
response = webConversation.getResponse(request);
assertEquals(HttpURLConnection.HTTP_NO_CONTENT, response.getResponseCode());
//fetch the metadata again and ensure it is changed
request = getGetFilesRequest(fileName + "?parts=meta");
response = webConversation.getResponse(request);
assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
responseObject = new JSONObject(response.getText());
checkFileMetadata(responseObject, fileName, new Long(-1), null, null, request.getURL().getRef(), new Long(0), new Boolean(true), new Boolean(true), null);
//make the file writeable again so test can clean up
request = getPutFileRequest(fileName + "?parts=meta", getFileMetadataObject(false, false).toString());
response = webConversation.getResponse(request);
assertEquals(HttpURLConnection.HTTP_NO_CONTENT, response.getResponseCode());
}
/**
* @returns A Patch with a single diff
*/
private JSONObject createPatch(int start, int end, String text) throws JSONException {
JSONObject diff = new JSONObject();
diff.put("start", start);
diff.put("end", end);
diff.put("text", text);
JSONArray diffArray = new JSONArray();
diffArray.put(diff);
JSONObject patch = new JSONObject();
patch.put("diff", diffArray);
return patch;
}
@Test
public void testPatchEmptyFile() throws JSONException, IOException, SAXException {
String fileName = "testPatch.txt";
String patchedContents = "hi there";
//setup: create an empty file
WebRequest request = getPostFilesRequest("", getNewFileJSON(fileName).toString(), fileName);
WebResponse response = webConversation.getResponse(request);
assertEquals(HttpURLConnection.HTTP_CREATED, response.getResponseCode());
//patch it, ensure the metadata is returned and is correct
JSONObject patch = createPatch(0, 0, patchedContents);
request = getPatchFileRequest(fileName, patch.toString());
response = webConversation.getResponse(request);
JSONObject patchedMetadata = new JSONObject(response.getText());
assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
assertEquals("Has expected content type", "application/json", response.getContentType());
assertEquals("Has expected length", patchedContents.length(), patchedMetadata.getInt(ProtocolConstants.KEY_LENGTH));
//fetch metadata, make sure it is consistent with metadata returned from patch response.
request = getGetFilesRequest(fileName + "?parts=meta");
response = webConversation.getResponse(request);
JSONObject getMetadata = new JSONObject(response.getText());
assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
assertEquals("ETag is consistent", patchedMetadata.getString(ProtocolConstants.KEY_ETAG), getMetadata.getString(ProtocolConstants.KEY_ETAG));
//fetch contents, make sure they are correct
request = getGetFilesRequest(fileName);
response = webConversation.getResponse(request);
assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
assertEquals("Has expected contents", patchedContents, response.getText());
}
@Test
public void testListenerMetadataHandling() throws JSONException, IOException, SAXException, CoreException {
String fileName = "testListenerMetadataHandling.txt";
//setup: create a file
WebRequest request = getPostFilesRequest("", getNewFileJSON(fileName).toString(), fileName);
WebResponse response = webConversation.getResponse(request);
assertEquals(HttpURLConnection.HTTP_CREATED, response.getResponseCode());
TestFilesystemModificationListener l = new TestFilesystemModificationListener();
try {
//modify the metadata
request = getPutFileRequest(fileName + "?parts=meta", getFileMetadataObject(true, true).toString());
response = webConversation.getResponse(request);
assertEquals(HttpURLConnection.HTTP_NO_CONTENT, response.getResponseCode());
IFileStore fileStore = EFS.getStore(makeLocalPathAbsolute(fileName));
l.assertListenerNotified(fileStore, ChangeType.PUTINFO);
} finally {
TestFilesystemModificationListener.cleanup(l);
}
//make the file writeable again so test can clean up
request = getPutFileRequest(fileName + "?parts=meta", getFileMetadataObject(false, false).toString());
response = webConversation.getResponse(request);
assertEquals(HttpURLConnection.HTTP_NO_CONTENT, response.getResponseCode());
}
}