/* * Copyright 2014 EMC Corporation. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. * A copy of the License is located at * * http://www.apache.org/licenses/LICENSE-2.0.txt * * or in the "license" file accompanying this file. This file 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 com.emc.esu.test; import com.emc.atmos.util.RandomInputStream; import com.emc.esu.api.*; import com.emc.esu.api.Checksum.Algorithm; import com.emc.esu.api.rest.DownloadHelper; import com.emc.esu.api.rest.UploadHelper; import org.apache.commons.codec.binary.Base64; import org.apache.log4j.Logger; import org.junit.After; import org.junit.Assert; import org.junit.Assume; import org.junit.Ignore; import org.junit.Test; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.io.*; import java.net.URL; import java.net.URLEncoder; import java.util.*; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * Implements testcases that are independent of the protocol (REST vs. SOAP). * Note that this class does not implement TestCase; it is called by the * REST and SOAP testcases. */ @SuppressWarnings("deprecation") public abstract class EsuApiTest { public static Logger l4j = Logger.getLogger( EsuApiTest.class ); /** * Use this as a prefix for namespace object paths and you won't have to clean up after yourself. * This also keeps all test objects under one folder, which is easy to delete should something go awry. */ protected static final String TEST_DIR_PREFIX = "/test_" + EsuApiTest.class.getSimpleName(); protected EsuApi esu; protected String uid; protected List<Identifier> cleanup = Collections.synchronizedList( new ArrayList<Identifier>() ); protected List<ObjectPath> cleanupDirs = Collections.synchronizedList( new ArrayList<ObjectPath>() ); protected boolean isVipr; /** * Tear down after a test is run. Cleans up objects that were created * during the test. Set cleanUp=false to disable this behavior. */ @After public void tearDown() { for (Identifier cleanItem : cleanup) { try { this.esu.deleteObject(cleanItem); } catch (Exception e) { System.out.println("Failed to delete " + cleanItem + ": " + e.getMessage()); } } try { // if test directories exists, recursively delete them for ( ObjectPath testDir : cleanupDirs ) { deleteRecursively( testDir ); } } catch ( EsuException e ) { if ( e.getHttpCode() != 404 ) { l4j.warn( "Could not delete test dir: ", e ); } } } protected void deleteRecursively( ObjectPath path ) { if ( path.isDirectory() ) { for ( DirectoryEntry entry : this.esu.listDirectory( path, null ) ) { deleteRecursively( entry.getPath() ); } } this.esu.deleteObject( path ); } protected ObjectPath createTestDir( String name ) { if (!name.endsWith("/")) name = name + "/"; ObjectPath path = new ObjectPath( TEST_DIR_PREFIX + "_" + name ); this.esu.createObjectOnPath( path, null, null, null, null ); cleanupDirs.add( path ); return path; } // // TESTS START HERE // @Test public void testUtf8JavaEncoding() throws Exception { String oneByteCharacters = "Hello"; String twoByteCharacters = "\u0410\u0411\u0412\u0413"; // Cyrillic letters String twoByteEscaped = "%D0%90%D0%91%D0%92%D0%93"; String fourByteCharacters = "\ud841\udf0e\ud841\udf31\ud841\udf79\ud843\udc53"; // Chinese symbols String fourByteEscaped = "%F0%A0%9C%8E%F0%A0%9C%B1%F0%A0%9D%B9%F0%A0%B1%93"; Assert.assertEquals( "2-byte characters failed", URLEncoder.encode( twoByteCharacters, "UTF-8" ), twoByteEscaped ); Assert.assertEquals( "4-byte characters failed", URLEncoder.encode( fourByteCharacters, "UTF-8" ), fourByteEscaped ); Assert.assertEquals( "2-byte/4-byte mix failed", URLEncoder.encode( twoByteCharacters + fourByteCharacters, "UTF-8" ), twoByteEscaped + fourByteEscaped ); Assert.assertEquals( "1-byte/2-byte mix failed", URLEncoder.encode( oneByteCharacters + twoByteCharacters, "UTF-8" ), oneByteCharacters + twoByteEscaped ); Assert.assertEquals( "1-4 byte mix failed", URLEncoder.encode( oneByteCharacters + twoByteCharacters + fourByteCharacters, "UTF-8" ), oneByteCharacters + twoByteEscaped + fourByteEscaped ); } /** * Test creating one empty object. No metadata, no content. */ @Test public void testCreateEmptyObject() throws Exception { ObjectId id = this.esu.createObject( null, null, null, null ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); // Read back the content String content = new String( this.esu.readObject( id, null, null ), "UTF-8" ); Assert.assertEquals( "object content wrong", "", content ); } /** * Test creating one empty object on a path. No metadata, no content. */ @Test public void testCreateEmptyObjectOnPath() throws Exception { ObjectPath op = new ObjectPath( "/" + rand8char() ); ObjectId id = this.esu.createObjectOnPath( op, null, null, null, null ); cleanup.add( op ); l4j.debug( "Path: " + op + " ID: " + id ); Assert.assertNotNull( id ); // Read back the content String content = new String( this.esu.readObject( op, null, null ), "UTF-8" ); Assert.assertEquals( "object content wrong", "", content ); content = new String( this.esu.readObject( id, null, null ), "UTF-8" ); Assert.assertEquals( "object content wrong when reading by id", "", content ); } /** * Tests using some extended characters when creating on a path. This particular test * uses one cryllic, one accented, and one japanese character. */ @Test public void testUnicodePath() throws Exception { String dirName = rand8char(); ObjectPath path = new ObjectPath( "/" + dirName + "/бöシ.txt" ); ObjectId id = this.esu.createObjectOnPath( path, null, null, null, null ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); ObjectPath parent = new ObjectPath( "/" + dirName + "/" ); List<DirectoryEntry> ents = this.esu.listDirectory( parent, null ); boolean found = false; for ( DirectoryEntry ent : ents ) { if ( ent.getPath().equals( path ) ) { found = true; } } Assert.assertTrue( "Did not find unicode file in dir", found ); // Check read this.esu.readObject( path, null, null ); } /** * Tests using some extra characters that might break URIs */ @Test public void testExtraPath() throws Exception { ObjectPath path = new ObjectPath( "/" + rand8char() + "/a+=- _!#$%^&*(),.z.txt" ); //ObjectPath path = new ObjectPath("/zimbramailbox/c8b4/511a-63c4-4ac9-8ff7+1c578de044be/stage/3r0sFrgUgL2ApCSkl3pobSX9D+k-1"); byte[] data = "Hello World".getBytes( "UTF-8" ); InputStream in = new ByteArrayInputStream( data ); ObjectId id = this.esu.createObjectFromStreamOnPath( path, null, null, in, data.length, null ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); } @Test public void testUtf8Path() throws Exception { String oneByteCharacters = "Hello! ,"; String twoByteCharacters = "\u0410\u0411\u0412\u0413"; // Cyrillic letters String fourByteCharacters = "\ud841\udf0e\ud841\udf31\ud841\udf79\ud843\udc53"; // Chinese symbols String crazyName = oneByteCharacters + twoByteCharacters + fourByteCharacters; byte[] content = "Crazy name creation test.".getBytes( "UTF-8" ); ObjectPath parentDir = createTestDir("Utf8Path"); ObjectPath path = new ObjectPath( parentDir + crazyName ); // create crazy-name object this.esu.createObjectOnPath( path, null, null, content, "text/plain" ); cleanup.add(path); // verify name in directory list boolean found = false; for ( DirectoryEntry entry : this.esu.listDirectory( parentDir, null ) ) { if ( entry.getPath().toString().equals( path.toString() ) ) { found = true; break; } } Assert.assertTrue( "crazyName not found in directory listing", found ); // verify content Assert.assertTrue( "content does not match", Arrays.equals( content, this.esu.readObject( path, null, null ) ) ); } @Test public void testUtf8Content() throws Exception { String oneByteCharacters = "Hello! ,"; String twoByteCharacters = "\u0410\u0411\u0412\u0413"; // Cyrillic letters String fourByteCharacters = "\ud841\udf0e\ud841\udf31\ud841\udf79\ud843\udc53"; // Chinese symbols byte[] content = (oneByteCharacters + twoByteCharacters + fourByteCharacters).getBytes( "UTF-8" ); ObjectPath parentDir = createTestDir("Utf8Content"); ObjectPath path = new ObjectPath( parentDir.getName() + "/" + "utf8Content.txt" ); // create object with multi-byte UTF-8 content this.esu.createObjectOnPath( path, null, null, content, "text/plain" ); // verify content Assert.assertTrue( "content does not match", Arrays.equals( content, this.esu.readObject( path, null, null ) ) ); } protected String rand8char() { Random r = new Random(); StringBuffer sb = new StringBuffer( 8 ); for ( int i = 0; i < 8; i++ ) { sb.append( (char) ('a' + r.nextInt( 26 )) ); } return sb.toString(); } /** * Test creating an object with content but without metadata */ @Test public void testCreateObjectWithContent() throws Exception { ObjectId id = this.esu.createObject( null, null, "hello".getBytes( "UTF-8" ), "text/plain" ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); // Read back the content String content = new String( this.esu.readObject( id, null, null ), "UTF-8" ); Assert.assertEquals( "object content wrong", "hello", content ); } @Test public void testCreateObjectWithContentStream() throws Exception { InputStream in = new ByteArrayInputStream( "hello".getBytes( "UTF-8" ) ); ObjectId id = this.esu.createObjectFromStream( null, null, in, 5, "text/plain" ); in.close(); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); // Read back the content String content = new String( this.esu.readObject( id, null, null ), "UTF-8" ); Assert.assertEquals( "object content wrong", "hello", content ); } @Test public void testCreateObjectWithContentStreamOnPath() throws Exception { ObjectPath op = new ObjectPath( "/" + rand8char() + ".tmp" ); InputStream in = new ByteArrayInputStream( "hello".getBytes( "UTF-8" ) ); ObjectId id = this.esu.createObjectFromStreamOnPath( op, null, null, in, 5, "text/plain" ); in.close(); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); // Read back the content String content = new String( this.esu.readObject( id, null, null ), "UTF-8" ); Assert.assertEquals( "object content wrong", "hello", content ); } /** * Test creating an object with metadata but no content. */ @Test public void testCreateObjectWithMetadataOnPath() { ObjectPath op = new ObjectPath( "/" + rand8char() + ".tmp" ); MetadataList mlist = new MetadataList(); Metadata listable = new Metadata( "listable", "foo", true ); Metadata unlistable = new Metadata( "unlistable", "bar", false ); Metadata listable2 = new Metadata( "listable2", "foo2 foo2", true ); Metadata unlistable2 = new Metadata( "unlistable2", "bar2 bar2", false ); mlist.addMetadata( listable ); mlist.addMetadata( unlistable ); mlist.addMetadata( listable2 ); mlist.addMetadata( unlistable2 ); ObjectId id = this.esu.createObjectOnPath( op, null, mlist, null, null ); //this.esu.updateObject( op, null, mlist, null, null, null ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( op ); // Read and validate the metadata MetadataList meta = this.esu.getUserMetadata( op, null ); Assert.assertNotNull( "value of 'listable' missing", meta.getMetadata( "listable" ) ); Assert.assertNotNull( "value of 'listable2' missing", meta.getMetadata( "listable2" ) ); Assert.assertNotNull( "value of 'unlistable' missing", meta.getMetadata( "unlistable" ) ); Assert.assertNotNull( "value of 'unlistable2' missing", meta.getMetadata( "unlistable2" ) ); Assert.assertEquals( "value of 'listable' wrong", "foo", meta.getMetadata( "listable" ).getValue() ); Assert.assertEquals( "value of 'listable2' wrong", "foo2 foo2", meta.getMetadata( "listable2" ).getValue() ); Assert.assertEquals( "value of 'unlistable' wrong", "bar", meta.getMetadata( "unlistable" ).getValue() ); Assert.assertEquals( "value of 'unlistable2' wrong", "bar2 bar2", meta.getMetadata( "unlistable2" ).getValue() ); // Check listable flags Assert.assertEquals( "'listable' is not listable", true, meta.getMetadata( "listable" ).isListable() ); Assert.assertEquals( "'listable2' is not listable", true, meta.getMetadata( "listable2" ).isListable() ); Assert.assertEquals( "'unlistable' is listable", false, meta.getMetadata( "unlistable" ).isListable() ); Assert.assertEquals( "'unlistable2' is listable", false, meta.getMetadata( "unlistable2" ).isListable() ); } /** * Test creating an object with metadata but no content. */ @Test public void testCreateObjectWithMetadata() { MetadataList mlist = new MetadataList(); Metadata listable = new Metadata( "listable", "foo", true ); Metadata unlistable = new Metadata( "unlistable", "bar", false ); Metadata listable2 = new Metadata( "listable2", "foo2 foo2", true ); Metadata unlistable2 = new Metadata( "unlistable2", "bar2 bar2", false ); Metadata listable3 = new Metadata( "listable3", null, true ); Metadata quotes = new Metadata("ST_modalities", "\\US\\", false); //Metadata withCommas = new Metadata( "withcommas", "I, Robot", false ); //Metadata withEquals = new Metadata( "withequals", "name=value", false ); mlist.addMetadata( listable ); mlist.addMetadata( unlistable ); mlist.addMetadata( listable2 ); mlist.addMetadata( unlistable2 ); mlist.addMetadata( listable3 ); mlist.addMetadata(quotes); //mlist.addMetadata( withCommas ); //mlist.addMetadata( withEquals ); ObjectId id = this.esu.createObject( null, mlist, null, null ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); // Read and validate the metadata MetadataList meta = this.esu.getUserMetadata( id, null ); Assert.assertEquals( "value of 'listable' wrong", "foo", meta.getMetadata( "listable" ).getValue() ); Assert.assertEquals( "value of 'listable2' wrong", "foo2 foo2", meta.getMetadata( "listable2" ).getValue() ); Assert.assertEquals( "value of 'unlistable' wrong", "bar", meta.getMetadata( "unlistable" ).getValue() ); Assert.assertEquals( "value of 'unlistable2' wrong", "bar2 bar2", meta.getMetadata( "unlistable2" ).getValue() ); Assert.assertNotNull( "listable3 missing", meta.getMetadata( "listable3" ) ); Assert.assertTrue( "Value of listable3 should be empty", meta.getMetadata( "listable3" ).getValue() == null || meta.getMetadata( "listable3" ).getValue().length() == 0 ); //Assert.assertEquals( "Value of withcommas wrong", "I, Robot", meta.getMetadata( "withcommas" ).getValue() ); //Assert.assertEquals( "Value of withequals wrong", "name=value", meta.getMetadata( "withequals" ).getValue() ); // Check listable flags Assert.assertEquals( "'listable' is not listable", true, meta.getMetadata( "listable" ).isListable() ); Assert.assertEquals( "'listable2' is not listable", true, meta.getMetadata( "listable2" ).isListable() ); Assert.assertEquals( "'listable3' is not listable", true, meta.getMetadata( "listable3" ).isListable() ); Assert.assertEquals( "'unlistable' is listable", false, meta.getMetadata( "unlistable" ).isListable() ); Assert.assertEquals( "'unlistable2' is listable", false, meta.getMetadata( "unlistable2" ).isListable() ); } /** * Test creating an object with metadata but no content. */ @Test public void testMetadataNormalizeSpace() { MetadataList mlist = new MetadataList(); Metadata unlistable = new Metadata( "unlistable", "bar bar bar bar", false ); Metadata leadingSpacesOdd = new Metadata( "leadingodd", " spaces", false); Metadata trailingSpacesOdd = new Metadata( "trailingodd", "spaces ", false); Metadata leadingSpacesEven = new Metadata( "leadingeven", " SPACES", false); Metadata trailingSpacesEven = new Metadata( "trailingeven", "spaces ", false); mlist.addMetadata( unlistable ); mlist.addMetadata( leadingSpacesOdd ); mlist.addMetadata( trailingSpacesOdd ); mlist.addMetadata( leadingSpacesEven); mlist.addMetadata( trailingSpacesEven); ObjectId id = this.esu.createObject( null, mlist, null, null ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); // Read and validate the metadata MetadataList meta = this.esu.getUserMetadata( id, null ); Assert.assertEquals( "value of 'unlistable' wrong", "bar bar bar bar", meta.getMetadata( "unlistable" ).getValue() ); // Check listable flags Assert.assertEquals( "'unlistable' is listable", false, meta.getMetadata( "unlistable" ).isListable() ); } /** * Test reading an object's content */ @Test public void testReadObject() throws Exception { ObjectId id = this.esu.createObject( null, null, "hello".getBytes( "UTF-8" ), "text/plain" ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); // Read back the content String content = new String( this.esu.readObject( id, null, null ), "UTF-8" ); Assert.assertEquals( "object content wrong", "hello", content ); // Read back only 2 bytes Extent extent = new Extent( 1, 2 ); content = new String( this.esu.readObject( id, extent, null ), "UTF-8" ); Assert.assertEquals( "partial object content wrong", "el", content ); } /** * Test reading an ACL back */ @Test public void testReadAcl() { // Create an object with an ACL Acl acl = new Acl(); acl.addGrant( new Grant( new Grantee( stripUid( uid ), Grantee.GRANT_TYPE.USER ), Permission.FULL_CONTROL ) ); acl.addGrant( new Grant( Grantee.OTHER, Permission.READ ) ); ObjectId id = this.esu.createObject( acl, null, null, null ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); // Read back the ACL and make sure it matches Acl newacl = this.esu.getAcl( id ); l4j.info( "Comparing " + newacl + " with " + acl ); Assert.assertEquals( "ACLs don't match", acl, newacl ); } /** * Inside an ACL, you use the UID only, not SubtenantID/UID * * @param uid * @return */ private String stripUid( String uid ) { int slash = uid.indexOf( '/' ); if ( slash != -1 ) { return uid.substring( slash + 1 ); } else { return uid; } } @Test public void testReadAclByPath() { ObjectPath op = new ObjectPath( "/" + rand8char() + ".tmp" ); // Create an object with an ACL Acl acl = new Acl(); acl.addGrant( new Grant( new Grantee( stripUid( uid ), Grantee.GRANT_TYPE.USER ), Permission.FULL_CONTROL ) ); acl.addGrant( new Grant( Grantee.OTHER, Permission.READ ) ); ObjectId id = this.esu.createObjectOnPath( op, acl, null, null, null ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( op ); // Read back the ACL and make sure it matches Acl newacl = this.esu.getAcl( op ); l4j.info( "Comparing " + newacl + " with " + acl ); Assert.assertEquals( "ACLs don't match", acl, newacl ); } /** * Test reading back user metadata */ @Test public void testGetUserMetadata() { // Create an object with user metadata MetadataList mlist = new MetadataList(); Metadata listable = new Metadata( "listable", "foo", true ); Metadata unlistable = new Metadata( "unlistable", "bar", false ); Metadata listable2 = new Metadata( "listable2", "foo2 foo2", true ); Metadata unlistable2 = new Metadata( "unlistable2", "bar2 bar2", false ); mlist.addMetadata( listable ); mlist.addMetadata( unlistable ); mlist.addMetadata( listable2 ); mlist.addMetadata( unlistable2 ); ObjectId id = this.esu.createObject( null, mlist, null, null ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); // Read only part of the metadata MetadataTags mtags = new MetadataTags(); mtags.addTag( new MetadataTag( "listable", true ) ); mtags.addTag( new MetadataTag( "unlistable", false ) ); MetadataList meta = this.esu.getUserMetadata( id, mtags ); Assert.assertEquals( "value of 'listable' wrong", "foo", meta.getMetadata( "listable" ).getValue() ); Assert.assertNull( "value of 'listable2' should not have been returned", meta.getMetadata( "listable2" ) ); Assert.assertEquals( "value of 'unlistable' wrong", "bar", meta.getMetadata( "unlistable" ).getValue() ); Assert.assertNull( "value of 'unlistable2' should not have been returned", meta.getMetadata( "unlistable2" ) ); } /** * Test deleting user metadata */ @Test public void testDeleteUserMetadata() { // Create an object with metadata MetadataList mlist = new MetadataList(); Metadata listable = new Metadata( "listable", "foo", true ); Metadata unlistable = new Metadata( "unlistable", "bar", false ); Metadata listable2 = new Metadata( "listable2", "foo2 foo2", true ); Metadata unlistable2 = new Metadata( "unlistable2", "bar2 bar2", false ); mlist.addMetadata( listable ); mlist.addMetadata( unlistable ); mlist.addMetadata( listable2 ); mlist.addMetadata( unlistable2 ); ObjectId id = this.esu.createObject( null, mlist, null, null ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); // Delete a couple of the metadata entries MetadataTags mtags = new MetadataTags(); mtags.addTag( new MetadataTag( "listable2", true ) ); mtags.addTag( new MetadataTag( "unlistable2", false ) ); this.esu.deleteUserMetadata( id, mtags ); // Read back the metadata for the object and ensure the deleted // entries don't exist MetadataList meta = this.esu.getUserMetadata( id, null ); Assert.assertEquals( "value of 'listable' wrong", "foo", meta.getMetadata( "listable" ).getValue() ); Assert.assertNull( "value of 'listable2' should not have been returned", meta.getMetadata( "listable2" ) ); Assert.assertEquals( "value of 'unlistable' wrong", "bar", meta.getMetadata( "unlistable" ).getValue() ); Assert.assertNull( "value of 'unlistable2' should not have been returned", meta.getMetadata( "unlistable2" ) ); } /** * Test creating object versions */ @Test public void testVersionObject() { Assume.assumeFalse(isVipr); // Create an object MetadataList mlist = new MetadataList(); Metadata listable = new Metadata( "listable", "foo", true ); Metadata unlistable = new Metadata( "unlistable", "bar", false ); Metadata listable2 = new Metadata( "listable2", "foo2 foo2", true ); Metadata unlistable2 = new Metadata( "unlistable2", "bar2 bar2", false ); mlist.addMetadata( listable ); mlist.addMetadata( unlistable ); mlist.addMetadata( listable2 ); mlist.addMetadata( unlistable2 ); ObjectId id = this.esu.createObject( null, mlist, null, null ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); // Version the object ObjectId vid = this.esu.versionObject( id ); cleanup.add( vid ); Assert.assertNotNull( "null version ID returned", vid ); Assert.assertFalse( "Version ID shoudn't be same as original ID", id.equals( vid ) ); // Fetch the version and read its data MetadataList meta = this.esu.getUserMetadata( vid, null ); Assert.assertEquals( "value of 'listable' wrong", "foo", meta.getMetadata( "listable" ).getValue() ); Assert.assertEquals( "value of 'listable2' wrong", "foo2 foo2", meta.getMetadata( "listable2" ).getValue() ); Assert.assertEquals( "value of 'unlistable' wrong", "bar", meta.getMetadata( "unlistable" ).getValue() ); Assert.assertEquals( "value of 'unlistable2' wrong", "bar2 bar2", meta.getMetadata( "unlistable2" ).getValue() ); } /** * Test listing the versions of an object */ @Test public void testListVersions() { Assume.assumeFalse(isVipr); // Create an object MetadataList mlist = new MetadataList(); Metadata listable = new Metadata( "listable", "foo", true ); Metadata unlistable = new Metadata( "unlistable", "bar", false ); Metadata listable2 = new Metadata( "listable2", "foo2 foo2", true ); Metadata unlistable2 = new Metadata( "unlistable2", "bar2 bar2", false ); mlist.addMetadata( listable ); mlist.addMetadata( unlistable ); mlist.addMetadata( listable2 ); mlist.addMetadata( unlistable2 ); ObjectId id = this.esu.createObject( null, mlist, null, null ); Assert.assertNotNull( "null ID returned", id ); // Version the object ObjectId vid1 = this.esu.versionObject( id ); Assert.assertNotNull( "null version ID returned", vid1 ); ObjectId vid2 = this.esu.versionObject( id ); Assert.assertNotNull( "null version ID returned", vid2 ); cleanup.add( id ); // List the versions and ensure their IDs are correct List<Identifier> versions = this.esu.listVersions( id ); Assert.assertEquals( "Wrong number of versions returned", 2, versions.size() ); Assert.assertTrue( "version 1 not found in version list", versions.contains( vid1 ) ); Assert.assertTrue( "version 2 not found in version list", versions.contains( vid2 ) ); } /** * Test listing the versions of an object */ @Test public void testListVersionsLong() { Assume.assumeFalse(isVipr); // Create an object MetadataList mlist = new MetadataList(); Metadata listable = new Metadata( "listable", "foo", true ); Metadata unlistable = new Metadata( "unlistable", "bar", false ); Metadata listable2 = new Metadata( "listable2", "foo2 foo2", true ); Metadata unlistable2 = new Metadata( "unlistable2", "bar2 bar2", false ); mlist.addMetadata( listable ); mlist.addMetadata( unlistable ); mlist.addMetadata( listable2 ); mlist.addMetadata( unlistable2 ); ObjectId id = this.esu.createObject( null, mlist, null, null ); Assert.assertNotNull( "null ID returned", id ); // Version the object ObjectId vid1 = this.esu.versionObject( id ); Version v1 = new Version(vid1, 0, null); Assert.assertNotNull( "null version ID returned", vid1 ); ObjectId vid2 = this.esu.versionObject( id ); Version v2 = new Version(vid2, 1, null); Assert.assertNotNull( "null version ID returned", vid2 ); cleanup.add( id ); // List the versions and ensure their IDs are correct ListOptions options = new ListOptions(); options.setLimit(1); List<Version> versions = new ArrayList<Version>(); do { versions.addAll(this.esu.listVersions( id, options )); } while(options.getToken() != null); Assert.assertEquals( "Wrong number of versions returned", 2, versions.size() ); Assert.assertTrue( "version 1 not found in version list", versions.contains( v1 ) ); Assert.assertTrue( "version 2 not found in version list", versions.contains( v2 ) ); for(Version v : versions) { Assert.assertNotNull("oid null in version", v.getId()); Assert.assertTrue("Invalid version number in version", v.getVersionNumber()>-1); Assert.assertNotNull("itime null in version", v.getItime()); } } /** * Test listing the versions of an object */ @Test public void testDeleteVersion() { Assume.assumeFalse(isVipr); // Create an object MetadataList mlist = new MetadataList(); Metadata listable = new Metadata( "listable", "foo", true ); Metadata unlistable = new Metadata( "unlistable", "bar", false ); Metadata listable2 = new Metadata( "listable2", "foo2 foo2", true ); Metadata unlistable2 = new Metadata( "unlistable2", "bar2 bar2", false ); mlist.addMetadata( listable ); mlist.addMetadata( unlistable ); mlist.addMetadata( listable2 ); mlist.addMetadata( unlistable2 ); ObjectId id = this.esu.createObject(null, mlist, null, null); Assert.assertNotNull( "null ID returned", id ); // Version the object ObjectId vid1 = this.esu.versionObject( id ); Assert.assertNotNull( "null version ID returned", vid1 ); ObjectId vid2 = this.esu.versionObject( id ); Assert.assertNotNull( "null version ID returned", vid2 ); cleanup.add( id ); // List the versions and ensure their IDs are correct List<Identifier> versions = this.esu.listVersions( id ); Assert.assertEquals( "Wrong number of versions returned", 2, versions.size() ); Assert.assertTrue( "version 1 not found in version list", versions.contains( vid1 ) ); Assert.assertTrue( "version 2 not found in version list", versions.contains( vid2 ) ); // Delete a version this.esu.deleteVersion( vid1 ); versions = this.esu.listVersions( id ); Assert.assertEquals( "Wrong number of versions returned", 1, versions.size() ); Assert.assertFalse( "version 1 found in version list", versions.contains( vid1 ) ); Assert.assertTrue( "version 2 not found in version list", versions.contains( vid2 ) ); } @Test public void testRestoreVersion() throws UnsupportedEncodingException { Assume.assumeFalse(isVipr); ObjectId id = this.esu.createObject( null, null, "Base Version Content".getBytes( "UTF-8" ), "text/plain" ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); // Version the object ObjectId vId = this.esu.versionObject( id ); // Update the object content this.esu.updateObject( id, null, null, null, "Child Version Content -- You should never see me".getBytes( "UTF-8" ), "text/plain" ); // Restore the original version this.esu.restoreVersion( id, vId ); // Read back the content String content = new String( this.esu.readObject( id, null, null ), "UTF-8" ); Assert.assertEquals( "object content wrong", "Base Version Content", content ); } /** * Test listing the system metadata on an object */ @Test public void testGetSystemMetadata() { // Create an object MetadataList mlist = new MetadataList(); Metadata listable = new Metadata( "listable", "foo", true ); Metadata unlistable = new Metadata( "unlistable", "bar", false ); Metadata listable2 = new Metadata( "listable2", "foo2 foo2", true ); Metadata unlistable2 = new Metadata( "unlistable2", "bar2 bar2", false ); mlist.addMetadata( listable ); mlist.addMetadata( unlistable ); mlist.addMetadata( listable2 ); mlist.addMetadata( unlistable2 ); ObjectId id = this.esu.createObject( null, mlist, null, null ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); // Read only part of the metadata MetadataTags mtags = new MetadataTags(); mtags.addTag( new MetadataTag( "atime", false ) ); mtags.addTag( new MetadataTag( "ctime", false ) ); MetadataList meta = this.esu.getSystemMetadata( id, mtags ); Assert.assertNotNull( "value of 'atime' missing", meta.getMetadata( "atime" ) ); Assert.assertNull( "value of 'mtime' should not have been returned", meta.getMetadata( "mtime" ) ); Assert.assertNotNull( "value of 'ctime' missing", meta.getMetadata( "ctime" ) ); Assert.assertNull( "value of 'gid' should not have been returned", meta.getMetadata( "gid" ) ); Assert.assertNull( "value of 'listable' should not have been returned", meta.getMetadata( "listable" ) ); } /** * Test listing objects by a tag that doesn't exist */ @Test public void testListObjectsNoExist() { ListOptions options = new ListOptions(); List<ObjectResult> objects = this.esu.listObjects( "this_tag_should_not_exist", options ); Assert.assertNotNull( "object list should be not null", objects ); Assert.assertEquals( "No objects should be returned", 0, objects.size() ); } /** * Test listing objects by a tag */ @Test public void testListObjects() { // Create an object MetadataList mlist = new MetadataList(); Metadata listable = new Metadata( "listable", "foo", true ); Metadata unlistable = new Metadata( "unlistable", "bar", false ); Metadata listable2 = new Metadata( "list/able/2", "foo2 foo2", true ); Metadata unlistable2 = new Metadata( "list/able/not", "bar2 bar2", false ); mlist.addMetadata( listable ); mlist.addMetadata( unlistable ); mlist.addMetadata( listable2 ); mlist.addMetadata( unlistable2 ); ObjectId id = this.esu.createObject( null, mlist, null, null ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); // List the objects. Make sure the one we created is in the list List<ObjectResult> objects = this.esu.listObjects( "listable", null ); Assert.assertTrue( "No objects returned", objects.size() > 0 ); Assert.assertTrue( "object not found in list", objects.contains( id ) ); } /** * Test listing objects by a tag */ @Test public void testListObjectsWithMetadata() { // Create an object MetadataList mlist = new MetadataList(); Metadata listable = new Metadata( "listable", "foo", true ); Metadata unlistable = new Metadata( "unlistable", "bar", false ); Metadata listable2 = new Metadata( "list/able/2", "foo2 foo2", true ); Metadata unlistable2 = new Metadata( "list/able/not", "bar2 bar2", false ); mlist.addMetadata( listable ); mlist.addMetadata( unlistable ); mlist.addMetadata( listable2 ); mlist.addMetadata( unlistable2 ); ObjectId id = this.esu.createObject( null, mlist, null, null ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); // List the objects. Make sure the one we created is in the list ListOptions options = new ListOptions(); options.setIncludeMetadata( true ); List<ObjectResult> objects = this.esu.listObjects( "listable", options ); Assert.assertTrue( "No objects returned", objects.size() > 0 ); // Find the item. boolean found = false; for ( Iterator<ObjectResult> i = objects.iterator(); i.hasNext(); ) { ObjectResult or = i.next(); if ( or.getId().equals( id ) ) { found = true; // check metadata Assert.assertEquals( "Wrong value on metadata", or.getMetadata().getMetadata( "listable" ).getValue(), "foo" ); } } Assert.assertTrue( "object not found in list", found ); } /** * Test listing objects by a tag, with only some of the metadata */ @Test public void testListObjectsWithSomeMetadata() { // Create an object MetadataList mlist = new MetadataList(); Metadata listable = new Metadata( "listable", "foo", true ); Metadata unlistable = new Metadata( "unlistable", "bar", false ); Metadata listable2 = new Metadata( "list/able/2", "foo2 foo2", true ); Metadata unlistable2 = new Metadata( "list/able/not", "bar2 bar2", false ); mlist.addMetadata( listable ); mlist.addMetadata( unlistable ); mlist.addMetadata( listable2 ); mlist.addMetadata( unlistable2 ); ObjectId id = this.esu.createObject( null, mlist, null, null ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); // List the objects. Make sure the one we created is in the list ListOptions options = new ListOptions(); options.setIncludeMetadata( true ); options.setUserMetadata( Arrays.asList( new String[]{"listable"} ) ); List<ObjectResult> objects = this.esu.listObjects( "listable", options ); Assert.assertTrue( "No objects returned", objects.size() > 0 ); // Find the item. boolean found = false; for ( Iterator<ObjectResult> i = objects.iterator(); i.hasNext(); ) { ObjectResult or = i.next(); if ( or.getId().equals( id ) ) { found = true; // check metadata Assert.assertEquals( "Wrong value on metadata", or.getMetadata().getMetadata( "listable" ).getValue(), "foo" ); // Other metadata should not be present Assert.assertNull( "unlistable should be missing", or.getMetadata().getMetadata( "unlistable" ) ); } } Assert.assertTrue( "object not found in list", found ); } /** * Test listing objects by a tag, paging the results */ @Test public void testListObjectsPaged() { // Create two objects. MetadataList mlist = new MetadataList(); Metadata listable = new Metadata( "listable", "foo", true ); mlist.addMetadata( listable ); ObjectId id1 = this.esu.createObject( null, mlist, null, null ); ObjectId id2 = this.esu.createObject( null, mlist, null, null ); Assert.assertNotNull( "null ID returned", id1 ); Assert.assertNotNull( "null ID returned", id2 ); cleanup.add( id1 ); cleanup.add( id2 ); // List the objects. Make sure the one we created is in the list ListOptions options = new ListOptions(); options.setIncludeMetadata( true ); options.setLimit( 1 ); List<ObjectResult> objects = this.esu.listObjects( "listable", options ); Assert.assertTrue( "No objects returned", objects.size() > 0 ); Assert.assertNotNull( "Token should be present", options.getToken() ); l4j.debug( "listObjectsPaged, Token: " + options.getToken() ); while ( options.getToken() != null ) { // Subsequent pages objects.addAll( this.esu.listObjects( "listable", options ) ); l4j.debug( "listObjectsPaged, Token: " + options.getToken() ); } // Ensure our IDs exist Assert.assertTrue( "First object not found", objects.contains( id1 ) ); Assert.assertTrue( "Second object not found", objects.contains( id2 ) ); } /** * Test fetching listable tags */ @Test public void testGetListableTags() { // Create an object ObjectId id = this.esu.createObject( null, null, null, null ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); MetadataList mlist = new MetadataList(); Metadata listable = new Metadata( "listable", "foo", true ); Metadata unlistable = new Metadata( "unlistable", "bar", false ); Metadata listable2 = new Metadata( "list/able/2", "foo2 foo2", true ); Metadata unlistable2 = new Metadata( "list/able/not", "bar2 bar2", false ); mlist.addMetadata( listable ); mlist.addMetadata( unlistable ); mlist.addMetadata( listable2 ); mlist.addMetadata( unlistable2 ); this.esu.updateObject( id, null, mlist, null, null, null ); // List tags. Ensure our object's tags are in the list. MetadataTags tags = this.esu.getListableTags( (String) null ); Assert.assertTrue( "listable tag not returned", tags.contains( "listable" ) ); Assert.assertTrue( "list/able/2 root tag not returned", tags.contains( "list" ) ); Assert.assertFalse( "list/able/not tag returned", tags.contains( "list/able/not" ) ); // List child tags tags = this.esu.getListableTags( "list/able" ); Assert.assertFalse( "non-child returned", tags.contains( "listable" ) ); Assert.assertTrue( "list/able/2 tag not returned", tags.contains( "2" ) ); Assert.assertFalse( "list/able/not tag returned", tags.contains( "not" ) ); } /** * Test listing the user metadata tags on an object */ @Test public void testListUserMetadataTags() { // Create an object MetadataList mlist = new MetadataList(); Metadata listable = new Metadata( "listable", "foo", true ); Metadata unlistable = new Metadata( "unlistable", "bar", false ); Metadata listable2 = new Metadata( "list/able/2", "foo2 foo2", true ); Metadata unlistable2 = new Metadata( "list/able/not", "bar2 bar2", false ); mlist.addMetadata( listable ); mlist.addMetadata( unlistable ); mlist.addMetadata( listable2 ); mlist.addMetadata( unlistable2 ); ObjectId id = this.esu.createObject( null, mlist, null, null ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); // List tags MetadataTags tags = this.esu.listUserMetadataTags( id ); Assert.assertTrue( "listable tag not returned", tags.contains( "listable" ) ); Assert.assertTrue( "list/able/2 tag not returned", tags.contains( "list/able/2" ) ); Assert.assertTrue( "unlistable tag not returned", tags.contains( "unlistable" ) ); Assert.assertTrue( "list/able/not tag not returned", tags.contains( "list/able/not" ) ); Assert.assertFalse( "unknown tag returned", tags.contains( "unknowntag" ) ); // Check listable flag Assert.assertEquals( "'listable' is not listable", true, tags.getTag( "listable" ).isListable() ); Assert.assertEquals( "'list/able/2' is not listable", true, tags.getTag( "list/able/2" ).isListable() ); Assert.assertEquals( "'unlistable' is listable", false, tags.getTag( "unlistable" ).isListable() ); Assert.assertEquals( "'list/able/not' is listable", false, tags.getTag( "list/able/not" ).isListable() ); } // /** // * Test executing a query. // */ // @Test // public void testQueryObjects() { // // Create an object // MetadataList mlist = new MetadataList(); // Metadata listable = new Metadata( "listable", "foo", true ); // Metadata unlistable = new Metadata( "unlistable", "bar", false ); // Metadata listable2 = new Metadata( "list/able/2", "foo2 foo2", true ); // Metadata unlistable2 = new Metadata( "list/able/not", "bar2 bar2", false ); // mlist.addMetadata( listable ); // mlist.addMetadata( unlistable ); // mlist.addMetadata( listable2 ); // mlist.addMetadata( unlistable2 ); // ObjectId id = this.esu.createObject( null, mlist, null, null ); // Assert.assertNotNull( "null ID returned", id ); // cleanup.add( id ); // // // Query for all objects for the current UID // String query = "for $h in collection() where $h/maui:MauiObject[uid=\"" + // uid + "\"] return $h"; // l4j.info( "Query: " + query ); // List<Identifier> objects = this.esu.queryObjects( query ); // // // Ensure the search results contains the object we just created // Assert.assertTrue( "object not found in list", objects.contains( id ) ); // // } /** * Tests updating an object's metadata */ @Test public void testUpdateObjectMetadata() throws Exception { // Create an object MetadataList mlist = new MetadataList(); Metadata unlistable = new Metadata( "unlistable", "foo", false ); mlist.addMetadata( unlistable ); ObjectId id = this.esu.createObject( null, mlist, "hello".getBytes( "UTF-8" ), null ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); // Update the metadata unlistable.setValue( "bar" ); this.esu.setUserMetadata( id, mlist ); // Re-read the metadata MetadataList meta = this.esu.getUserMetadata( id, null ); Assert.assertEquals( "value of 'unlistable' wrong", "bar", meta.getMetadata( "unlistable" ).getValue() ); // Check that content was not modified String content = new String( this.esu.readObject( id, null, null ), "UTF-8" ); Assert.assertEquals( "object content wrong", "hello", content ); } @Test public void testUpdateObjectAcl() throws Exception { // Create an object with an ACL Acl acl = new Acl(); acl.addGrant( new Grant( new Grantee( stripUid( uid ), Grantee.GRANT_TYPE.USER ), Permission.FULL_CONTROL ) ); Grant other = new Grant( Grantee.OTHER, Permission.READ ); acl.addGrant( other ); ObjectId id = this.esu.createObject( acl, null, null, null ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); // Read back the ACL and make sure it matches Acl newacl = this.esu.getAcl( id ); l4j.info( "Comparing " + newacl + " with " + acl ); Assert.assertEquals( "ACLs don't match", acl, newacl ); // Change the ACL and update the object. acl.removeGrant( other ); Grant o2 = new Grant( Grantee.OTHER, Permission.NONE ); acl.addGrant( o2 ); this.esu.setAcl( id, acl ); // Read the ACL back and check it newacl = this.esu.getAcl( id ); l4j.info( "Comparing " + newacl + " with " + acl ); Assert.assertEquals( "ACLs don't match", acl, newacl ); } /** * Tests updating an object's contents */ @Test public void testUpdateObjectContent() throws Exception { // Create an object ObjectId id = this.esu.createObject( null, null, "hello".getBytes( "UTF-8" ), "text/plain" ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); // Update part of the content Extent extent = new Extent( 1, 1 ); this.esu.updateObject( id, null, null, extent, "u".getBytes( "UTF-8" ), null ); // Read back the content and check it String content = new String( this.esu.readObject( id, null, null ), "UTF-8" ); Assert.assertEquals( "object content wrong", "hullo", content ); } @Test public void testUpdateObjectContentStream() throws Exception { // Create an object ObjectId id = this.esu.createObject( null, null, "hello".getBytes( "UTF-8" ), "text/plain" ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); // Update part of the content Extent extent = new Extent( 1, 1 ); InputStream in = new ByteArrayInputStream( "u".getBytes( "UTF-8" ) ); this.esu.updateObjectFromStream( id, null, null, extent, in, 1, null ); in.close(); // Read back the content and check it String content = new String( this.esu.readObject( id, null, null ), "UTF-8" ); Assert.assertEquals( "object content wrong", "hullo", content ); } /** * Test replacing an object's entire contents */ @Test public void testReplaceObjectContent() throws Exception { // Create an object ObjectId id = this.esu.createObject( null, null, "hello".getBytes( "UTF-8" ), "text/plain" ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); // Update all of the content this.esu.updateObject( id, null, null, null, "bonjour".getBytes( "UTF-8" ), null ); // Read back the content and check it String content = new String( this.esu.readObject( id, null, null ), "UTF-8" ); Assert.assertEquals( "object content wrong", "bonjour", content ); } /** * Test the UploadHelper's create method */ @Test public void testCreateHelper() throws Exception { // use a blocksize of 1 to test multiple transfers. UploadHelper uploadHelper = new UploadHelper( this.esu, new byte[1] ); ByteArrayOutputStream baos = new ByteArrayOutputStream(); baos.write( "hello".getBytes( "UTF-8" ) ); // Create an object from our file stream ObjectId id = uploadHelper.createObject( new ByteArrayInputStream( baos.toByteArray() ), null, null, true ); cleanup.add( id ); // Read contents back and check them String content = new String( this.esu.readObject( id, null, null ), "UTF-8" ); Assert.assertEquals( "object content wrong", "hello", content ); } /** * Test the UploadHelper's update method */ @Test public void testUpdateHelper() throws Exception { // use a blocksize of 1 to test multiple transfers. UploadHelper uploadHelper = new UploadHelper( this.esu, new byte[1] ); uploadHelper.setMimeType( "text/plain" ); // Create an object with content. ObjectId id = this.esu.createObject( null, null, "Four score and twenty years ago".getBytes( "UTF-8" ), "text/plain" ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); // update the object contents ByteArrayOutputStream baos = new ByteArrayOutputStream(); baos.write( "hello".getBytes( "UTF-8" ) ); uploadHelper.updateObject( id, new ByteArrayInputStream( baos.toByteArray() ), null, null, true ); // Read contents back and check them String content = new String( this.esu.readObject( id, null, null ), "UTF-8" ); Assert.assertEquals( "object content wrong", "hello", content ); } /** * Tests the download helper. Tests both single and multiple requests. */ @Test public void testDownloadHelper() throws Exception { // Create an object with content. ObjectId id = this.esu.createObject( null, null, "Four score and twenty years ago".getBytes( "UTF-8" ), "text/plain" ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); // Download the content DownloadHelper downloadHelper = new DownloadHelper( this.esu, null ); ByteArrayOutputStream baos = new ByteArrayOutputStream(); downloadHelper.readObject( id, baos, false ); // Check the download String data = new String( baos.toByteArray(), "UTF-8" ); Assert.assertEquals( "object content wrong", "Four score and twenty years ago", data ); // Download again 1 byte in a request downloadHelper = new DownloadHelper( this.esu, new byte[1] ); baos = new ByteArrayOutputStream(); downloadHelper.readObject( id, baos, false ); // Check the download data = new String( baos.toByteArray(), "UTF-8" ); Assert.assertEquals( "object content wrong", "Four score and twenty years ago", data ); } // @Test // public void testUploadDownload() throws Exception { // // Create a byte array to test // int size=10*1024*1024; // byte[] testData = new byte[size]; // for( int i=0; i<size; i++ ) { // testData[i] = (byte)(i%0x93); // } // UploadHelper uh = new UploadHelper( this.esu, null ); // // ObjectId id = uh.createObject( new ByteArrayInputStream( testData ), null, null, true ); // cleanup.add( id ); // // ByteArrayOutputStream baos = new ByteArrayOutputStream( size ); // // DownloadHelper dl = new DownloadHelper( this.esu, new byte[4*1024*1024] ); // dl.readObject( id, baos, true ); // // Assert.assertFalse( "Download should have been OK", dl.isFailed() ); // Assert.assertNull( "Error should have been null", dl.getError() ); // // byte[] outData = baos.toByteArray(); // // // Check the files // Assert.assertEquals( "File lengths differ", testData.length, outData.length ); // // Assert.assertArrayEquals( "Data contents differ", testData, outData ); // // } @Test public void testListDirectory() throws Exception { String dir = rand8char(); String file = rand8char(); String dir2 = rand8char(); ObjectPath dirPath = new ObjectPath( "/" + dir + "/" ); ObjectPath op = new ObjectPath( "/" + dir + "/" + file ); ObjectPath dirPath2 = new ObjectPath( "/" + dir + "/" + dir2 + "/" ); ObjectId dirId = this.esu.createObjectOnPath( dirPath, null, null, null, null ); ObjectId id = this.esu.createObjectOnPath( op, null, null, null, null ); this.esu.createObjectOnPath( dirPath2, null, null, null, null ); cleanup.add( op ); cleanup.add( dirPath2 ); cleanup.add( dirPath ); l4j.debug( "Path: " + op + " ID: " + id ); Assert.assertNotNull( id ); Assert.assertNotNull( dirId ); // Read back the content String content = new String( this.esu.readObject( op, null, null ), "UTF-8" ); Assert.assertEquals( "object content wrong", "", content ); content = new String( this.esu.readObject( id, null, null ), "UTF-8" ); Assert.assertEquals( "object content wrong when reading by id", "", content ); // List the parent path List<DirectoryEntry> dirList = esu.listDirectory( dirPath, null ); l4j.debug( "Dir content: " + content ); Assert.assertTrue( "File not found in directory", directoryContains( dirList, op ) ); Assert.assertTrue( "subdirectory not found in directory", directoryContains( dirList, dirPath2 ) ); } @Test public void testListDirectoryPaged() throws Exception { String dir = rand8char(); String file = rand8char(); String dir2 = rand8char(); ObjectPath dirPath = new ObjectPath( "/" + dir + "/" ); ObjectPath op = new ObjectPath( "/" + dir + "/" + file ); ObjectPath dirPath2 = new ObjectPath( "/" + dir + "/" + dir2 + "/" ); ObjectId dirId = this.esu.createObjectOnPath( dirPath, null, null, null, null ); ObjectId id = this.esu.createObjectOnPath( op, null, null, null, null ); this.esu.createObjectOnPath( dirPath2, null, null, null, null ); cleanup.add( op ); cleanup.add( dirPath2 ); cleanup.add( dirPath ); l4j.debug( "Path: " + op + " ID: " + id ); Assert.assertNotNull( id ); Assert.assertNotNull( dirId ); // List the parent path ListOptions options = new ListOptions(); options.setLimit( 1 ); List<DirectoryEntry> dirList = esu.listDirectory( dirPath, options ); Assert.assertNotNull( "Token should have been returned", options.getToken() ); l4j.debug( "listDirectoryPaged, token: " + options.getToken() ); while ( options.getToken() != null ) { dirList.addAll( esu.listDirectory( dirPath, options ) ); } Assert.assertTrue( "File not found in directory", directoryContains( dirList, op ) ); Assert.assertTrue( "subdirectory not found in directory", directoryContains( dirList, dirPath2 ) ); } @Test public void testListDirectoryWithMetadata() throws Exception { String dir = rand8char(); String file = rand8char(); String dir2 = rand8char(); ObjectPath dirPath = new ObjectPath( "/" + dir + "/" ); ObjectPath op = new ObjectPath( "/" + dir + "/" + file ); ObjectPath dirPath2 = new ObjectPath( "/" + dir + "/" + dir2 + "/" ); MetadataList mlist = new MetadataList(); Metadata listable = new Metadata( "listable", "foo", true ); Metadata unlistable = new Metadata( "unlistable", "bar", false ); Metadata listable2 = new Metadata( "list/able/2", "foo2 foo2", true ); Metadata unlistable2 = new Metadata( "list/able/not", "bar2 bar2", false ); mlist.addMetadata( listable ); mlist.addMetadata( unlistable ); mlist.addMetadata( listable2 ); mlist.addMetadata( unlistable2 ); ObjectId dirId = this.esu.createObjectOnPath( dirPath, null, null, null, null ); ObjectId id = this.esu.createObjectOnPath( op, null, mlist, null, null ); this.esu.createObjectOnPath( dirPath2, null, null, null, null ); cleanup.add( op ); cleanup.add( dirPath2 ); cleanup.add( dirPath ); l4j.debug( "Path: " + op + " ID: " + id ); Assert.assertNotNull( id ); Assert.assertNotNull( dirId ); // List the parent path ListOptions options = new ListOptions(); options.setIncludeMetadata( true ); List<DirectoryEntry> dirList = esu.listDirectory( dirPath, options ); Assert.assertTrue( "File not found in directory", directoryContains( dirList, op ) ); Assert.assertTrue( "subdirectory not found in directory", directoryContains( dirList, dirPath2 ) ); for ( Iterator<DirectoryEntry> i = dirList.iterator(); i.hasNext(); ) { DirectoryEntry de = i.next(); if ( de.getPath().equals( op ) ) { // Check the metadata Assert.assertEquals( "Wrong value on metadata", de.getUserMetadata().getMetadata( "listable" ).getValue(), "foo" ); } } Assert.assertTrue( "File not found in directory", directoryContains( dirList, op ) ); Assert.assertTrue( "subdirectory not found in directory", directoryContains( dirList, dirPath2 ) ); } @Test public void testListDirectoryWithSomeMetadata() throws Exception { String dir = rand8char(); String file = rand8char(); String dir2 = rand8char(); ObjectPath dirPath = new ObjectPath( "/" + dir + "/" ); ObjectPath op = new ObjectPath( "/" + dir + "/" + file ); ObjectPath dirPath2 = new ObjectPath( "/" + dir + "/" + dir2 + "/" ); MetadataList mlist = new MetadataList(); Metadata listable = new Metadata( "listable", "foo", true ); Metadata unlistable = new Metadata( "unlistable", "bar", false ); Metadata listable2 = new Metadata( "list/able/2", "foo2 foo2", true ); Metadata unlistable2 = new Metadata( "list/able/not", "bar2 bar2", false ); mlist.addMetadata( listable ); mlist.addMetadata( unlistable ); mlist.addMetadata( listable2 ); mlist.addMetadata( unlistable2 ); ObjectId dirId = this.esu.createObjectOnPath( dirPath, null, null, null, null ); ObjectId id = this.esu.createObjectOnPath( op, null, mlist, null, null ); this.esu.createObjectOnPath( dirPath2, null, null, null, null ); cleanup.add( op ); cleanup.add( dirPath2 ); cleanup.add( dirPath ); l4j.debug( "Path: " + op + " ID: " + id ); Assert.assertNotNull( id ); Assert.assertNotNull( dirId ); // List the parent path ListOptions options = new ListOptions(); options.setIncludeMetadata( true ); options.setUserMetadata( Arrays.asList( new String[]{"listable"} ) ); List<DirectoryEntry> dirList = esu.listDirectory( dirPath, options ); Assert.assertTrue( "File not found in directory", directoryContains( dirList, op ) ); Assert.assertTrue( "subdirectory not found in directory", directoryContains( dirList, dirPath2 ) ); for ( Iterator<DirectoryEntry> i = dirList.iterator(); i.hasNext(); ) { DirectoryEntry de = i.next(); if ( de.getPath().equals( op ) ) { // Check the metadata Assert.assertEquals( "Wrong value on metadata", de.getUserMetadata().getMetadata( "listable" ).getValue(), "foo" ); // Other metadata should not be present Assert.assertNull( "unlistable should be missing", de.getUserMetadata().getMetadata( "unlistable" ) ); } } Assert.assertTrue( "File not found in directory", directoryContains( dirList, op ) ); Assert.assertTrue( "subdirectory not found in directory", directoryContains( dirList, dirPath2 ) ); } private boolean directoryContains( List<DirectoryEntry> dir, ObjectPath path ) { for ( Iterator<DirectoryEntry> i = dir.iterator(); i.hasNext(); ) { DirectoryEntry de = i.next(); if ( de.getPath().equals( path ) ) { return true; } } return false; } /** * This method tests various legal and illegal pathnames * * @throws Exception */ @Test public void testPathNaming() throws Exception { ObjectPath path = new ObjectPath( "/some/file" ); Assert.assertFalse( "File should not be directory", path.isDirectory() ); path = new ObjectPath( "/some/file.txt" ); Assert.assertFalse( "File should not be directory", path.isDirectory() ); ObjectPath path2 = new ObjectPath( "/some/file.txt" ); Assert.assertEquals( "Equal paths should be equal", path, path2 ); path = new ObjectPath( "/some/file/with/long.path/extra.stuff.here.zip" ); Assert.assertFalse( "File should not be directory", path.isDirectory() ); path = new ObjectPath( "/" ); Assert.assertTrue( "Directory should be directory", path.isDirectory() ); path = new ObjectPath( "/long/path/with/lots/of/elements/" ); Assert.assertTrue( "Directory should be directory", path.isDirectory() ); } /** * Tests dot directories (you should be able to create them even though they break the URL specification.) * * @throws Exception */ @Test public void testDotDirectories() throws Exception { String parentPath = "/dottest/"; String dotPath = parentPath + "./"; String dotdotPath = parentPath + "../"; String filename = "test.txt"; byte[] content = "Hello World!".getBytes( "UTF-8" ); // isolate this test in the namespace ObjectId parentId = null; try { parentId = this.esu.createObjectOnPath( new ObjectPath( parentPath ), null, null, null, null ); } catch(EsuException e) { if(e.getAtmosCode() == 1016) { deleteRecursively(new ObjectPath( parentPath )); parentId = this.esu.createObjectOnPath( new ObjectPath( parentPath ), null, null, null, null ); } else { throw e; } } // test single dot path (./) ObjectId fileId = this.esu.createObjectOnPath( new ObjectPath( parentPath + "hidden.txt" ), null, null, content, "text/plain" ); cleanup.add( fileId ); ObjectId dirId = this.esu.createObjectOnPath( new ObjectPath( dotPath ), null, null, null, null ); Assert.assertNotNull( "null ID returned on dot path creation", dirId ); fileId = this.esu.createObjectOnPath( new ObjectPath( dotPath + filename ), null, null, content, "text/plain" ); // make sure we only see one file (the "." path is its own directory and not a synonym for the current directory) List<DirectoryEntry> entries = this.esu.listDirectory( new ObjectPath( dotPath ), null ); Assert.assertEquals( "dot path listing was not 1", entries.size(), 1 ); Assert.assertTrue( "dot path listing did not contain a dot in the path", entries.get( 0 ).getPath().toString().contains( dotPath ) ); Assert.assertEquals( "dot path listing did not contain test file", entries.get( 0 ).getPath().getName(), filename ); cleanup.add( fileId ); cleanup.add( dirId ); // test double dot path (../) dirId = this.esu.createObjectOnPath( new ObjectPath( dotdotPath ), null, null, null, null ); Assert.assertNotNull( "null ID returned on dotdot path creation", dirId ); fileId = this.esu.createObjectOnPath( new ObjectPath( dotdotPath + filename ), null, null, content, "text/plain" ); // make sure we only see one file (the ".." path is its own directory and not a synonym for the parent directory) entries = this.esu.listDirectory( new ObjectPath( dotdotPath ), null ); Assert.assertEquals( "dotdot path listing was not 1", entries.size(), 1 ); Assert.assertTrue( "dotdot path listing did not contain a dotdot in the path", entries.get( 0 ).getPath().toString().contains( dotdotPath ) ); Assert.assertEquals( "dotdot path listing did not contain test file", entries.get( 0 ).getPath().getName(), filename ); cleanup.add( fileId ); cleanup.add( dirId ); cleanup.add( parentId ); } /** * Tests the 'get all metadata' call using a path * * @throws Exception */ @Test public void testGetAllMetadataByPath() throws Exception { ObjectPath op = new ObjectPath( "/" + rand8char() + ".tmp" ); // Create an object with an ACL Acl acl = new Acl(); acl.addGrant( new Grant( new Grantee( uid, Grantee.GRANT_TYPE.USER ), Permission.FULL_CONTROL ) ); acl.addGrant( new Grant( Grantee.OTHER, Permission.READ ) ); MetadataList mlist = new MetadataList(); Metadata listable = new Metadata( "listable", "foo", true ); Metadata unlistable = new Metadata( "unlistable", "bar", false ); Metadata listable2 = new Metadata( "listable2", "foo2 foo2", true ); Metadata unlistable2 = new Metadata( "unlistable2", "bar2 bar2", false ); mlist.addMetadata( listable ); mlist.addMetadata( unlistable ); mlist.addMetadata( listable2 ); mlist.addMetadata( unlistable2 ); String mimeType = "test/mimetype"; String content = "test"; ObjectId id = this.esu.createObjectOnPath( op, acl, null, content.getBytes( "UTF-8" ), mimeType ); this.esu.updateObject( op, null, mlist, null, null, mimeType ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( op ); // Read it back with HEAD call ObjectMetadata om = this.esu.getAllMetadata( op ); Assert.assertNotNull( "value of 'listable' missing", om.getMetadata().getMetadata( "listable" ) ); Assert.assertNotNull( "value of 'unlistable' missing", om.getMetadata().getMetadata( "unlistable" ) ); Assert.assertNotNull( "value of 'atime' missing", om.getMetadata().getMetadata( "atime" ) ); Assert.assertNotNull( "value of 'ctime' missing", om.getMetadata().getMetadata( "ctime" ) ); Assert.assertEquals( "value of 'listable' wrong", "foo", om.getMetadata().getMetadata( "listable" ).getValue() ); Assert.assertEquals( "value of 'unlistable' wrong", "bar", om.getMetadata().getMetadata( "unlistable" ).getValue() ); Assert.assertEquals( "Mimetype incorrect", mimeType, om.getMimeType() ); // Check the ACL // not checking this by path because an extra groupid is added // during the create calls by path. //Assert.assertEquals( "ACLs don't match", acl, om.getAcl() ); } @Test public void testGetAllMetadataById() throws Exception { // Create an object with an ACL Acl acl = new Acl(); acl.addGrant( new Grant( new Grantee( uid, Grantee.GRANT_TYPE.USER ), Permission.FULL_CONTROL ) ); acl.addGrant( new Grant( Grantee.OTHER, Permission.READ ) ); MetadataList mlist = new MetadataList(); Metadata listable = new Metadata( "listable", "foo", true ); Metadata unlistable = new Metadata( "unlistable", "bar", false ); Metadata listable2 = new Metadata( "listable2", "foo2 foo2", true ); Metadata unlistable2 = new Metadata( "unlistable2", "bar2 bar2", false ); mlist.addMetadata( listable ); mlist.addMetadata( unlistable ); mlist.addMetadata( listable2 ); mlist.addMetadata( unlistable2 ); String mimeType = "test/mimetype"; String content = "test"; ObjectId id = this.esu.createObject( acl, mlist, content.getBytes( "UTF-8" ), mimeType ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); // Read it back with HEAD call ObjectMetadata om = this.esu.getAllMetadata( id ); Assert.assertNotNull( "value of 'listable' missing", om.getMetadata().getMetadata( "listable" ) ); Assert.assertNotNull( "value of 'unlistable' missing", om.getMetadata().getMetadata( "unlistable" ) ); Assert.assertNotNull( "value of 'atime' missing", om.getMetadata().getMetadata( "atime" ) ); Assert.assertNotNull( "value of 'ctime' missing", om.getMetadata().getMetadata( "ctime" ) ); Assert.assertEquals( "value of 'listable' wrong", "foo", om.getMetadata().getMetadata( "listable" ).getValue() ); Assert.assertEquals( "value of 'unlistable' wrong", "bar", om.getMetadata().getMetadata( "unlistable" ).getValue() ); Assert.assertEquals( "Mimetype incorrect", mimeType, om.getMimeType() ); // Check the ACL //Assert.assertEquals( "ACLs don't match", acl, om.getAcl() ); } /** * Tests getting object replica information. */ @Test public void testGetObjectReplicaInfo() throws Exception { ObjectId id = this.esu.createObject( null, null, "hello".getBytes( "UTF-8" ), "text/plain" ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); MetadataTags mt = new MetadataTags(); mt.addTag( new MetadataTag( "user.maui.lso", false ) ); MetadataList meta = this.esu.getUserMetadata( id, mt ); Assert.assertNotNull( meta.getMetadata( "user.maui.lso" ) ); l4j.debug( "Replica info: " + meta.getMetadata( "user.maui.lso" ) ); } @Test public void testCreateHelperWithPath() throws Exception { String dir = rand8char(); String file = rand8char(); ObjectPath op = new ObjectPath( "/" + dir + "/" + file ); // use a blocksize of 1 to test multiple transfers. UploadHelper uploadHelper = new UploadHelper( this.esu, new byte[1] ); ByteArrayOutputStream baos = new ByteArrayOutputStream(); baos.write( "hello".getBytes( "UTF-8" ) ); // Create an object from our file stream ObjectId id = uploadHelper.createObjectOnPath( op, new ByteArrayInputStream( baos.toByteArray() ), null, null, true ); cleanup.add( op ); // Read contents back and check them String content = new String( this.esu.readObject( id, null, null ), "UTF-8" ); Assert.assertEquals( "object content wrong", "hello", content ); } @Test public void testUpdateHelperWithPath() throws Exception { String dir = rand8char(); String file = rand8char(); ObjectPath op = new ObjectPath( "/" + dir + "/" + file ); // use a blocksize of 1 to test multiple transfers. UploadHelper uploadHelper = new UploadHelper( this.esu, new byte[1] ); uploadHelper.setMimeType( "text/plain" ); // Create an object with content. ObjectId id = this.esu.createObjectOnPath( op, null, null, "Four score and twenty years ago".getBytes( "UTF-8" ), "text/plain" ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( op ); // update the object contents ByteArrayOutputStream baos = new ByteArrayOutputStream(); baos.write( "hello".getBytes( "UTF-8" ) ); uploadHelper.updateObject( op, new ByteArrayInputStream( baos.toByteArray() ), null, null, true ); // Read contents back and check them String content = new String( this.esu.readObject( id, null, null ), "UTF-8" ); Assert.assertEquals( "object content wrong", "hello", content ); } @Test public void testGetShareableUrl() throws Exception { Assume.assumeFalse(isVipr); // Create an object with content. String str = "Four score and twenty years ago"; ObjectId id = this.esu.createObject( null, null, str.getBytes( "UTF-8" ), "text/plain" ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); Calendar c = Calendar.getInstance(); c.add( Calendar.HOUR, 4 ); Date expiration = c.getTime(); URL u = esu.getShareableUrl( id, expiration ); l4j.debug( "Sharable URL: " + u ); InputStream stream = (InputStream) u.getContent(); BufferedReader br = new BufferedReader( new InputStreamReader( stream ) ); String content = br.readLine(); l4j.debug( "Content: " + content ); Assert.assertEquals( "URL does not contain proper content", str, content.toString() ); } @Test public void testGetShareableUrlWithPath() throws Exception { Assume.assumeFalse(isVipr); // Create an object with content. String str = "Four score and twenty years ago"; ObjectPath op = new ObjectPath( "/" + rand8char() + ".txt" ); ObjectId id = this.esu.createObjectOnPath( op, null, null, str.getBytes( "UTF-8" ), "text/plain" ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( op ); Calendar c = Calendar.getInstance(); c.add( Calendar.HOUR, 4 ); Date expiration = c.getTime(); URL u = esu.getShareableUrl( op, expiration ); l4j.debug( "Sharable URL: " + u ); InputStream stream = (InputStream) u.getContent(); BufferedReader br = new BufferedReader( new InputStreamReader( stream ) ); String content = br.readLine(); l4j.debug( "Content: " + content ); Assert.assertEquals( "URL does not contain proper content", str, content.toString() ); } @Test public void testExpiredSharableUrl() throws Exception { Assume.assumeFalse(isVipr); // Create an object with content. String str = "Four score and twenty years ago"; ObjectId id = this.esu.createObject( null, null, str.getBytes( "UTF-8" ), "text/plain" ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); Calendar c = Calendar.getInstance(); c.add( Calendar.HOUR, -4 ); Date expiration = c.getTime(); URL u = esu.getShareableUrl( id, expiration ); l4j.debug( "Sharable URL: " + u ); try { InputStream stream = (InputStream) u.getContent(); BufferedReader br = new BufferedReader( new InputStreamReader( stream ) ); String content = br.readLine(); l4j.debug( "Content: " + content ); Assert.fail( "Request should have failed" ); } catch ( Exception e ) { l4j.debug( "Error (expected): " + e ); } } @Test public void testReadObjectStream() throws Exception { ObjectId id = this.esu.createObject( null, null, "hello".getBytes( "UTF-8" ), "text/plain" ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); // Read back the content InputStream in = this.esu.readObjectStream( id, null ); BufferedReader br = new BufferedReader( new InputStreamReader( in, "UTF-8" ) ); String content = br.readLine(); br.close(); Assert.assertEquals( "object content wrong", "hello", content ); // Read back only 2 bytes Extent extent = new Extent( 1, 2 ); in = this.esu.readObjectStream( id, extent ); br = new BufferedReader( new InputStreamReader( in, "UTF-8" ) ); content = br.readLine(); br.close(); Assert.assertEquals( "partial object content wrong", "el", content ); } @Test public void testCreateChecksum() throws Exception { Checksum ck = new Checksum( Algorithm.SHA0 ); ObjectId id = this.esu.createObject( null, null, "hello".getBytes( "UTF-8" ), "text/plain", ck ); l4j.debug( "Checksum: " + ck ); cleanup.add( id ); } /** * Note, to test read checksums, see comment in testReadChecksum * * @throws Exception */ @Test public void testUploadDownloadChecksum() throws Exception { // Create a byte array to test int size = 10 * 1024 * 1024; byte[] testData = new byte[size]; for ( int i = 0; i < size; i++ ) { testData[i] = (byte) (i % 0x93); } MetadataList mlist = new MetadataList(); Metadata policy = new Metadata( "policy", "erasure", false ); mlist.addMetadata( policy ); UploadHelper uh = new UploadHelper( this.esu, null ); uh.setChecksumming( true ); ObjectId id = uh.createObject( new ByteArrayInputStream( testData ), null, mlist, true ); cleanup.add( id ); ByteArrayOutputStream baos = new ByteArrayOutputStream( size ); DownloadHelper dl = new DownloadHelper( this.esu, new byte[4 * 1024 * 1024] ); dl.setChecksumming( true ); dl.readObject( id, baos, true ); Assert.assertFalse( "Download should have been OK", dl.isFailed() ); Assert.assertNull( "Error should have been null", dl.getError() ); byte[] outData = baos.toByteArray(); // Check the files Assert.assertEquals( "File lengths differ", testData.length, outData.length ); Assert.assertArrayEquals( "Data contents differ", testData, outData ); } @Test public void testUnicodeMetadata() throws Exception { MetadataList mlist = new MetadataList(); Metadata nbspValue = new Metadata( "nbspvalue", "Nobreak\u00A0Value", false ); Metadata nbspName = new Metadata( "Nobreak\u00A0Name", "regular text here", false ); Metadata cryllic = new Metadata( "cryllic", "спасибо", false ); l4j.debug( "NBSP Value: " + nbspValue ); l4j.debug( "NBSP Name: " + nbspName ); mlist.addMetadata( nbspValue ); mlist.addMetadata( nbspName ); mlist.addMetadata( cryllic ); ObjectId id = this.esu.createObject( null, mlist, null, null ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); // Read and validate the metadata MetadataList meta = this.esu.getUserMetadata( id, null ); l4j.debug( "Read Back:" ); l4j.debug( "NBSP Value: " + meta.getMetadata( "nbspvalue" ) ); l4j.debug( "NBSP Name: " + meta.getMetadata( "Nobreak\u00A0Name" ) ); Assert.assertEquals( "value of 'nobreakvalue' wrong", "Nobreak\u00A0Value", meta.getMetadata( "nbspvalue" ).getValue() ); Assert.assertEquals( "Value of cryllic wrong", "спасибо", meta.getMetadata( "cryllic" ).getValue() ); } @Test public void testUtf8Metadata() throws Exception { String oneByteCharacters = "Hello! "; String twoByteCharacters = "\u0410\u0411\u0412\u0413"; // Cyrillic letters String fourByteCharacters = "\ud841\udf0e\ud841\udf31\ud841\udf79\ud843\udc53"; // Chinese symbols String utf8String = oneByteCharacters + twoByteCharacters + fourByteCharacters; MetadataList metaList = new MetadataList(); metaList.addMetadata( new Metadata( "utf8Key", utf8String, false ) ); metaList.addMetadata( new Metadata( utf8String, "utf8Value", false ) ); ObjectId id = this.esu.createObject( null, metaList, null, null ); cleanup.add( id ); // list all tags and make sure the UTF8 tag is in the list MetadataTags tags = this.esu.listUserMetadataTags( id ); Assert.assertTrue( "UTF8 key not found in tag list", tags.contains( utf8String ) ); // get the user metadata and make sure all UTF8 characters are accurate metaList = this.esu.getUserMetadata( id, null ); Metadata meta = metaList.getMetadata( utf8String ); Assert.assertEquals( "UTF8 key does not match", meta.getName(), utf8String ); Assert.assertEquals( "UTF8 key value does not match", meta.getValue(), "utf8Value" ); Assert.assertEquals( "UTF8 value does not match", metaList.getMetadata( "utf8Key" ).getValue(), utf8String ); // test set metadata with UTF8 metaList = new MetadataList(); metaList.addMetadata( new Metadata( "newKey", utf8String + "2", false ) ); metaList.addMetadata( new Metadata( utf8String + "2", "newValue", false ) ); this.esu.setUserMetadata( id, metaList ); // verify set metadata call (also testing getAllMetadata) ObjectMetadata objMeta = this.esu.getAllMetadata( id ); metaList = objMeta.getMetadata(); meta = metaList.getMetadata( utf8String + "2" ); Assert.assertEquals( "UTF8 key does not match", meta.getName(), utf8String + "2" ); Assert.assertEquals( "UTF8 key value does not match", meta.getValue(), "newValue" ); Assert.assertEquals( "UTF8 value does not match", metaList.getMetadata( "newKey" ).getValue(), utf8String + "2" ); } @Test public void testUtf8MetadataFilter() throws Exception { String oneByteCharacters = "Hello! "; String twoByteCharacters = "\u0410\u0411\u0412\u0413"; // Cyrillic letters String fourByteCharacters = "\ud841\udf0e\ud841\udf31\ud841\udf79\ud843\udc53"; // Chinese symbols String utf8String = oneByteCharacters + twoByteCharacters + fourByteCharacters; MetadataList metaList = new MetadataList(); metaList.addMetadata( new Metadata( "utf8Key", utf8String, false ) ); metaList.addMetadata( new Metadata( utf8String, "utf8Value", false ) ); ObjectId id = this.esu.createObject( null, metaList, null, null ); cleanup.add( id ); // apply a filter that includes the UTF8 tag MetadataTags tags = new MetadataTags(); tags.addTag( new MetadataTag( utf8String, false ) ); metaList = this.esu.getUserMetadata( id, tags ); Assert.assertEquals( "UTF8 filter was not honored", metaList.count(), 1 ); Assert.assertNotNull( "UTF8 key was not found in filtered results", metaList.getMetadata( utf8String ) ); } @Test public void testUtf8DeleteMetadata() throws Exception { String oneByteCharacters = "Hello! "; String twoByteCharacters = "\u0410\u0411\u0412\u0413"; // Cyrillic letters String fourByteCharacters = "\ud841\udf0e\ud841\udf31\ud841\udf79\ud843\udc53"; // Chinese symbols String utf8String = oneByteCharacters + twoByteCharacters + fourByteCharacters; MetadataList metaList = new MetadataList(); metaList.addMetadata( new Metadata( "utf8Key", utf8String, false ) ); metaList.addMetadata( new Metadata( utf8String, "utf8Value", false ) ); ObjectId id = this.esu.createObject( null, metaList, null, null ); cleanup.add( id ); // delete the UTF8 tag MetadataTags tags = new MetadataTags(); tags.addTag( new MetadataTag( utf8String, false ) ); this.esu.deleteUserMetadata( id, tags ); // verify delete was successful tags = this.esu.listUserMetadataTags( id ); Assert.assertFalse( "UTF8 key was not deleted", tags.contains( utf8String ) ); } @Test public void testUtf8ListableMetadata() throws Exception { String oneByteCharacters = "Hello! "; String twoByteCharacters = "\u0410\u0411\u0412\u0413"; // Cyrillic letters String fourByteCharacters = "\ud841\udf0e\ud841\udf31\ud841\udf79\ud843\udc53"; // Chinese symbols String utf8String = oneByteCharacters + twoByteCharacters + fourByteCharacters; MetadataList metaList = new MetadataList(); metaList.addMetadata( new Metadata( utf8String, "utf8Value", true ) ); ObjectId id = this.esu.createObject( null, metaList, null, null ); cleanup.add( id ); metaList = this.esu.getUserMetadata( id, null ); Metadata meta = metaList.getMetadata( utf8String ); Assert.assertEquals( "UTF8 key does not match", meta.getName(), utf8String ); Assert.assertEquals( "UTF8 key value does not match", meta.getValue(), "utf8Value" ); Assert.assertTrue( "UTF8 metadata is not listable", meta.isListable() ); // verify we can list the tag and see our object boolean found = false; for ( ObjectResult result : this.esu.listObjects( utf8String, null ) ) { if ( result.getId().equals( id ) ) { found = true; break; } } Assert.assertTrue( "UTF8 tag listing did not contain the correct object ID", found ); // verify we can list child tags of the UTF8 tag MetadataTags tags = this.esu.getListableTags( new MetadataTag( utf8String, true ) ); Assert.assertNotNull( "UTF8 child tag listing was null", tags ); } //@Test public void testUtf8ListableTagWithComma() { String stringWithComma = "Hello, you!"; MetadataList metaList = new MetadataList(); metaList.addMetadata( new Metadata( stringWithComma, "value", true ) ); ObjectId id = this.esu.createObject( null, metaList, null, null ); cleanup.add( id ); metaList = this.esu.getUserMetadata( id, null ); Metadata meta = metaList.getMetadata( stringWithComma ); Assert.assertEquals( "key does not match", meta.getName(), stringWithComma ); Assert.assertTrue( "metadata is not listable", meta.isListable() ); boolean found = false; for ( ObjectResult result : this.esu.listObjects( stringWithComma, null ) ) { if ( result.getId().equals( id ) ) { found = true; break; } } Assert.assertTrue( "listing did not contain the correct object ID", found ); } @Test public void testRename() throws Exception { ObjectPath op1 = new ObjectPath( "/" + rand8char() + ".tmp" ); ObjectPath op2 = new ObjectPath( "/" + rand8char() + ".tmp" ); ObjectId id = this.esu.createObjectOnPath( op1, null, null, "Four score and seven years ago".getBytes( "UTF-8" ), "text/plain" ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); // Rename this.esu.rename( op1, op2, false ); // Read back the content String content = new String( this.esu.readObject( op2, null, null ), "UTF-8" ); Assert.assertEquals( "object content wrong", "Four score and seven years ago", content ); } @Test public void testRenameOverwrite() throws Exception { ObjectPath op1 = new ObjectPath( "/" + rand8char() + ".tmp" ); ObjectPath op2 = new ObjectPath( "/" + rand8char() + ".tmp" ); ObjectId id = this.esu.createObjectOnPath( op1, null, null, "Four score and seven years ago".getBytes( "UTF-8" ), "text/plain" ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); ObjectId id2 = this.esu.createObjectOnPath( op2, null, null, "You should not see this".getBytes( "UTF-8" ), "text/plain" ); cleanup.add( id2 ); // Rename this.esu.rename( op1, op2, true ); // Wait for overwrite to complete Thread.sleep( 5000 ); // Read back the content String content = new String( this.esu.readObject( op2, null, null ), "UTF-8" ); Assert.assertEquals( "object content wrong", "Four score and seven years ago", content ); } /** * Tests renaming a path to UTF-8 multi-byte characters. This is a separate test from create as the characters are * passed in the headers instead of the URL itself. * * @throws Exception */ @Test public void testUtf8Rename() throws Exception { String oneByteCharacters = "Hello! ,"; String twoByteCharacters = "\u0410\u0411\u0412\u0413"; // Cyrillic letters String fourByteCharacters = "\ud841\udf0e\ud841\udf31\ud841\udf79\ud843\udc53"; // Chinese symbols ObjectPath parentDir = createTestDir("Utf8Rename"); String normalName = parentDir + rand8char() + ".tmp"; String crazyName = parentDir + oneByteCharacters + twoByteCharacters + fourByteCharacters; byte[] content = "This is a really crazy name.".getBytes( "UTF-8" ); // normal name this.esu.createObjectOnPath( new ObjectPath( normalName ), null, null, content, "text/plain" ); // crazy multi-byte character name this.esu.rename( new ObjectPath( normalName ), new ObjectPath( crazyName ), true ); // Wait for overwrite to complete Thread.sleep( 5000 ); // verify name in directory list boolean found = false; for ( DirectoryEntry entry : this.esu.listDirectory( parentDir, null ) ) { if ( entry.getPath().toString().equals( crazyName ) ) { found = true; break; } } Assert.assertTrue( "crazyName not found in directory listing", found ); // Read back the content Assert.assertTrue( "object content wrong", Arrays.equals( content, this.esu.readObject( new ObjectPath( crazyName ), null, null ) ) ); } /** * Tests readback with checksum verification. In order to test this, create a policy * with erasure coding and then set a policy selector with "policy=erasure" to invoke * the erasure coding policy. * * @throws Exception */ @Test public void testReadChecksum() throws Exception { MetadataList mlist = new MetadataList(); Metadata policy = new Metadata( "policy", "erasure", false ); mlist.addMetadata( policy ); Checksum createChecksum = new Checksum( Algorithm.SHA0 ); ObjectId id = this.esu.createObject( null, mlist, "hello".getBytes( "UTF-8" ), "text/plain", createChecksum ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); // Read back the content Checksum readChecksum = new Checksum( Algorithm.SHA0 ); String content = new String( this.esu.readObject( id, null, null, readChecksum ), "UTF-8" ); Assert.assertEquals( "object content wrong", "hello", content ); } /** * Tests getting the service information */ @Test public void testGetServiceInformation() throws Exception { ServiceInformation si = this.esu.getServiceInformation(); Assert.assertNotNull( "Atmos version is null", si.getAtmosVersion() ); } /** * Test getting object info. Note to fully run this testcase, you should * create a policy named 'retaindelete' that keys off of the metadata * policy=retaindelete that includes a retention and deletion criteria. */ @Test public void testGetObjectInfo() throws Exception { MetadataList mlist = new MetadataList(); Metadata policy = new Metadata( "policy", "retaindelete", false ); mlist.addMetadata( policy ); ObjectId id = this.esu.createObject( null, mlist, "hello".getBytes( "UTF-8" ), "text/plain" ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); // Read back the content String content = new String( this.esu.readObject( id, null, null ), "UTF-8" ); Assert.assertEquals( "object content wrong", "hello", content ); // Get the object info ObjectInfo oi = this.esu.getObjectInfo( id ); Assert.assertNotNull( "ObjectInfo null", oi ); Assert.assertNotNull( "ObjectInfo expiration null", oi.getExpiration() ); Assert.assertNotNull( "ObjectInfo objectid null", oi.getObjectId() ); Assert.assertNotNull( "ObjectInfo raw xml null", oi.getRawXml() ); Assert.assertNotNull( "ObjectInfo replicas null", oi.getReplicas() ); Assert.assertNotNull( "ObjectInfo retention null", oi.getRetention() ); Assert.assertNotNull( "ObjectInfo selection null", oi.getSelection() ); Assert.assertTrue( "ObjectInfo should have at least one replica", oi.getReplicas().size() > 0 ); } @Test public void testHmac() throws Exception { // Compute the signature hash String input = "Hello World"; byte[] secret = Base64.decodeBase64( "D7qsp4j16PBHWSiUbc/bt3lbPBY=".getBytes( "UTF-8" ) ); Mac mac = Mac.getInstance( "HmacSHA1" ); SecretKeySpec key = new SecretKeySpec( secret, "HmacSHA1" ); mac.init( key ); l4j.debug( "Hashing: \n" + input.toString() ); byte[] hashData = mac.doFinal( input.toString().getBytes( "ISO-8859-1" ) ); // Encode the hash in Base64. String hashOut = new String( Base64.encodeBase64( hashData ), "UTF-8" ); l4j.debug( "Hash: " + hashOut ); } @Test public void testDirectoryMetadata() throws Exception { ObjectPath dir = new ObjectPath("/" + rand8char() + "/"); MetadataList mlist = new MetadataList(); Metadata listable = new Metadata( "listable", "foo", true ); Metadata unlistable = new Metadata( "unlistable", "bar", false ); Metadata listable2 = new Metadata( "listable2", "foo2 foo2", true ); Metadata unlistable2 = new Metadata( "unlistable2", "bar2 bar2", false ); Metadata listable3 = new Metadata( "listable3", null, true ); //Metadata withCommas = new Metadata( "withcommas", "I, Robot", false ); //Metadata withEquals = new Metadata( "withequals", "name=value", false ); mlist.addMetadata( listable ); mlist.addMetadata( unlistable ); mlist.addMetadata( listable2 ); mlist.addMetadata( unlistable2 ); mlist.addMetadata( listable3 ); //mlist.addMetadata( withCommas ); //mlist.addMetadata( withEquals ); ObjectId id = this.esu.createObjectOnPath( dir, null, mlist, null, null ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); // Read and validate the metadata MetadataList meta = this.esu.getAllMetadata( dir ).getMetadata(); Assert.assertEquals( "value of 'listable' wrong", "foo", meta.getMetadata( "listable" ).getValue() ); Assert.assertEquals( "value of 'listable2' wrong", "foo2 foo2", meta.getMetadata( "listable2" ).getValue() ); Assert.assertEquals( "value of 'unlistable' wrong", "bar", meta.getMetadata( "unlistable" ).getValue() ); Assert.assertEquals( "value of 'unlistable2' wrong", "bar2 bar2", meta.getMetadata( "unlistable2" ).getValue() ); Assert.assertNotNull( "listable3 missing", meta.getMetadata( "listable3" ) ); Assert.assertTrue( "Value of listable3 should be empty", meta.getMetadata( "listable3" ).getValue() == null || meta.getMetadata( "listable3" ).getValue().length() == 0 ); //Assert.assertEquals( "Value of withcommas wrong", "I, Robot", meta.getMetadata( "withcommas" ).getValue() ); //Assert.assertEquals( "Value of withequals wrong", "name=value", meta.getMetadata( "withequals" ).getValue() ); // Check listable flags Assert.assertEquals( "'listable' is not listable", true, meta.getMetadata( "listable" ).isListable() ); Assert.assertEquals( "'listable2' is not listable", true, meta.getMetadata( "listable2" ).isListable() ); Assert.assertEquals( "'listable3' is not listable", true, meta.getMetadata( "listable3" ).isListable() ); Assert.assertEquals( "'unlistable' is listable", false, meta.getMetadata( "unlistable" ).isListable() ); Assert.assertEquals( "'unlistable2' is listable", false, meta.getMetadata( "unlistable2" ).isListable() ); } /** * Tests fetching data with a MultiExtent. */ //@Test public void testMultiExtent() throws Exception { String input = "Four score and seven years ago"; ObjectId id = esu.createObject(null, null, input.getBytes("UTF-8"), "text/plain"); cleanup.add(id); Assert.assertNotNull("Object null", id); MultiExtent me = new MultiExtent(); me.add(new Extent(27,2)); //ag me.add(new Extent(9,1)); // e me.add(new Extent(5,1)); // s me.add(new Extent(4,1)); // ' ' me.add(new Extent(27,3)); // ago Assert.assertEquals("Extent string wrong", "bytes=27-28,9-9,5-5,4-4,27-29", me.toString()); byte[] data = esu.readObject(id, me, null); String out = new String(data, "UTF-8"); Assert.assertEquals("Content incorrect", "ages ago", out); } //---------- Features supported by the Atmos 2.0 REST API. ----------\\ // TODO: If this is not supported, remove it @Ignore("Turned off by default.") @Test public void testHardLink() throws Exception { Assume.assumeFalse(isVipr); ObjectPath op1 = new ObjectPath("/" + rand8char() + ".tmp"); ObjectPath op2 = new ObjectPath("/" + rand8char() + ".tmp"); ObjectId id = this.esu.createObjectOnPath( op1, null, null, "Four score and seven years ago".getBytes( "UTF-8" ), "text/plain" ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); l4j.info("nlink after create: " + this.esu.getSystemMetadata( op1, null).getMetadata("nlink").getValue()); // Rename this.esu.hardLink( op1, op2 ); l4j.info("nlink after hardlink: " + this.esu.getSystemMetadata( op1, null).getMetadata("nlink").getValue()); // Read back the content String content = new String( this.esu.readObject( op2, null, null ), "UTF-8" ); Assert.assertEquals( "object content wrong", "Four score and seven years ago", content ); this.esu.deleteObject(op2); l4j.info("nlink after delete: " + this.esu.getSystemMetadata( op1, null).getMetadata("nlink").getValue()); } @Test public void testGetShareableUrlAndDisposition() throws Exception { Assume.assumeFalse(isVipr); // Create an object with content. String str = "Four score and twenty years ago"; ObjectId id = this.esu.createObject( null, null, str.getBytes( "UTF-8" ), "text/plain" ); Assert.assertNotNull( "null ID returned", id ); cleanup.add( id ); String disposition="attachment; filename=\"foo bar.txt\""; Calendar c = Calendar.getInstance(); c.add( Calendar.HOUR, 4 ); Date expiration = c.getTime(); URL u = this.esu.getShareableUrl( id, expiration, disposition ); l4j.debug( "Sharable URL: " + u ); InputStream stream = (InputStream)u.getContent(); BufferedReader br = new BufferedReader( new InputStreamReader( stream ) ); String content = br.readLine(); l4j.debug( "Content: " + content ); Assert.assertEquals( "URL does not contain proper content", str, content.toString() ); } @Test public void testGetShareableUrlWithPathAndDisposition() throws Exception { Assume.assumeFalse(isVipr); // Create an object with content. String str = "Four score and twenty years ago"; ObjectPath op = new ObjectPath( "/" + rand8char() + ".txt" ); ObjectId id = this.esu.createObjectOnPath( op, null, null, str.getBytes( "UTF-8" ), "text/plain" ); Assert.assertNotNull( "null ID returned", id ); //cleanup.add( op ); String disposition="attachment; filename=\"foo bar.txt\""; Calendar c = Calendar.getInstance(); c.add( Calendar.HOUR, 4 ); Date expiration = c.getTime(); URL u = this.esu.getShareableUrl( op, expiration, disposition ); l4j.debug( "Sharable URL: " + u ); InputStream stream = (InputStream)u.getContent(); BufferedReader br = new BufferedReader( new InputStreamReader( stream ) ); String content = br.readLine(); l4j.debug( "Content: " + content ); Assert.assertEquals( "URL does not contain proper content", str, content.toString() ); } @Test public void testGetShareableUrlWithPathAndUTF8Disposition() throws Exception { Assume.assumeFalse(isVipr); // Create an object with content. String str = "Four score and twenty years ago"; ObjectPath op = new ObjectPath( "/" + rand8char() + ".txt" ); ObjectId id = this.esu.createObjectOnPath( op, null, null, str.getBytes( "UTF-8" ), "text/plain" ); Assert.assertNotNull( "null ID returned", id ); //cleanup.add( op ); // One cryllic, one accented, and one japanese character // RFC5987 String disposition="attachment; filename=\"no UTF support.txt\"; filename*=UTF-8''" + URLEncoder.encode("бöシ.txt", "UTF-8"); Calendar c = Calendar.getInstance(); c.add( Calendar.HOUR, 4 ); Date expiration = c.getTime(); URL u = this.esu.getShareableUrl( op, expiration, disposition ); l4j.debug( "Sharable URL: " + u ); InputStream stream = (InputStream)u.getContent(); BufferedReader br = new BufferedReader( new InputStreamReader( stream ) ); String content = br.readLine(); l4j.debug( "Content: " + content ); Assert.assertEquals( "URL does not contain proper content", str, content.toString() ); } @Test public void testGetServiceInformationFeatures() throws Exception { ServiceInformation info = this.esu.getServiceInformation(); l4j.info("Supported features: " + info.getFeatures()); Assert.assertTrue("Expected at least one feature", info.getFeatures().size()>0); } @Test public void testBug23750() throws Exception { byte[] data = new byte[1000]; Arrays.fill( data, (byte) 0 ); MetadataList mdList = new MetadataList(); mdList.addMetadata( new Metadata( "test", null, true ) ); Checksum sha1 = new Checksum( Checksum.Algorithm.SHA1 ); ObjectId oid = this.esu.createObject( null, mdList, data, null, sha1 ); try { Extent extent = new Extent( 1000, 1000 ); Checksum sha0 = new Checksum( Checksum.Algorithm.SHA0 ); sha0.update( data, 0, 1000 ); this.esu.updateObject( oid, null, mdList, extent, data, null, sha0 ); Assert.fail("Should have triggered an exception"); } catch (EsuException e) { // expected } } @Test public void testCrudKeys() throws Exception { Assume.assumeFalse(isVipr); String keyPool = "Test_key-pool#@!$%^.."; String key = "KEY_TEST"; String content = "Hello World!"; byte[] data = content.getBytes("UTF-8"); ObjectId oid = this.esu.createObjectWithKey( keyPool, key, null, null, data, data.length, "text/plain" ); Assert.assertNotNull( "Null object ID returned", oid ); String readContent = new String( this.esu.readObjectWithKey( keyPool, key, null, null ), "UTF-8" ); Assert.assertEquals( "content mismatch", content, readContent ); content = "Hello Waldo!"; data = content.getBytes( "UTF-8" ); this.esu.updateObjectWithKey( keyPool, key, null, null, null, data, null ); readContent = new String( this.esu.readObjectWithKey( keyPool, key, null, null ), "UTF-8" ); Assert.assertEquals( "content mismatch", content, readContent ); this.esu.deleteObjectWithKey( keyPool, key ); try { this.esu.readObjectWithKey( keyPool, key, null, null ); Assert.fail("Object still exists"); } catch (EsuException e) { if (e.getHttpCode() != 404) throw e; } } @Test public void testIssue9() throws Exception { int threadCount = 10; final int objectSize = 10 * 1000 * 1000; // size is not a power of 2. final MetadataList list = new MetadataList(); list.addMetadata( new Metadata( "test-data", null, true ) ); final EsuApi api = esu; final List<Identifier> cleanupList = cleanup; ThreadPoolExecutor executor = new ThreadPoolExecutor( threadCount, threadCount, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>() ); try { for ( int i = 0; i < threadCount; i++ ) { executor.execute( new Thread() { public void run() { ObjectId oid = api.createObjectFromStream( null, list, new RandomInputStream( objectSize ), objectSize, null ); cleanupList.add( oid ); } } ); } while ( true ) { Thread.sleep( 1000 ); if ( executor.getActiveCount() < 1 ) break; } } finally { executor.shutdown(); } } }