Java tutorial
/******************************************************************************* * Copyright (c) 2010, 2013 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 static org.junit.Assert.fail; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; import org.eclipse.core.filesystem.EFS; import org.eclipse.core.filesystem.IFileInfo; import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.URIUtil; import org.eclipse.orion.internal.server.core.IOUtilities; import org.eclipse.orion.internal.server.core.metastore.SimpleMetaStore; import org.eclipse.orion.internal.server.core.metastore.SimpleMetaStoreUtil; import org.eclipse.orion.internal.server.servlets.ProtocolConstants; import org.eclipse.orion.server.core.LogHelper; import org.eclipse.orion.server.core.OrionConfiguration; import org.eclipse.orion.server.core.metastore.IMetaStore; import org.eclipse.orion.server.core.metastore.ProjectInfo; import org.eclipse.orion.server.core.metastore.UserInfo; import org.eclipse.orion.server.core.metastore.WorkspaceInfo; import org.eclipse.orion.server.tests.AbstractServerTest; import org.eclipse.orion.server.tests.ServerTestsActivator; import org.eclipse.orion.server.tests.servlets.internal.DeleteMethodWebRequest; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.xml.sax.SAXException; import com.meterware.httpunit.GetMethodWebRequest; import com.meterware.httpunit.PostMethodWebRequest; import com.meterware.httpunit.PutMethodWebRequest; import com.meterware.httpunit.WebConversation; import com.meterware.httpunit.WebRequest; import com.meterware.httpunit.WebResponse; /** * Common base class for file system tests. */ public abstract class FileSystemTest extends AbstractServerTest { public static final String FILE_SERVLET_LOCATION = "file/"; private static String FILESTORE_PREFIX; /** * Location of the test project within the file servlet namespace. */ protected String testProjectBaseLocation = ""; /** * The local file system location of the test project. */ protected String testProjectLocalFileLocation = ""; protected WebConversation webConversation; /** * Creates a test project with the given name. * @throws SAXException * @throws IOException */ protected void createTestProject(String name) throws Exception { //create workspace String workspaceName = getClass().getName() + "#" + name; URI workspaceLocation = createWorkspace(workspaceName); //create a project String projectName = name + "Project"; WebRequest request = getCreateProjectRequest(workspaceLocation, projectName, null); WebResponse response = webConversation.getResponse(request); if (response.getResponseCode() != HttpURLConnection.HTTP_CREATED) { String msg = "Unexpected " + response.getResponseCode() + " response creating project " + projectName + ": " + response.getText(); System.out.println(msg); LogHelper.log(new Status(IStatus.ERROR, ServerTestsActivator.PI_TESTS, msg)); fail(msg); } IPath workspacePath = new Path(workspaceLocation.getPath()); String workspaceId = new Path(workspaceLocation.getPath()).segment(workspacePath.segmentCount() - 1); testProjectBaseLocation = "/" + workspaceId + '/' + projectName; JSONObject project = new JSONObject(response.getText()); testProjectLocalFileLocation = "/" + project.optString(ProtocolConstants.KEY_ID, null); } protected boolean checkDirectoryExists(String path) throws CoreException { IFileStore dir = EFS.getStore(makeLocalPathAbsolute(path)); return (dir.fetchInfo().exists() && dir.fetchInfo().isDirectory()); } protected boolean checkFileExists(String path) throws CoreException { IFileStore file = EFS.getStore(makeLocalPathAbsolute(path)); return (file.fetchInfo().exists() && !file.fetchInfo().isDirectory()); } protected static void clearWorkspace() throws CoreException { IMetaStore store = OrionConfiguration.getMetaStore(); List<String> userIds = store.readAllUsers(); for (String userId : userIds) { IFileStore userHome = OrionConfiguration.getUserHome(userId); UserInfo user = store.readUser(userId); for (String workspaceId : user.getWorkspaceIds()) { WorkspaceInfo workspace = store.readWorkspace(workspaceId); List<String> projectNames = workspace.getProjectNames(); for (String projectName : projectNames) { ProjectInfo project = store.readProject(workspaceId, projectName); URI contentLocation = project.getContentLocation(); // delete the project folders IFileStore projectDir = EFS.getStore(contentLocation); if (userHome.isParentOf(projectDir)) { for (IFileStore child : projectDir.childStores(EFS.NONE, null)) { if (!child.getName().equals("project.json")) { child.delete(EFS.NONE, null); } } } // delete the project metadata store.deleteProject(workspaceId, projectName); } // delete the workspace metadata store.deleteWorkspace(userId, workspaceId); } } } /** * Allows a subclass test to insert a different base location for the file system contents * of that test. The return value should be an empty string, or a path with leading * slash and no trailing slash. */ protected String getTestBaseFileSystemLocation() { return testProjectLocalFileLocation; } /** * Allows a subclass test to insert a different base resource URI, such as the * workspace/project for that test. The return value should be an empty string, or a path with leading * slash and no trailing slash. */ protected String getTestBaseResourceURILocation() { return testProjectBaseLocation; } protected static File getWorkspaceRoot() throws CoreException { return EFS.getStore(URI.create(FILESTORE_PREFIX)).toLocalFile(EFS.NONE, null); } /** * Creates a new directory in the server's local file system at the root location for the file servlet. */ protected void createDirectory(String path) throws CoreException { IFileInfo info = null; URI location = makeLocalPathAbsolute(path); IFileStore dir = EFS.getStore(location); dir.mkdir(EFS.NONE, null); info = dir.fetchInfo(); assertTrue("Coudn't create directory " + path, info.exists() && info.isDirectory()); } protected static void createFile(URI uri, String fileContent) throws CoreException { IFileStore outputFile = EFS.getStore(uri); outputFile.delete(EFS.NONE, null); InputStream input = new ByteArrayInputStream(fileContent.getBytes()); transferData(input, outputFile.openOutputStream(EFS.NONE, null)); IFileInfo info = outputFile.fetchInfo(); assertTrue("Coudn't create file " + uri, info.exists() && !info.isDirectory()); } protected void createFile(String path, String fileContent) throws CoreException { createFile(makeLocalPathAbsolute(path), fileContent); } private String getAbsolutePath(String path) { String userRoot = OrionConfiguration.getUserHome(testUserId).toURI().toString() + "/"; String absolutePath; if (OrionConfiguration.getMetaStore() instanceof SimpleMetaStore) { // simple metastore, projects located in user/workspace/project Path basePath = new Path(getTestBaseResourceURILocation()); String workspaceId = basePath.segment(0); String workspaceName = SimpleMetaStoreUtil.decodeWorkspaceNameFromWorkspaceId(workspaceId); String projectName = basePath.segment(1); absolutePath = new Path(userRoot).append(workspaceName).append(projectName).append(path).toString(); } else { // legacy metastore, projects located in user/project absolutePath = new Path(userRoot).append(getTestBaseFileSystemLocation()).append(path).toString(); } return absolutePath; } protected URI makeLocalPathAbsolute(String path) { String absolutePath = getAbsolutePath(path); try { return URIUtil.fromString(absolutePath); } catch (URISyntaxException e) { fail(e.getMessage()); return null; } } protected static void initializeWorkspaceLocation() { IFileStore root = OrionConfiguration.getUserHome(null); FILESTORE_PREFIX = root.toURI().toString() + "/"; } protected void remove(String path) throws CoreException { String absolutePath = getAbsolutePath(path); IFileStore outputFile = EFS.getStore(URI.create(absolutePath)); outputFile.delete(EFS.NONE, null); } private static void transferData(InputStream input, OutputStream output) { try { try { int c = 0; while ((c = input.read()) != -1) output.write(c); } finally { input.close(); output.close(); } } catch (IOException e) { e.printStackTrace(); assertTrue(e.toString(), false); } } protected void checkDirectoryMetadata(JSONObject dirObject, String name, String path, Long localTimestamp, Boolean isReadonly, Boolean isExecutable, String location) throws JSONException { assertTrue("Expected directory but found file", dirObject.getBoolean(ProtocolConstants.KEY_DIRECTORY)); if (name != null) { assertEquals("Invalid directory name", name, dirObject.getString(ProtocolConstants.KEY_NAME)); } if (path != null) { assertEquals("Invalid directory path", path, dirObject.getString(ProtocolConstants.KEY_PATH)); } if (localTimestamp != null) { if (localTimestamp < 0) { assertNotNull("Directory timestamp should not be null", dirObject.getLong(ProtocolConstants.KEY_LOCAL_TIMESTAMP)); } else { assertEquals("Invalid directory timestamp", localTimestamp, new Long(dirObject.getLong(ProtocolConstants.KEY_LOCAL_TIMESTAMP))); } } if (location != null) { assertEquals("Invalid directory location", location, dirObject.getString(ProtocolConstants.KEY_LOCATION)); } if (isReadonly != null && isExecutable != null) { JSONObject attributes = dirObject.getJSONObject(ProtocolConstants.KEY_ATTRIBUTES); assertNotNull("Expected Attributes section in directory metadata", attributes); if (isReadonly != null) { assertEquals("Ibvalid directory readonly attribute", isReadonly, attributes.getBoolean(ProtocolConstants.KEY_ATTRIBUTE_READ_ONLY)); } if (isExecutable != null) { assertEquals("Invalid directory executable attribute", isExecutable, attributes.getBoolean(ProtocolConstants.KEY_ATTRIBUTE_EXECUTABLE)); } } } protected void checkFileMetadata(JSONObject fileObject, String name, Long localTimestamp, String charset, String contentType, String location, Long length, Boolean isReadonly, Boolean isExecutable, String parentName) throws JSONException { assertFalse("Expected file but found directory", fileObject.getBoolean(ProtocolConstants.KEY_DIRECTORY)); if (name != null) { assertEquals("Invalid file name", name, fileObject.getString(ProtocolConstants.KEY_NAME)); } if (localTimestamp != null) { if (localTimestamp < 0) { assertNotNull("File timestamp should not be null", fileObject.getLong(ProtocolConstants.KEY_LOCAL_TIMESTAMP)); } else { assertEquals("Invalid file timestamp", localTimestamp, new Long(fileObject.getLong(ProtocolConstants.KEY_LOCAL_TIMESTAMP))); } } if (charset != null) { assertEquals("Invalid file charset", charset, fileObject.getString("Charset")); } if (contentType != null) { assertEquals("Invalid file content type", contentType, fileObject.getString("ContentType")); } if (location != null) { assertEquals("Invalid file location", location, fileObject.getString(ProtocolConstants.KEY_LOCATION)); } if (length != null) { assertEquals("Invalid file length", length, new Long(fileObject.getLong(ProtocolConstants.KEY_LENGTH))); } if (isReadonly != null || isExecutable != null) { int attrs = EFS.getLocalFileSystem().attributes(); JSONObject attributes = fileObject.optJSONObject(ProtocolConstants.KEY_ATTRIBUTES); assertNotNull("Expected Attributes section in file metadata", attributes); if (isReadonly != null && ((attrs & EFS.ATTRIBUTE_READ_ONLY) != 0)) { assertEquals("Invalid file readonly attribute", isReadonly.booleanValue(), attributes.getBoolean(ProtocolConstants.KEY_ATTRIBUTE_READ_ONLY)); } if (isExecutable != null && ((attrs & EFS.ATTRIBUTE_EXECUTABLE) != 0)) { assertEquals("Invalid file executable attribute", isExecutable.booleanValue(), attributes.getBoolean(ProtocolConstants.KEY_ATTRIBUTE_EXECUTABLE)); } } if (parentName != null) { JSONArray parents = fileObject.getJSONArray(ProtocolConstants.KEY_PARENTS); assertNotNull("Expected Parents array in file metadata", parents); assertEquals("Expected single parent item", 1, parents.length()); JSONObject parent = parents.getJSONObject(0); assertNotNull("Invalid parent item", parent); assertEquals("Invalid file parent name", parentName, parent.get(ProtocolConstants.KEY_NAME)); } } protected WebRequest getDeleteFilesRequest(String uri) { WebRequest request = new DeleteMethodWebRequest(makeResourceURIAbsolute(uri)); request.setHeaderField(ProtocolConstants.HEADER_ORION_VERSION, "1"); setAuthentication(request); return request; } protected List<JSONObject> getDirectoryChildren(JSONObject dirObject) throws JSONException { assertTrue("Expected directory but found file", dirObject.getBoolean(ProtocolConstants.KEY_DIRECTORY)); List<JSONObject> children = new ArrayList<JSONObject>(); try { JSONArray chidrenArray = dirObject.getJSONArray(ProtocolConstants.KEY_CHILDREN); for (int i = 0; i < chidrenArray.length(); i++) { children.add(chidrenArray.getJSONObject(i)); } } catch (JSONException e) { // when no Children section attached return empty list } return children; } /** * Creates a request to get the resource at the given location. * @param location Either an absolute URI, or a workspace-relative URI */ protected WebRequest getGetFilesRequest(String location) { String requestURI = makeResourceURIAbsolute(location); WebRequest request = new GetMethodWebRequest(requestURI); request.setHeaderField(ProtocolConstants.HEADER_ORION_VERSION, "1"); setAuthentication(request); return request; } protected JSONObject getNewDirJSON(String dirName) throws JSONException { JSONObject json = new JSONObject(); json.put(ProtocolConstants.KEY_NAME, dirName); json.put(ProtocolConstants.KEY_DIRECTORY, true); return json; } protected JSONObject getNewFileJSON(String dirName) throws JSONException { JSONObject json = new JSONObject(); if (dirName != null) json.put(ProtocolConstants.KEY_NAME, dirName); json.put(ProtocolConstants.KEY_DIRECTORY, false); json.put("Charset", "UTF-8"); json.put("ContentType", "text/plain"); return json; } private static char hexDigit(int val) { return (val < 10) ? (char) ('0' + val) : (char) ('A' + val - 10); } /** * http://tools.ietf.org/html/rfc5023#section-9.7.1 * @param s * @return */ private static String encodeSlug(String s) { final byte percent = 0x25; try { byte bytes[] = s.getBytes("UTF-8"); StringBuilder buf = new StringBuilder(); for (int i = 0; i < bytes.length; i++) { byte b = bytes[i]; if (b < 0x20 || b > 0x7e || b == percent) { buf.append('%').append(hexDigit((b >> 4) & 0x0f)).append(hexDigit(b & 0x0f)); } else { buf.append((char) b); // ASCII } } return buf.toString(); } catch (UnsupportedEncodingException e) { // Should not happen return null; } } protected WebRequest getPostFilesRequest(String uri, String json, String slug) { try { WebRequest request = new PostMethodWebRequest(makeResourceURIAbsolute(uri), IOUtilities.toInputStream(json), "application/json"); request.setHeaderField(ProtocolConstants.HEADER_SLUG, encodeSlug(slug)); request.setHeaderField(ProtocolConstants.HEADER_ORION_VERSION, "1"); setAuthentication(request); return request; } catch (UnsupportedEncodingException e) { fail(e.getMessage()); } //can never get here return null; } protected WebRequest getPutFileRequest(String uri, String body) { try { WebRequest request = new PutMethodWebRequest(makeResourceURIAbsolute(uri), IOUtilities.toInputStream(body), "application/json"); request.setHeaderField(ProtocolConstants.HEADER_ORION_VERSION, "1"); setAuthentication(request); return request; } catch (UnsupportedEncodingException e) { fail(e.getMessage()); } //can never get here return null; } /** * Makes a URI absolute. If the provided URI is relative, it is assumed to be relative to the workspace location (file servlet location). * If the provided URI is already absolute it is returned as-is. * The provided URI must be correctly encoded. */ protected String makeResourceURIAbsolute(String uriString) { try { URI uri = new URI(uriString); if (uri.isAbsolute()) return uriString; if (uriString.startsWith("/")) { return toAbsoluteURI(uriString); } } catch (URISyntaxException e) { //unencoded string - fall through } try { if (uriString.startsWith(FILE_SERVLET_LOCATION)) return URIUtil.fromString(SERVER_LOCATION + uriString).toString(); //avoid double slash if (uriString.startsWith("/")) uriString = uriString.substring(1); String path = new Path(FILE_SERVLET_LOCATION).append(getTestBaseResourceURILocation()).append(uriString) .toString(); return new URI(SERVER_LOCATION + path).toString(); } catch (URISyntaxException e) { fail(e.getMessage()); return null; } } protected WebRequest getCreateWorkspaceRequest(String workspaceName) { WebRequest request = new PostMethodWebRequest(SERVER_LOCATION + "/workspace"); if (workspaceName != null) request.setHeaderField(ProtocolConstants.HEADER_SLUG, workspaceName); request.setHeaderField(ProtocolConstants.HEADER_ORION_VERSION, "1"); setAuthentication(request); return request; } protected WebRequest getCreateProjectRequest(URI workspaceLocation, String projectName, String projectLocation) throws JSONException, IOException { workspaceLocation = addSchemeHostPort(workspaceLocation); JSONObject body = new JSONObject(); if (projectLocation != null) body.put(ProtocolConstants.KEY_CONTENT_LOCATION, projectLocation); InputStream in = IOUtilities.toInputStream(body.toString()); WebRequest request = new PostMethodWebRequest(workspaceLocation.toString(), in, "UTF-8"); if (projectName != null) request.setHeaderField(ProtocolConstants.HEADER_SLUG, projectName); request.setHeaderField(ProtocolConstants.HEADER_ORION_VERSION, "1"); setAuthentication(request); return request; } protected URI addSchemeHostPort(URI uri) { String scheme = uri.getScheme(); String host = uri.getHost(); int port = uri.getPort(); if (scheme == null) { scheme = "http"; } if (host == null) { host = "localhost"; } if (port == -1) { port = 8080; } try { return new URI(scheme, uri.getUserInfo(), host, port, uri.getPath(), uri.getQuery(), uri.getFragment()); } catch (URISyntaxException e) { throw new RuntimeException(e); } } /** * Creates a new workspace, and returns the raw response object. */ protected WebResponse basicCreateWorkspace(String workspaceName) throws IOException, SAXException { WebRequest request = getCreateWorkspaceRequest(workspaceName); WebResponse response = webConversation.getResponse(request); assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode()); return response; } /** * Creates a new workspace, and returns the URI of the resulting resource. */ protected URI createWorkspace(String workspaceName) throws IOException, SAXException { WebResponse response = basicCreateWorkspace(workspaceName); return SERVER_URI.resolve(response.getHeaderField(ProtocolConstants.HEADER_LOCATION)); } }