public static String testAccount() {
    return TEST_ACCOUNT;
} public static final Charset OIO_CHARSET = Charset.forName("UTF-8"); public static OioUrl url(String account, String container) {
    return url(account, container, null);
} public class Hex {

	private static final char[] hexArray = "0123456789ABCDEF".toCharArray();

	private byte[] wrapped;
	private String str;

	private Hex(byte[] wrapped, String str) {
		this.wrapped = wrapped;
		this.str = str;
	}

	/**
	 * Wraps the specifies byte array
	 * 
	 * @param bytes
	 *            the array to wrap
	 * @return a new Hex wrapping the array
	 * @throws IllegalArgumentException
	 *             if the specified array is {@code null}
	 */
	public static Hex fromBytes(byte[] bytes) {
		Check.checkArgument(null != bytes);
		return new Hex(bytes, toHex(bytes));
	}

	/**
	 * Converts the specified byte array in its hexadecimal string format (in upper case)
	 * @param bytes the byte array to convert
	 * @return the hexadecimal format
	 */
	public static String toHex(byte[] bytes) {
		char[] hexChars = new char[bytes.length * 2];
		for (int j = 0; j < bytes.length; j++) {
			int v = bytes[j] & 0xFF;
			hexChars[j * 2] = hexArray[v >>> 4];
			hexChars[j * 2 + 1] = hexArray[v & 0x0F];
		}
		return new String(hexChars);
	}

	/**
	 * Returns a copy of the wrapped array
	 * @return a copy of the wrapped array
	 */
	public byte[] bytes() {
		return Arrays.copyOf(wrapped, wrapped.length);
	}

	/**
	 * Returns the hexadecimal string format of the wrapped array
	 * @param upperCase specifies if the result will be in upper case or not
	 * @return the hexadecimal string
	 */
	public String hexString(boolean upperCase) {
		return upperCase ? str : str.toLowerCase();
	}

	@Override
	public String toString() {
		return this.str;
	}

} public class BadRequestException extends OioException {


    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    public BadRequestException(String message) {
        super(message);
    }
} public class ContainerExistException extends OioException {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    public ContainerExistException(String message) {
        super(message);
    }
} public class ContainerNotFoundException extends OioException {

    /**
     * 
     */
    private static final long serialVersionUID = -4662162990209727136L;
    
    public ContainerNotFoundException() {
        super(null);
    }
    public ContainerNotFoundException(String message) {
        super(message);
    }
} public class ObjectNotFoundException extends OioException {

    /**
     * 
     */
    private static final long serialVersionUID = -2995680181164449256L;

    public ObjectNotFoundException() {
        super(null);
    }

    public ObjectNotFoundException(String message) {
        super(message);
    }
} @SuppressWarnings("deprecation")
public class OioException extends SdsException {

    /**
     * 
     */
    private static final long serialVersionUID = 3270900242235005338L;

    public OioException(String message) {
        super(message);
    }

    public OioException(String message, Throwable t) {
        super(message, t);
    }
} public class OioHttpSettings {

	private Integer sendBufferSize = 131072;
	private Integer receiveBufferSize = 131072;
	private Boolean setSocketBufferSize = false;
	private Integer connectTimeout = 30000;
	private Integer readTimeout = 60000;
	private String userAgent = "oio-http";

	public OioHttpSettings() {
	}

	public Integer sendBufferSize() {
		return sendBufferSize;
	}

	public OioHttpSettings sendBufferSize(Integer sendBufferSize) {
		this.sendBufferSize = sendBufferSize;
		return this;
	}

	public Integer receiveBufferSize() {
		return receiveBufferSize;
	}

	public OioHttpSettings receiveBufferSize(Integer receiveBufferSize) {
		this.receiveBufferSize = receiveBufferSize;
		return this;
	}

    /**
     * Should the size of the socket buffers be explicitly set?
     * When true, explicitly set the send buffer size (resp. receive buffer
     * size) to {@link #sendBufferSize} (resp. {@link #receiveBufferSize}).
     * When false, let the kernel adjust the size automatically.
     *
     * @return true when the API should set the socket buffer sizes,
     *  false when it should let the kernel decide.
     */
    public Boolean setSocketBufferSize() {
        return this.setSocketBufferSize;
    }

    /**
     * Should the size of the socket buffers be explicitly set?
     * When true, explicitly set the send buffer size (resp. receive buffer
     * size) to {@link #sendBufferSize} (resp. {@link #receiveBufferSize}).
     * When false, let the kernel adjust the size automatically.
     *
     * @param setSocketBufferSize
     * @return this
     */
    public OioHttpSettings setSocketBufferSize(Boolean setSocketBufferSize) {
        this.setSocketBufferSize = setSocketBufferSize;
        return this;
    }

	public Integer connectTimeout() {
		return connectTimeout;
	}

	public OioHttpSettings connectTimeout(Integer connectTimeout) {
		this.connectTimeout = connectTimeout;
		return this;
	}

	public Integer readTimeout() {
		return readTimeout;
	}

	public OioHttpSettings readTimeout(Integer readTimeout) {
		this.readTimeout = readTimeout;
		return this;
	}

    public String userAgent() {
        return userAgent;
    }

    public OioHttpSettings userAgent(String userAgent) {
        this.userAgent = userAgent;
        return this;
    }
} public class ContainerInfo {

    private String name;
    private String account;
    private Long ctime;
    private Long init;
    private Long usage;
    private Long version;
    private String id;
    private String ns;
    private String type;
    private String user;
    private String schemavers;
    private String versionMainAdmin;
    private String versionMainAliases;
    private String versionMainChunks;
    private String versionMainContents;
    private String versionMainProperties;

    public ContainerInfo(String name) {
        this.name = name;
    }

    public String name() {
        return name;
    }

    public ContainerInfo name(String name) {
        this.name = name;
        return this;
    }

    public String account() {
        return account;
    }

    public ContainerInfo account(String account) {
        this.account = account;
        return this;
    }

    public Long ctime() {
        return ctime;
    }

    public ContainerInfo ctime(Long ctime) {
        this.ctime = ctime;
        return this;
    }

    public Long init() {
        return init;
    }

    public ContainerInfo init(Long init) {
        this.init = init;
        return this;
    }

    public Long usage() {
        return usage;
    }

    public ContainerInfo usage(Long usage) {
        this.usage = usage;
        return this;
    }

    public Long version() {
        return version;
    }

    public ContainerInfo version(Long version) {
        this.version = version;
        return this;
    }

    public String id() {
        return id;
    }

    public ContainerInfo id(String id) {
        this.id = id;
        return this;
    }

    public String ns() {
        return ns;
    }

    public ContainerInfo ns(String ns) {
        this.ns = ns;
        return this;
    }

    public String type() {
        return type;
    }

    public ContainerInfo type(String type) {
        this.type = type;
        return this;
    }

    public String user() {
        return user;
    }

    public ContainerInfo user(String user) {
        this.user = user;
        return this;
    }

    public String schemavers() {
        return schemavers;
    }

    public ContainerInfo schemavers(String schemavers) {
        this.schemavers = schemavers;
        return this;
    }

    public String versionMainAdmin() {
        return versionMainAdmin;
    }

    public ContainerInfo versionMainAdmin(String versionMainAdmin) {
        this.versionMainAdmin = versionMainAdmin;
        return this;
    }

    public String versionMainAliases() {
        return versionMainAliases;
    }

    public ContainerInfo versionMainAliases(String versionMainAliases) {
        this.versionMainAliases = versionMainAliases;
        return this;
    }

    public String versionMainChunks() {
        return versionMainChunks;
    }

    public ContainerInfo versionMainChunks(String versionMainChunks) {
        this.versionMainChunks = versionMainChunks;
        return this;
    }

    public String versionMainContents() {
        return versionMainContents;
    }

    public ContainerInfo versionMainContents(String versionMainContents) {
        this.versionMainContents = versionMainContents;
        return this;
    }

    public String versionMainProperties() {
        return versionMainProperties;
    }

    public ContainerInfo versionMainProperties(
            String versionMainProperties) {
        this.versionMainProperties = versionMainProperties;
        return this;
    }

    @Override
    public String toString() {
        return MoreObjects.toStringHelper(this)
                .omitNullValues()
                .add("name", name)
                .add("account", account)
                .add("m2-ctime", ctime)
                .add("m2-init", init)
                .add("m2-usage", usage)
                .add("id", id)
                .add("ns", ns)
                .add("type", type)
                .add("user-name", user)
                .toString();
    }
} public class NamespaceInfo {

    private String ns;
    private Long chunksize;
    private Map<String, String> options;
    @SerializedName("storage_policy")
    private Map<String, String> storagePolicies;
    @SerializedName("storage_class")
    private Map<String, String> storageClasses;
    @SerializedName("data_security")
    private Map<String, String> dataSecurities;
    @SerializedName("data_treatments")
    private Map<String, String> dataTreatments;

    public NamespaceInfo() {
    }

    public String ns() {
        return ns;
    }

    public NamespaceInfo ns(String ns) {
        this.ns = ns;
        return this;
    }

    public Long chunksize() {
        return chunksize;
    }

    public NamespaceInfo chunksize(Long chunksize) {
        this.chunksize = chunksize;
        return this;
    }

    public Map<String, String> options() {
        return options;
    }

    public NamespaceInfo options(Map<String, String> options) {
        this.options = options;
        return this;
    }

    public Map<String, String> storagePolicies() {
        return storagePolicies;
    }

    public NamespaceInfo storagePolicies(Map<String, String> storagePolicies) {
        this.storagePolicies = storagePolicies;
        return this;
    }

    public Map<String, String> storageClasses() {
        return storageClasses;
    }

    public NamespaceInfo storageClasses(Map<String, String> storageClasses) {
        this.storageClasses = storageClasses;
        return this;
    }

    public Map<String, String> dataSecurities() {
        return dataSecurities;
    }

    public NamespaceInfo dataSecurities(Map<String, String> dataSecurities) {
        this.dataSecurities = dataSecurities;
        return this;
    }

    public Map<String, String> dataTreatments() {
        return dataTreatments;
    }

    public NamespaceInfo dataTreatments(Map<String, String> dataTreatments) {
        this.dataTreatments = dataTreatments;
        return this;
    }

} public class ObjectCreationOptions {

    private Long version;
    private Map<String, String> properties;
    private String policy;
    private String mimeType;
    private boolean simulateVersioning = false;

    public Long version() {
        return version;
    }

    public ObjectCreationOptions version(Long version) {
        this.version = version;
        return this;
    }

    public Map<String, String> properties() {
        return properties;
    }

    public ObjectCreationOptions properties(Map<String, String> properties) {
        this.properties = properties;
        return this;
    }

    public String policy() {
        return policy;
    }

    public ObjectCreationOptions policy(String policy) {
        this.policy = policy;
        return this;
    }

    public String mimeType() {
        return mimeType;
    }

    public ObjectCreationOptions mimeType(String mimeType) {
        this.mimeType = mimeType;
        return this;
    }

    public boolean simulateVersioning() {
        return simulateVersioning;
    }

    public ObjectCreationOptions simulateVersioning(boolean simulateVersioning) {
        this.simulateVersioning = simulateVersioning;
        return this;
    }

} public class ObjectDeletionOptions {

    private Long version;
    private boolean simulateVersioning = false;
    private boolean deleteMarker = false;

    public Long version() {
        return version;
    }

    public ObjectDeletionOptions version(Long version) {
        this.version = version;
        return this;
    }

    public boolean simulateVersioning() {
        return simulateVersioning;
    }

    public ObjectDeletionOptions simulateVersioning(boolean simulateVersioning) {
        this.simulateVersioning = simulateVersioning;
        return this;
    }

    public boolean deleteMarker() {
        return deleteMarker;
    }

    public ObjectDeletionOptions deleteMarker(boolean deleteMarker) {
        this.deleteMarker = deleteMarker;
        return this;
    }

} public class ObjectInfo {

    private OioUrl url;
    private String oid;
    private Long ctime;
    private Boolean deleted = false;
    private String policy;
    private String hash;
    private String hashMethod;
    private String chunkMethod;
    private Long size;
    private Long version;
    private String mimeType;
    private Map<String, String> properties;
    private List<ChunkInfo> chunks;
    private ECInfo ecinfo;
    private RequestContext reqCtx;

    private transient Map<Integer, List<ChunkInfo>> sortedChunks;

    private static final Comparator<ChunkInfo> comparator = new Comparator<ChunkInfo>() {

        @Override
        public int compare(ChunkInfo c1, ChunkInfo c2) {
            return c1.pos()
                    .compare(c2.pos());
        }
    };

    public ObjectInfo() {
        // TODO: content hash
        this.properties = new HashMap<String, String>();
        this.hash = Hash.md5()
                .hashBytes("".getBytes(OIO_CHARSET))
                .toString();
    }

    public List<ChunkInfo> chunks() {
        return chunks;
    }

    public Map<Integer, List<ChunkInfo>> sortedChunks() {
        return sortedChunks;
    }

    public ObjectInfo chunks(List<ChunkInfo> chunks) {
        this.sortedChunks = sortChunks(chunks);
        this.chunks = chunks;
        return this;
    }

    public ObjectInfo size(Long size) {
        this.size = size;
        return this;
    }

    public ObjectInfo hash(String hash) {
        this.hash = hash;
        return this;
    }

    public ObjectInfo url(OioUrl url) {
        this.url = url;
        return this;
    }

    public OioUrl url() {
        return url;
    }

    public String oid() {
        return oid;
    }

    public ObjectInfo oid(String oid) {
        this.oid = oid;
        return this;
    }

    public String hash() {
        return hash;
    }

    public Long size() {
        return size;
    }

    public String policy() {
        return policy;
    }

    public ObjectInfo policy(String policy) {
        this.policy = policy;
        return this;
    }

    public boolean deleted() {
        return deleted;
    }

    public Long ctime() {
        return ctime;
    }

    public ObjectInfo ctime(Long ctime) {
        this.ctime = ctime;
        return this;
    }

    public String hashMethod() {
        return hashMethod;
    }

    public ObjectInfo hashMethod(String hashMethod) {
        this.hashMethod = hashMethod;
        return this;
    }

    public String chunkMethod() {
        return chunkMethod;
    }

    public ObjectInfo chunkMethod(String chunkMethod) {
        this.chunkMethod = chunkMethod;
        this.ecinfo = ECInfo.fromString(chunkMethod);
        return this;
    }

    public Long version() {
        return version;
    }

    public ObjectInfo version(Long version) {
        this.version = version;
        return this;
    }

    @Deprecated
    public String mtype() {
        return mimeType();
    }

    @Deprecated
    public ObjectInfo mtype(String mimeType) {
        return mimeType(mimeType);
    }

    public String mimeType() {
        return mimeType;
    }

    public ObjectInfo mimeType(String mimeType) {
        this.mimeType = mimeType;
        return this;
    }

    public Integer nbchunks() {
        return isEC() ? chunks.size() : sortedChunks.size();
    }

    public Long chunksize(Integer pos) {
        return sortedChunks.get(pos).get(0).size();
    }

    public Map<String, String> properties() {
        return properties;
    }

    public ObjectInfo properties(Map<String, String> properties) {
        this.properties = properties;
        return this;
    }

    public ECInfo ecinfo(){
    	return ecinfo;
    }

    public boolean isEC(){
    	return null != ecinfo;
    }

    public long metachunksize(int pos) {
        if (!isEC())
            return -1;
        long maxmcsize = ecinfo.k() * sortedChunks.get(pos).get(0).size();
        long remaining = size - (pos * maxmcsize);
        return Math.min(maxmcsize, remaining);
    }

    /**
     * @return a string suitable to be sent as {@code CHUNK_META_FULL_PATH} header value.
     */
    public String fullpath() {
        if (this.url.account() == null || this.url.account().isEmpty()
                || this.url.container() == null || this.url.container().isEmpty()
                || this.url.object() == null || this.url.object().isEmpty()
                || this.version() == null || this.version() == 0
                || this.oid() == null || this.oid().isEmpty()) {
            throw new IllegalArgumentException("Can't encode fullpath");
        }
        StringBuilder sb = new StringBuilder();
        sb.append(Strings.quote(this.url.account()));
        sb.append('/');
        sb.append(Strings.quote(this.url.container()));
        sb.append('/');
        sb.append(Strings.quote(this.url.object()));
        sb.append('/');
        sb.append(Strings.quote(this.version()));
        sb.append('/');
        sb.append(Strings.quote(this.oid()));
        return sb.toString();
    }

    @Override
    public String toString() {
        return MoreObjects.toStringHelper(this)
                .omitNullValues()
                .add("url", url)
                .add("ctime", ctime)
                .add("mime-type", mimeType)
                .add("deleted", deleted)
                .add("policy", policy)
                .add("hash", hash)
                .add("hash-method", hashMethod)
                .add("chunk-method", chunkMethod)
                .add("size", size)
                .add("version", version)
                .add("props", properties)
                .add("chunks", chunks)
                .toString();
    }

    public RequestContext requestContext() {
        return this.reqCtx;
    }

    /**
     * Set the context of the request that lead to this object's creation.
     *
     * @param reqCtx
     *            the request context
     * @return {@code this}
     */
    public ObjectInfo withRequestContext(RequestContext reqCtx) {
        this.reqCtx = reqCtx;
        return this;
    }

    /* -- INTERNAL -- */

    private Map<Integer, List<ChunkInfo>> sortChunks(
            List<ChunkInfo> chunks) {

        Map<Integer, List<ChunkInfo>> res = new HashMap<Integer, List<ChunkInfo>>();
        for (ChunkInfo ci : chunks) {
            List<ChunkInfo> l = res.get(ci.pos().meta());
            if (null == l) {
                l = new ArrayList<ChunkInfo>();
                res.put(ci.pos().meta(), l);
            }
            l.add(ci);
        }
        for (List<ChunkInfo> l : res.values())
            Collections.sort(l, comparator);

        return res;
    }

} public class OioUrl {

    private static final byte[] BACK_ZERO = { '\0' };

    private String ns;
    private String account;
    private String container;
    private String cid;
    private String object;

    private OioUrl(String ns, String account, String container, String cid,
            String object) {
        this.ns = ns;
        this.account = account;
        this.container = container;
        this.cid = cid;
        this.object = object;
    }
    
    
    
    public static OioUrl url(String account, String container) {
        return url(account, container, null);
    }

    public static OioUrl url(String account, String container,
            String object) {
        checkArgument(!nullOrEmpty(account),
                "account cannot be null or empty");
        checkArgument(!nullOrEmpty(container),
                "container cannot be null or empty");
        return new OioUrl(null,
                account,
                container,
                cid(account, container),
                object);
    }
    
    public static OioUrl url(String ns, String account, String container,
            String object) {
        checkArgument(!nullOrEmpty(account),
                "account cannot be null or empty");
        checkArgument(!nullOrEmpty(container),
                "container cannot be null or empty");
        return new OioUrl(ns, 
                account,
                container,
                cid(account, container),
                object);
    }

    public String namespace() {
        return ns;
    }

    public OioUrl namespace(String namespace) {
        this.ns = namespace;
        return this;
    }

    public String account() {
        return account;
    }

    public OioUrl account(String account) {
        this.account = account;
        return this;
    }

    public String container() {
        return container;
    }

    public OioUrl container(String container) {
        this.container = container;
        return this;
    }

    public String object() {
        return object;
    }

    public OioUrl object(String object) {
        this.object = object;
        return this;
    }

    public String cid() {
        return cid;
    }

    @Override
    public String toString() {
        return MoreObjects.toStringHelper(this)
                .omitNullValues()
                .add("namespace", ns)
                .add("account", account)
                .add("container", container)
                .add("object", object)
                .toString();
    }

    /**
     * Generates the container id from the specified account and container name
     * 
     * @param account
     *            the name of the account
     * @param container
     *            the name of the container
     * @return the generated id
     */
    public static String cid(String account, String container) {
        return Hash.sha256()
                .putBytes(account.getBytes(OIO_CHARSET))
                .putBytes(BACK_ZERO)
                .putBytes(container.getBytes(OIO_CHARSET))
                .hash().toString();
    }

} public class Range {

    private static final Pattern RANGE_PATTERN = Pattern
            .compile("^([\\d]+)?-([\\d]+)?$");

    private long from = 0;
    private long to = -1;

    private Range(long from, long to) {
        this.from = from;
        this.to = to;
    }

    public static Range upTo(long to) {
        checkArgument(0 < to);
        return new Range(0, to);
    }

    public static Range from(long from) {
        checkArgument(0 <= from);
        return new Range(from, -1);
    }

    public static Range between(long from, long to) {
        checkArgument(from >= 0 && to > 0 && to >= from,
                "Invalid range");
        return new Range(from, to);
    }

    public static Range parse(String str) {
        Matcher m = RANGE_PATTERN.matcher(str);
        checkArgument(m.matches());
        if (null == m.group(1)) {
            checkArgument(null != m.group(2), "useless range");
            return upTo(parseInt(m.group(2)));
        }
        return (null == m.group(2)) ? from(parseInt(m.group(1)))
                : between(parseInt(m.group(1)), parseInt(m.group(2)));
    }

    public long from() {
        return from;
    }

    public long to() {
        return to;
    }

    public String headerValue() {
        return to < 0
                ? format("bytes=%d-", from)
                : format("bytes=%d-%d", from, to);
    }

    public String rangeValue() {
        return to < 0
                ? format("%d-", from)
                : format("%d-%d", from, to);
    }

    @Override
    public String toString() {
        return MoreObjects.toStringHelper(this)
                .add("from", from)
                .add("to", to)
                .toString();
    }
}
import static io.openio.sds.TestHelper.testAccount;
import static io.openio.sds.common.OioConstants.OIO_CHARSET;
import static io.openio.sds.models.OioUrl.url;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import io.openio.sds.common.Hex;
import io.openio.sds.exceptions.BadRequestException;
import io.openio.sds.exceptions.ContainerExistException;
import io.openio.sds.exceptions.ContainerNotFoundException;
import io.openio.sds.exceptions.ObjectNotFoundException;
import io.openio.sds.exceptions.OioException;
import io.openio.sds.http.OioHttpSettings;
import io.openio.sds.models.ContainerInfo;
import io.openio.sds.models.NamespaceInfo;
import io.openio.sds.models.ObjectCreationOptions;
import io.openio.sds.models.ObjectDeletionOptions;
import io.openio.sds.models.ObjectInfo;
import io.openio.sds.models.OioUrl;
import io.openio.sds.models.Range;
        } catch (BadRequestException exc) {
            throw exc;
        } finally {
            client.deleteContainer(url);
        }
    }

    @Test
    public void handleSizedObject() throws IOException,
            NoSuchAlgorithmException {
        byte[] src = TestHelper.bytes(1024L);
        OioUrl url = url(testAccount(), UUID.randomUUID().toString(), UUID
                .randomUUID().toString());
        client.createContainer(url);
        try {
            client.putObject(url, 1024L, new ByteArrayInputStream(src));
            try {
                ObjectInfo oinf = client.getObjectInfo(url);
                Assert.assertNotNull(oinf);
                Assert.assertEquals(1024, oinf.size().longValue());
                Assert.assertTrue(0 < oinf.ctime());
                Assert.assertNotNull(oinf.policy());
                Assert.assertNotNull(oinf.chunkMethod());
                Assert.assertNotNull(oinf.hashMethod());
                checkObject(oinf, new ByteArrayInputStream(src));
                Assert.assertEquals(
                        Hex.toHex(MessageDigest.getInstance("MD5").digest(src)),
                        oinf.hash());
            } finally {
                client.deleteObject(url);
            }
        } finally {
            client.deleteContainer(url);
        }
    }

    @Test
    public void handleSizedObjectSmallBuffers() throws IOException,
            NoSuchAlgorithmException {
        Settings newSettings = TestHelper.settings();
        newSettings.rawx().http().setSocketBufferSize(true).sendBufferSize(16384)
                .receiveBufferSize(16384);
        newSettings.proxy().http().setSocketBufferSize(true).sendBufferSize(8192)
                .receiveBufferSize(8192);
        Client prevClient = client;
        client = ClientBuilder.newClient(newSettings);
        try {
            this.handleSizedObject();
        } finally {
            client = prevClient;
        }
    }

    @Test
    public void range() throws IOException, NoSuchAlgorithmException {
        byte[] src = TestHelper.bytes(1024L);
        OioUrl url = url(testAccount(), UUID.randomUUID().toString(), UUID
                .randomUUID().toString());
        client.createContainer(url);

        byte[] ranged = Arrays.copyOfRange(src, 10, 20);

        try {
            client.putObject(url, 1024L, new ByteArrayInputStream(src));
            try {
                ObjectInfo oinf = client.getObjectInfo(url);
                Assert.assertNotNull(oinf);
                Assert.assertEquals(1024, oinf.size().longValue());
                Assert.assertTrue(0 < oinf.ctime());
                Assert.assertNotNull(oinf.policy());
                Assert.assertNotNull(oinf.chunkMethod());
                Assert.assertNotNull(oinf.hashMethod());
                checkObject(oinf, Range.between(10, 20),
                        new ByteArrayInputStream(ranged));
                Assert.assertEquals(
                        Hex.toHex(MessageDigest.getInstance("MD5").digest(src)),
                        oinf.hash());
            } finally {
                client.deleteObject(url);
            }
        } finally {
            client.deleteContainer(url);
        }

    }

    @Test
    public void handleMultiChunkObject() throws IOException,
            NoSuchAlgorithmException {
        byte[] src = TestHelper.bytes(10 * 1000 * 1024L);
        OioUrl url = url(testAccount(), UUID.randomUUID().toString(), UUID
                .randomUUID().toString());

        client.createContainer(url);
        try {
            client.putObject(url, 10 * 1000 * 1024L, new ByteArrayInputStream(
                    src));
            try {
                ObjectInfo oinf = client.getObjectInfo(url);
                Assert.assertNotNull(oinf);
                checkObject(oinf, new ByteArrayInputStream(src));
                Assert.assertEquals(
                        Hex.toHex(MessageDigest.getInstance("MD5").digest(src)),
                        oinf.hash());
            } finally {
                try {
                    client.deleteObject(url);
                } catch (OioException e) {
                    System.out.println("Failed to delete object " + url + ": " + e);
                }
            }
        } finally {
            try {
                client.deleteContainer(url);
            } catch (OioException e) {
                System.out.println("Failed to delete container " + url + ": " + e);
            }
        }
    }

    @Test(expected = ObjectNotFoundException.class)