Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add UnitTests and Utilities.

Add UnitTest project.
Add Utilities project.
Add Target SDK to API Level 10.
  • Loading branch information...
commit 8b19546de549a014a4abeb156e970f4cc9167688 1 parent 1eca7c7
Simon Krueger skrueger authored
Showing with 3,759 additions and 1 deletion.
  1. +1 −1  sample/AndroidManifest.xml
  2. +9 −0 unittest/.classpath
  3. +35 −0 unittest/.project
  4. +15 −0 unittest/AndroidManifest.xml
  5. +93 −0 unittest/build.xml
  6. +40 −0 unittest/proguard.cfg
  7. +13 −0 unittest/project.properties
  8. +46 −0 unittest/src/com/microsoft/live/TestUtils.java
  9. +349 −0 unittest/src/com/microsoft/live/unittest/ApiTest.java
  10. +87 −0 unittest/src/com/microsoft/live/unittest/CopyTest.java
  11. +143 −0 unittest/src/com/microsoft/live/unittest/DeleteTest.java
  12. +133 −0 unittest/src/com/microsoft/live/unittest/DownloadTest.java
  13. +91 −0 unittest/src/com/microsoft/live/unittest/FileOperationApiTest.java
  14. +150 −0 unittest/src/com/microsoft/live/unittest/GetTest.java
  15. +45 −0 unittest/src/com/microsoft/live/unittest/JsonEnclosingApiTest.java
  16. +87 −0 unittest/src/com/microsoft/live/unittest/MoveTest.java
  17. +212 −0 unittest/src/com/microsoft/live/unittest/PostTest.java
  18. +218 −0 unittest/src/com/microsoft/live/unittest/PutTest.java
  19. +363 −0 unittest/src/com/microsoft/live/unittest/UploadTest.java
  20. +8 −0 utilities/.classpath
  21. +33 −0 utilities/.project
  22. +9 −0 utilities/AndroidManifest.xml
  23. +90 −0 utilities/build.xml
  24. +40 −0 utilities/proguard.cfg
  25. +13 −0 utilities/project.properties
  26. +11 −0 utilities/src/com/microsoft/live/constants/ErrorCodes.java
  27. +25 −0 utilities/src/com/microsoft/live/constants/ErrorMessages.java
  28. +37 −0 utilities/src/com/microsoft/live/constants/JsonKeys.java
  29. +13 −0 utilities/src/com/microsoft/live/constants/Paths.java
  30. +38 −0 utilities/src/com/microsoft/live/constants/Scopes.java
  31. +133 −0 utilities/src/com/microsoft/live/mock/MockHttpClient.java
  32. +96 −0 utilities/src/com/microsoft/live/mock/MockHttpEntity.java
  33. +180 −0 utilities/src/com/microsoft/live/mock/MockHttpResponse.java
  34. +8 −0 utilities/src/com/microsoft/live/test/util/AssertMessages.java
  35. +52 −0 utilities/src/com/microsoft/live/test/util/AsyncRunnable.java
  36. +108 −0 utilities/src/com/microsoft/live/test/util/AsyncRunnableWithBody.java
  37. +31 −0 utilities/src/com/microsoft/live/test/util/AsyncRunnableWithDestination.java
  38. +45 −0 utilities/src/com/microsoft/live/test/util/CopyAsyncRunnable.java
  39. +35 −0 utilities/src/com/microsoft/live/test/util/DeleteAsyncRunnable.java
  40. +66 −0 utilities/src/com/microsoft/live/test/util/DownloadAsyncRunnable.java
  41. +34 −0 utilities/src/com/microsoft/live/test/util/DownloadOperationQueueingListener.java
  42. +35 −0 utilities/src/com/microsoft/live/test/util/GetAsyncRunnable.java
  43. +39 −0 utilities/src/com/microsoft/live/test/util/MoveAsyncRunnable.java
  44. +28 −0 utilities/src/com/microsoft/live/test/util/OperationQueueingListener.java
  45. +67 −0 utilities/src/com/microsoft/live/test/util/PostAsyncRunnable.java
  46. +67 −0 utilities/src/com/microsoft/live/test/util/PutAsyncRunnable.java
  47. +16 −0 utilities/src/com/microsoft/live/test/util/QueueingListener.java
  48. +150 −0 utilities/src/com/microsoft/live/test/util/UploadAsyncRunnable.java
  49. +32 −0 utilities/src/com/microsoft/live/test/util/UploadOperationQueueingListener.java
  50. +20 −0 utilities/src/com/microsoft/live/util/NullLiveAuthListener.java
  51. +27 −0 utilities/src/com/microsoft/live/util/NullLiveDownloadOperationListener.java
  52. +19 −0 utilities/src/com/microsoft/live/util/NullLiveOperationListener.java
  53. +24 −0 utilities/src/com/microsoft/live/util/NullLiveUploadOperationListener.java
2  sample/AndroidManifest.xml
View
@@ -2,7 +2,7 @@
<manifest package="com.microsoft.live.sample"
android:versionCode="1"
android:versionName="1.0" xmlns:android="http://schemas.android.com/apk/res/android">
- <uses-sdk android:minSdkVersion="8" />
+ <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="10"/>
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
9 unittest/.classpath
View
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="gen"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/LiveSdk"/>
+ <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
+ <classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
+ <classpathentry kind="output" path="bin/classes"/>
+</classpath>
35 unittest/.project
View
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>LiveSdkUnitTest</name>
+ <comment></comment>
+ <projects>
+ <project>LiveSdk</project>
+ <project>LiveSdkSample</project>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>com.android.ide.eclipse.adt.ApkBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>com.android.ide.eclipse.adt.AndroidNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
15 unittest/AndroidManifest.xml
View
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.microsoft.live.unittest"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="10"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+ <instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="com.microsoft.live.sample"></instrumentation>
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+</manifest>
93 unittest/build.xml
View
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="LiveSdkUnitTest" default="help">
+
+ <!-- build.properties has the sdk.dir.
+ Must load environment variables before including it. -->
+ <property environment="env" />
+ <property file="../build.properties" />
+
+ <!-- The local.properties file is created and updated by the 'android' tool.
+ It contains the path to the SDK. It should *NOT* be checked into
+ Version Control Systems. -->
+ <property file="local.properties" />
+
+ <!-- The ant.properties file can be created by you. It is only edited by the
+ 'android' tool to add properties to it.
+ This is the place to change some Ant specific build properties.
+ Here are some properties you may want to change/update:
+
+ source.dir
+ The name of the source directory. Default is 'src'.
+ out.dir
+ The name of the output directory. Default is 'bin'.
+
+ For other overridable properties, look at the beginning of the rules
+ files in the SDK, at tools/ant/build.xml
+
+ Properties related to the SDK location or the project target should
+ be updated using the 'android' tool with the 'update' action.
+
+ This file is an integral part of the build system for your
+ application and should be checked into Version Control Systems.
+
+ -->
+ <property file="ant.properties" />
+
+ <!-- The project.properties file is created and updated by the 'android'
+ tool, as well as ADT.
+
+ This contains project specific properties such as project target, and library
+ dependencies. Lower level build properties are stored in ant.properties
+ (or in .classpath for Eclipse projects).
+
+ This file is an integral part of the build system for your
+ application and should be checked into Version Control Systems. -->
+ <loadproperties srcFile="project.properties" />
+
+ <!-- quick check on sdk.dir -->
+ <fail
+ message="sdk.dir is missing. Make sure to generate local.properties using 'android update project'"
+ unless="sdk.dir"
+ />
+
+
+<!-- extension targets. Uncomment the ones where you want to do custom work
+ in between standard targets -->
+<!--
+ <target name="-pre-build">
+ </target>
+ <target name="-pre-compile">
+ </target>
+
+ /* This is typically used for code obfuscation.
+ Compiled code location: ${out.classes.absolute.dir}
+ If this is not done in place, override ${out.dex.input.absolute.dir} */
+ <target name="-post-compile">
+ </target>
+-->
+
+ <!-- Import the actual build file.
+
+ To customize existing targets, there are two options:
+ - Customize only one target:
+ - copy/paste the target into this file, *before* the
+ <import> task.
+ - customize it to your needs.
+ - Customize the whole content of build.xml
+ - copy/paste the content of the rules files (minus the top node)
+ into this file, replacing the <import> task.
+ - customize to your needs.
+
+ ***********************
+ ****** IMPORTANT ******
+ ***********************
+ In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
+ in order to avoid having your file be overridden by tools such as "android update project"
+ -->
+ <!-- version-tag: custom -->
+ <import file="${sdk.dir}/tools/ant/build.xml" />
+
+
+
+
+</project>
40 unittest/proguard.cfg
View
@@ -0,0 +1,40 @@
+-optimizationpasses 5
+-dontusemixedcaseclassnames
+-dontskipnonpubliclibraryclasses
+-dontpreverify
+-verbose
+-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
+
+-keep public class * extends android.app.Activity
+-keep public class * extends android.app.Application
+-keep public class * extends android.app.Service
+-keep public class * extends android.content.BroadcastReceiver
+-keep public class * extends android.content.ContentProvider
+-keep public class * extends android.app.backup.BackupAgentHelper
+-keep public class * extends android.preference.Preference
+-keep public class com.android.vending.licensing.ILicensingService
+
+-keepclasseswithmembernames class * {
+ native <methods>;
+}
+
+-keepclasseswithmembers class * {
+ public <init>(android.content.Context, android.util.AttributeSet);
+}
+
+-keepclasseswithmembers class * {
+ public <init>(android.content.Context, android.util.AttributeSet, int);
+}
+
+-keepclassmembers class * extends android.app.Activity {
+ public void *(android.view.View);
+}
+
+-keepclassmembers enum * {
+ public static **[] values();
+ public static ** valueOf(java.lang.String);
+}
+
+-keep class * implements android.os.Parcelable {
+ public static final android.os.Parcelable$Creator *;
+}
13 unittest/project.properties
View
@@ -0,0 +1,13 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-8
+android.library.reference.1=../src
+android.library.reference.2=../utilities
46 unittest/src/com/microsoft/live/TestUtils.java
View
@@ -0,0 +1,46 @@
+package com.microsoft.live;
+
+
+import java.util.Arrays;
+import java.util.Calendar;
+
+import org.apache.http.client.HttpClient;
+
+import android.content.Context;
+import android.test.mock.MockApplication;
+
+/**
+ * This class has access to default (i.e., internal) classes and methods inside of com.microsoft.live.
+ * It is used to assist test cases.
+ */
+public final class TestUtils {
+
+ public static LiveConnectClient newLiveConnectClient(HttpClient client) {
+ LiveAuthClient authClient = new LiveAuthClient(new MockApplication() {
+ @Override
+ public Context getApplicationContext() {
+ return this;
+ }
+ }, "someclientid");
+
+ LiveConnectSession session = new LiveConnectSession(authClient);
+ session.setAccessToken("access_token");
+ session.setAuthenticationToken("authentication_token");
+
+ Calendar calendar = Calendar.getInstance();
+ calendar.add(Calendar.SECOND, 3600);
+ session.setExpiresIn(calendar.getTime());
+
+ String[] scopes = {"scope"};
+ session.setScopes(Arrays.asList(scopes));
+ session.setRefreshToken("refresh_token");
+ session.setTokenType("token_type");
+
+ LiveConnectClient liveClient = new LiveConnectClient(session);
+ liveClient.setHttpClient(client);
+
+ return liveClient;
+ }
+
+ private TestUtils() { throw new AssertionError(); }
+}
349 unittest/src/com/microsoft/live/unittest/ApiTest.java
View
@@ -0,0 +1,349 @@
+package com.microsoft.live.unittest;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.http.Header;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.HttpVersion;
+import org.apache.http.StatusLine;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.message.BasicStatusLine;
+import org.apache.http.protocol.HTTP;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.os.Build;
+import android.test.InstrumentationTestCase;
+
+import com.microsoft.live.LiveConnectClient;
+import com.microsoft.live.LiveDownloadOperation;
+import com.microsoft.live.LiveOperation;
+import com.microsoft.live.LiveOperationException;
+import com.microsoft.live.TestUtils;
+import com.microsoft.live.constants.ErrorCodes;
+import com.microsoft.live.constants.ErrorMessages;
+import com.microsoft.live.constants.JsonKeys;
+import com.microsoft.live.mock.MockHttpClient;
+import com.microsoft.live.mock.MockHttpEntity;
+import com.microsoft.live.mock.MockHttpResponse;
+import com.microsoft.live.test.util.AssertMessages;
+import com.microsoft.live.test.util.AsyncRunnable;
+
+public abstract class ApiTest<OperationType, ListenerType> extends InstrumentationTestCase {
+
+ private static final String INVALID_FORMAT = "!@#098 {} [] This is an invalid formated " +
+ "response body asdfkaj{}dfa(*&!@#";
+
+ /**
+ * Changes the mockClient to one that checks if the incoming requests contains the
+ * Live Library header and then reverts to the original mockClient.
+ */
+ protected void loadLiveLibraryHeaderChecker() {
+ final MockHttpClient currentMockClient = this.mockClient;
+ MockHttpClient liveLibraryHeaderCheckerClient = new MockHttpClient() {
+ @Override
+ public HttpResponse execute(HttpUriRequest request) throws IOException,
+ ClientProtocolException {
+ Header header = request.getFirstHeader("X-HTTP-Live-Library");
+
+ assertEquals("android/" + Build.VERSION.RELEASE + "_5.0", header.getValue());
+
+ // load the old mock client back after we check.
+ mockClient = currentMockClient;
+ return currentMockClient.execute(request);
+ }
+
+ @Override
+ public HttpResponse getHttpResponse() {
+ return currentMockClient.getHttpResponse();
+ }
+
+ @Override
+ public void setHttpResponse(HttpResponse httpResponse) {
+ currentMockClient.setHttpResponse(httpResponse);
+ }
+
+ @Override
+ public void addHttpResponse(HttpResponse httpResponse) {
+ currentMockClient.addHttpResponse(httpResponse);
+ }
+
+ @Override
+ public void clearHttpResponseQueue() {
+ currentMockClient.clearHttpResponseQueue();
+ }
+ };
+
+ this.mockClient = liveLibraryHeaderCheckerClient;
+ }
+
+ /** wait time to retrieve a response from a blocking queue for an async call*/
+ protected static int WAIT_TIME_IN_SECS = 10;
+
+ protected static void assertEquals(InputStream is, String response) throws IOException {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+ StringBuilder sb = new StringBuilder();
+
+ try {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ sb.append(line);
+ }
+ } finally {
+ // Close silently.
+ // Close could throw an exception, and if we don't catch it, it will trump
+ // the originally thrown exception.
+ // Unfortunately, this means that if there was a problem only with close the reader,
+ // it will be ignored. I assume we can safely ignore this case, because if there is
+ // a problem closing a stream, there is little we can do to correc this.
+ try { reader.close(); } catch (Exception e) { }
+ }
+
+ assertEquals(response, sb.toString());
+ }
+
+ protected BlockingQueue<LiveOperationException> exceptionQueue;
+ protected LiveConnectClient liveConnectClient;
+ protected MockHttpClient mockClient;
+ protected MockHttpEntity mockEntity;
+ protected MockHttpResponse mockResponse;
+ protected ListenerType queueingListener;
+ protected BlockingQueue<OperationType> responseQueue;
+
+ public abstract void testAsyncResponseBodyInvalid() throws Throwable;
+ public abstract void testAsyncResponseBodyValid() throws Throwable;
+ public abstract void testAsyncResponseBodyValidWithUserState() throws Throwable;
+ public abstract void testSyncResponseBodyInvalid() throws Exception;
+ public abstract void testSyncResponseBodyValid() throws Exception;
+
+ protected abstract void checkValidResponseBody(OperationType operation) throws Exception;
+ protected abstract AsyncRunnable<OperationType, ListenerType> createAsyncRunnable(String requestPath);
+ protected abstract AsyncRunnable<OperationType, ListenerType> createAsyncRunnable(String requestPath,
+ Object userState);
+ protected abstract void loadValidResponseBody() throws Exception;
+ protected abstract String getMethod();
+
+ protected void checkOperationMembers(LiveDownloadOperation operation,
+ String method,
+ String path) {
+ this.checkOperationMembers(operation, method, path, null);
+ }
+
+
+ protected void checkOperationMembers(LiveDownloadOperation operation,
+ String method,
+ String path,
+ Object userState) {
+ assertEquals(method, operation.getMethod());
+ assertEquals(path, operation.getPath());
+ assertEquals(userState, operation.getUserState());
+ }
+
+ /**
+ * Asserts that the given LiveOperation has the correct method, path, and userState
+ *
+ * @param operation
+ * @param method
+ * @param path
+ */
+ protected void checkOperationMembers(LiveOperation operation,
+ String method,
+ String path) {
+ this.checkOperationMembers(operation, method, path, null);
+ }
+
+ /**
+ * Asserts that the given LiveOperation has the correct method, path, and userState.
+ *
+ * @param operation
+ * @param method
+ * @param path
+ * @param userState
+ */
+ protected void checkOperationMembers(LiveOperation operation,
+ String method,
+ String path,
+ Object userState) {
+ assertEquals(method, operation.getMethod());
+ assertEquals(path, operation.getPath());
+ assertEquals(userState, operation.getUserState());
+ }
+
+ /**
+ * Asserts the response contains the error for an Invalid Path.
+ *
+ * @param operation
+ * @param requestPath
+ * @throws JSONException
+ */
+ protected void checkPathInvalid(LiveOperation operation,
+ String requestPath) throws JSONException {
+ JSONObject result = operation.getResult();
+ JSONObject error = result.getJSONObject(JsonKeys.ERROR);
+ String message = error.getString(JsonKeys.MESSAGE);
+ String code = error.getString(JsonKeys.CODE);
+
+ assertEquals(String.format(ErrorMessages.URL_NOT_VALID, requestPath.toLowerCase()),
+ message);
+ assertEquals(ErrorCodes.REQUEST_URL_INVALID, code);
+
+ String rawResult = operation.getRawResult();
+ assertEquals(result.toString(), rawResult);
+ }
+
+ protected void checkResponseBodyInvalid(LiveDownloadOperation operation) throws IOException {
+ InputStream is = operation.getStream();
+ ApiTest.assertEquals(is, INVALID_FORMAT);
+ }
+
+ /**
+ * Asserts the LiveOperation's result and raw result members are null.
+ *
+ * @param operation
+ */
+ protected void checkResponseBodyInvalid(LiveOperation operation) {
+ JSONObject result = operation.getResult();
+ assertNull(result);
+
+ String rawResult = operation.getRawResult();
+ assertNull(rawResult);
+ }
+
+ protected void checkReturnedException(LiveDownloadOperation fromMethod,
+ LiveDownloadOperation fromCallback,
+ LiveOperationException exception) throws IOException {
+ assertNotNull(exception.getMessage());
+
+ this.checkReturnedOperations(fromMethod, fromCallback);
+ }
+
+ /**
+ * Asserts the returned exception is not null and the LiveOperations from the method,
+ * and the callback listener are the same object. Also, asserts the responseQueue,
+ * and exceptionQueue are empty.
+ *
+ * @param fromMethod
+ * @param fromCallback
+ * @param exception
+ */
+ protected void checkReturnedException(LiveOperation fromMethod,
+ LiveOperation fromCallback,
+ LiveOperationException exception) {
+ assertNotNull(exception.getMessage());
+
+ this.checkReturnedOperations(fromMethod, fromCallback);
+
+ this.checkResponseBodyInvalid(fromMethod);
+ }
+
+ /**
+ * Asserts the returned LiveOperations from the method, and from the callback listener
+ * are the same object. Also, asserts the responseQueue and exceptionQueue are empty.
+ *
+ * @param fromMethod
+ * @param fromCallback
+ */
+ protected <T> void checkReturnedOperations(T fromMethod, T fromCallback) {
+ assertTrue(fromMethod == fromCallback);
+ assertTrue(this.responseQueue.isEmpty());
+ assertTrue(this.exceptionQueue.isEmpty());
+ }
+
+ protected void failNoIllegalArgumentExceptionThrown() {
+ this.failNoExceptionThrown(IllegalArgumentException.class);
+ }
+
+ protected void failNoLiveOperationExceptionThrown() {
+ this.failNoExceptionThrown(LiveOperationException.class);
+ }
+
+ protected void failNoNullPointerExceptionThrown() {
+ this.failNoExceptionThrown(NullPointerException.class);
+ }
+
+ /** Loads an invalid formated body into the HttpClient
+ * @throws Exception */
+ protected void loadInvalidResponseBody() throws Exception {
+ byte[] bytes = INVALID_FORMAT.getBytes();
+ this.mockResponse.addHeader(HTTP.CONTENT_LEN, Long.toString(bytes.length));
+ this.mockEntity.setInputStream(new ByteArrayInputStream(bytes));
+ this.mockClient.setHttpResponse(mockResponse);
+ }
+
+ /**
+ * Loads an invalid path response into the HttpClient.
+ *
+ * @param requestPath
+ * @throws Exception
+ */
+ protected void loadPathInvalidResponse(String requestPath) throws Exception {
+ JSONObject error = new JSONObject();
+ error.put(JsonKeys.CODE, ErrorCodes.REQUEST_URL_INVALID);
+
+ String message = String.format(ErrorMessages.URL_NOT_VALID,
+ requestPath.toLowerCase());
+ error.put(JsonKeys.MESSAGE, message);
+
+ JSONObject response = new JSONObject();
+ response.put(JsonKeys.ERROR, error);
+
+ byte[] bytes = response.toString().getBytes();
+ this.mockResponse.addHeader(HTTP.CONTENT_LEN, Long.toString(bytes.length));
+ this.mockEntity.setInputStream(new ByteArrayInputStream(bytes));
+ StatusLine status = new BasicStatusLine(HttpVersion.HTTP_1_1,
+ HttpStatus.SC_BAD_REQUEST,
+ "Bad Request");
+ this.mockResponse.setStatusLine(status);
+ this.mockClient.setHttpResponse(this.mockResponse);
+ }
+
+ protected LiveOperationException pollExceptionQueue() throws InterruptedException {
+ return this.exceptionQueue.poll(WAIT_TIME_IN_SECS, TimeUnit.SECONDS);
+ }
+
+ protected OperationType pollResponseQueue() throws InterruptedException {
+ return this.responseQueue.poll(WAIT_TIME_IN_SECS, TimeUnit.SECONDS);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // Set up the MockClient
+ this.mockEntity = new MockHttpEntity();
+
+ StatusLine statusLine = new BasicStatusLine(HttpVersion.HTTP_1_1,
+ HttpStatus.SC_OK,
+ "OK");
+ this.mockResponse = new MockHttpResponse(this.mockEntity, statusLine);
+ this.mockClient = new MockHttpClient(this.mockResponse);
+ this.loadLiveLibraryHeaderChecker();
+ this.exceptionQueue = new LinkedBlockingQueue<LiveOperationException>();
+ this.liveConnectClient = TestUtils.newLiveConnectClient(this.mockClient);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+
+ this.mockEntity = null;
+ this.mockClient = null;
+ this.responseQueue = null;
+ this.exceptionQueue = null;
+ this.queueingListener = null;
+ this.liveConnectClient = null;
+ }
+
+ private void failNoExceptionThrown(Class<?> cl) {
+ fail(String.format(AssertMessages.NO_EXCEPTION_THROWN, cl));
+ }
+}
87 unittest/src/com/microsoft/live/unittest/CopyTest.java
View
@@ -0,0 +1,87 @@
+package com.microsoft.live.unittest;
+
+import java.io.ByteArrayInputStream;
+
+import org.json.JSONObject;
+
+import android.text.TextUtils;
+
+import com.microsoft.live.LiveOperation;
+import com.microsoft.live.LiveOperationException;
+import com.microsoft.live.test.util.CopyAsyncRunnable;
+
+public class CopyTest extends FileOperationApiTest {
+
+ private static final String KEY = "key";
+
+ /** HTTP method this class is testing */
+ private static final String METHOD = "COPY";
+
+ private static final String VALUE = "value";
+
+ @Override
+ public void testSyncResponseBodyInvalid() throws Exception {
+ this.loadInvalidResponseBody();
+
+ try {
+ String requestPath = "folder.12319";
+ String destination = "folder.1239081";
+ this.liveConnectClient.copy(requestPath, destination);
+ this.failNoLiveOperationExceptionThrown();
+ } catch (LiveOperationException e) {
+ assertFalse(TextUtils.isEmpty(e.getMessage()));
+ }
+ }
+
+ @Override
+ public void testSyncResponseBodyValid() throws Exception {
+ this.loadValidResponseBody();
+
+ String requestPath = "folder.181231";
+ String destination = "folder.1231";
+ LiveOperation operation = this.liveConnectClient.copy(requestPath, destination);
+
+ this.checkOperationMembers(operation, METHOD, requestPath);
+ this.checkValidResponseBody(operation);
+ }
+
+ @Override
+ protected void checkValidResponseBody(LiveOperation operation) throws Exception {
+ JSONObject result = operation.getResult();
+ assertEquals(VALUE, result.getString(KEY));
+ }
+
+ @Override
+ protected CopyAsyncRunnable createAsyncRunnable(String requestPath,
+ String destination) {
+ return new CopyAsyncRunnable(this.responseQueue,
+ this.liveConnectClient,
+ requestPath,
+ destination,
+ this.queueingListener);
+ }
+
+ @Override
+ protected CopyAsyncRunnable createAsyncRunnable(String requestPath,
+ String destination,
+ Object userState) {
+ return new CopyAsyncRunnable(this.responseQueue,
+ this.liveConnectClient,
+ requestPath,
+ destination,
+ this.queueingListener,
+ userState);
+ }
+
+ @Override
+ protected String getMethod() {
+ return METHOD;
+ }
+
+ @Override
+ protected void loadValidResponseBody() throws Exception {
+ JSONObject responseBody = new JSONObject();
+ responseBody.put(KEY, VALUE);
+ this.mockEntity.setInputStream(new ByteArrayInputStream(responseBody.toString().getBytes()));
+ }
+}
143 unittest/src/com/microsoft/live/unittest/DeleteTest.java
View
@@ -0,0 +1,143 @@
+package com.microsoft.live.unittest;
+
+
+import java.io.ByteArrayInputStream;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.json.JSONObject;
+
+import android.text.TextUtils;
+
+import com.microsoft.live.LiveOperation;
+import com.microsoft.live.LiveOperationException;
+import com.microsoft.live.LiveOperationListener;
+import com.microsoft.live.test.util.DeleteAsyncRunnable;
+import com.microsoft.live.test.util.OperationQueueingListener;
+
+public class DeleteTest extends ApiTest<LiveOperation, LiveOperationListener> {
+
+ /** HTTP method this class is testing */
+ private static final String METHOD = "DELETE";
+
+ private String calendarId;
+
+ @Override
+ public void testAsyncResponseBodyInvalid() throws Throwable {
+ this.loadInvalidResponseBody();
+
+ String requestPath = this.calendarId;
+ this.runTestOnUiThread(createAsyncRunnable(requestPath));
+
+ LiveOperation fromMethod = this.responseQueue.take();
+ LiveOperation fromCallback = this.pollResponseQueue();
+ LiveOperationException exception = this.pollExceptionQueue();
+
+ this.checkReturnedException(fromMethod, fromCallback, exception);
+ this.checkOperationMembers(fromMethod, METHOD, requestPath);
+ this.checkResponseBodyInvalid(fromMethod);
+ }
+
+ @Override
+ public void testAsyncResponseBodyValid() throws Throwable {
+ this.loadValidResponseBody();
+
+ String requestPath = this.calendarId;
+ this.runTestOnUiThread(createAsyncRunnable(requestPath));
+
+ LiveOperation fromMethod = this.responseQueue.take();
+ LiveOperation fromCallback = this.pollResponseQueue();
+
+ this.checkReturnedOperations(fromMethod, fromCallback);
+ this.checkOperationMembers(fromMethod, METHOD, requestPath);
+ this.checkValidResponseBody(fromMethod);
+ }
+
+ @Override
+ public void testAsyncResponseBodyValidWithUserState() throws Throwable {
+ this.loadValidResponseBody();
+
+ Object userState = new Object();
+ String requestPath = this.calendarId;
+ this.runTestOnUiThread(createAsyncRunnable(requestPath, userState));
+
+ LiveOperation fromMethod = this.responseQueue.take();
+ LiveOperation fromCallback = this.pollResponseQueue();
+
+ this.checkReturnedOperations(fromMethod, fromCallback);
+ this.checkOperationMembers(fromMethod, METHOD, requestPath, userState);
+ this.checkValidResponseBody(fromMethod);
+ }
+
+
+ @Override
+ public void testSyncResponseBodyInvalid() throws Exception {
+ this.loadInvalidResponseBody();
+
+ try {
+ String requestPath = this.calendarId;
+ this.liveConnectClient.delete(requestPath);
+ this.failNoLiveOperationExceptionThrown();
+ } catch (LiveOperationException e) {
+ assertFalse(TextUtils.isEmpty(e.getMessage()));
+ }
+ }
+
+ @Override
+ public void testSyncResponseBodyValid() throws Exception {
+ this.loadValidResponseBody();
+
+ String requestPath = this.calendarId;
+ LiveOperation operation = this.liveConnectClient.delete(requestPath);
+
+ this.checkOperationMembers(operation, METHOD, requestPath);
+ this.checkValidResponseBody(operation);
+ }
+
+ @Override
+ protected void checkValidResponseBody(LiveOperation operation) {
+ JSONObject result = operation.getResult();
+ assertEquals(0, result.length());
+
+ String rawResult = operation.getRawResult();
+ assertEquals("{}", rawResult);
+ }
+
+ @Override
+ protected DeleteAsyncRunnable createAsyncRunnable(String requestPath) {
+ return new DeleteAsyncRunnable(this.responseQueue,
+ this.liveConnectClient,
+ requestPath,
+ this.queueingListener);
+ }
+
+ @Override
+ protected DeleteAsyncRunnable createAsyncRunnable(String requestPath, Object userState) {
+ return new DeleteAsyncRunnable(this.responseQueue,
+ this.liveConnectClient,
+ requestPath,
+ this.queueingListener,
+ userState);
+ }
+
+ @Override
+ protected String getMethod() {
+ return METHOD;
+ }
+
+ @Override
+ protected void loadValidResponseBody() {
+ // valid delete bodies are empty strings
+ String validResponseBody = "";
+ this.mockEntity.setInputStream(new ByteArrayInputStream(validResponseBody.getBytes()));
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ this.calendarId = "calendar.013123";
+ this.responseQueue = new LinkedBlockingQueue<LiveOperation>();
+ this.queueingListener = new OperationQueueingListener(this.exceptionQueue,
+ this.responseQueue);
+ }
+}
133 unittest/src/com/microsoft/live/unittest/DownloadTest.java
View
@@ -0,0 +1,133 @@
+package com.microsoft.live.unittest;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.apache.http.protocol.HTTP;
+
+import com.microsoft.live.LiveDownloadOperation;
+import com.microsoft.live.LiveDownloadOperationListener;
+import com.microsoft.live.test.util.DownloadAsyncRunnable;
+import com.microsoft.live.test.util.DownloadOperationQueueingListener;
+
+public class DownloadTest extends ApiTest<LiveDownloadOperation, LiveDownloadOperationListener> {
+
+ private static final String VALID_PATH = "file.123/content";
+ private static final String RESPONSE = "Some random data";
+
+ @Override
+ public void testAsyncResponseBodyInvalid() throws Throwable {
+ this.loadInvalidResponseBody();
+
+ String requestPath = VALID_PATH;
+ this.runTestOnUiThread(this.createAsyncRunnable(requestPath));
+
+ LiveDownloadOperation fromMethod = this.responseQueue.take();
+ LiveDownloadOperation fromCallback = this.pollResponseQueue();
+
+ this.checkReturnedOperations(fromMethod, fromCallback);
+ this.checkOperationMembers(fromMethod, this.getMethod(), requestPath);
+ this.checkResponseBodyInvalid(fromMethod);
+ }
+
+ @Override
+ public void testAsyncResponseBodyValid() throws Throwable {
+ this.loadValidResponseBody();
+ String requestPath = VALID_PATH;
+
+ this.runTestOnUiThread(this.createAsyncRunnable(requestPath));
+
+ LiveDownloadOperation fromMethod = this.responseQueue.take();
+ LiveDownloadOperation fromCallback = this.pollResponseQueue();
+
+ this.checkReturnedOperations(fromMethod, fromCallback);
+ this.checkOperationMembers(fromMethod, this.getMethod(), requestPath);
+ this.checkValidResponseBody(fromMethod);
+ }
+
+ @Override
+ public void testAsyncResponseBodyValidWithUserState() throws Throwable {
+ this.loadValidResponseBody();
+ String requestPath = VALID_PATH;
+ Object userState = new Object();
+
+ this.runTestOnUiThread(this.createAsyncRunnable(requestPath, userState));
+
+ LiveDownloadOperation fromMethod = this.responseQueue.take();
+ LiveDownloadOperation fromCallback = this.pollResponseQueue();
+
+ this.checkReturnedOperations(fromMethod, fromCallback);
+ this.checkOperationMembers(fromMethod, this.getMethod(), requestPath, userState);
+ this.checkValidResponseBody(fromMethod);
+
+ }
+
+
+ @Override
+ public void testSyncResponseBodyInvalid() throws Exception {
+ this.loadInvalidResponseBody();
+
+ String requestPath = VALID_PATH;
+
+ LiveDownloadOperation operation = this.liveConnectClient.download(requestPath);
+
+ this.checkOperationMembers(operation, this.getMethod(), requestPath);
+ this.checkResponseBodyInvalid(operation);
+ }
+
+ @Override
+ public void testSyncResponseBodyValid() throws Exception {
+ this.loadValidResponseBody();
+ String requestPath = VALID_PATH;
+
+ LiveDownloadOperation operation = this.liveConnectClient.download(requestPath);
+
+ this.checkOperationMembers(operation, this.getMethod(), requestPath);
+ this.checkValidResponseBody(operation);
+ }
+
+ @Override
+ protected void checkValidResponseBody(LiveDownloadOperation operation) throws Exception {
+ InputStream is = operation.getStream();
+ ApiTest.assertEquals(is, RESPONSE);
+ }
+
+ @Override
+ protected DownloadAsyncRunnable createAsyncRunnable(String requestPath) {
+ return new DownloadAsyncRunnable(this.responseQueue,
+ this.liveConnectClient,
+ requestPath,
+ this.queueingListener);
+ }
+
+ @Override
+ protected DownloadAsyncRunnable createAsyncRunnable(String requestPath, Object userState) {
+ return new DownloadAsyncRunnable(this.responseQueue,
+ this.liveConnectClient,
+ requestPath,
+ this.queueingListener,
+ userState);
+ }
+
+ @Override
+ protected String getMethod() {
+ return "GET";
+ }
+
+ @Override
+ protected void loadValidResponseBody() throws Exception {
+ byte[] bytes = RESPONSE.getBytes();
+ this.mockResponse.addHeader(HTTP.CONTENT_LEN, Long.toString(bytes.length));
+ this.mockEntity.setInputStream(new ByteArrayInputStream(bytes));
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ this.responseQueue = new LinkedBlockingQueue<LiveDownloadOperation>();
+ this.queueingListener = new DownloadOperationQueueingListener(this.exceptionQueue,
+ this.responseQueue);
+ }
+}
91 unittest/src/com/microsoft/live/unittest/FileOperationApiTest.java
View
@@ -0,0 +1,91 @@
+package com.microsoft.live.unittest;
+
+import java.util.concurrent.LinkedBlockingQueue;
+
+import com.microsoft.live.LiveOperation;
+import com.microsoft.live.LiveOperationException;
+import com.microsoft.live.LiveOperationListener;
+import com.microsoft.live.test.util.AsyncRunnable;
+import com.microsoft.live.test.util.AsyncRunnableWithDestination;
+import com.microsoft.live.test.util.OperationQueueingListener;
+
+public abstract class FileOperationApiTest extends ApiTest<LiveOperation, LiveOperationListener> {
+
+ @Override
+ public void testAsyncResponseBodyInvalid() throws Throwable {
+ this.loadInvalidResponseBody();
+
+ String requestPath = "file.123123";
+ String destination = "file.123109";
+ this.runTestOnUiThread(createAsyncRunnable(requestPath, destination));
+
+ LiveOperation fromMethod = this.responseQueue.take();
+ LiveOperation fromCallback = this.pollResponseQueue();
+ LiveOperationException exception = this.pollExceptionQueue();
+
+ this.checkReturnedException(fromMethod, fromCallback, exception);
+ this.checkOperationMembers(fromMethod, this.getMethod(), requestPath);
+ this.checkResponseBodyInvalid(fromMethod);
+
+ }
+
+ @Override
+ public void testAsyncResponseBodyValid() throws Throwable {
+ this.loadValidResponseBody();
+
+ String requestPath = "file.123123";
+ String destination = "file.123109";
+ this.runTestOnUiThread(createAsyncRunnable(requestPath, destination));
+
+ LiveOperation fromMethod = this.responseQueue.take();
+ LiveOperation fromCallback = this.pollResponseQueue();
+
+ this.checkReturnedOperations(fromMethod, fromCallback);
+ this.checkOperationMembers(fromMethod, this.getMethod(), requestPath);
+ this.checkValidResponseBody(fromMethod);
+ }
+
+ @Override
+ public void testAsyncResponseBodyValidWithUserState() throws Throwable {
+ this.loadValidResponseBody();
+
+ String requestPath = "file.123123";
+ String destination = "file.123109";
+ Object userState = new Object();
+
+ this.runTestOnUiThread(createAsyncRunnable(requestPath, destination, userState));
+
+ LiveOperation fromMethod = this.responseQueue.take();
+ LiveOperation fromCallback = this.pollResponseQueue();
+
+ this.checkReturnedOperations(fromMethod, fromCallback);
+ this.checkOperationMembers(fromMethod, this.getMethod(), requestPath, userState);
+ this.checkValidResponseBody(fromMethod);
+ }
+
+ protected abstract AsyncRunnableWithDestination<LiveOperation, LiveOperationListener>
+ createAsyncRunnable(String requestPath, String destination);
+
+ protected abstract AsyncRunnableWithDestination<LiveOperation, LiveOperationListener>
+ createAsyncRunnable(String requestPath, String destination, Object userState);
+
+ @Override
+ protected AsyncRunnable<LiveOperation, LiveOperationListener> createAsyncRunnable(String requestPath) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected AsyncRunnable<LiveOperation, LiveOperationListener> createAsyncRunnable(String requestPath,
+ Object userState) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ this.responseQueue = new LinkedBlockingQueue<LiveOperation>();
+ this.queueingListener = new OperationQueueingListener(this.exceptionQueue,
+ this.responseQueue);
+ }
+}
150 unittest/src/com/microsoft/live/unittest/GetTest.java
View
@@ -0,0 +1,150 @@
+package com.microsoft.live.unittest;
+
+
+import java.io.ByteArrayInputStream;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import com.microsoft.live.LiveOperation;
+import com.microsoft.live.LiveOperationException;
+import com.microsoft.live.LiveOperationListener;
+import com.microsoft.live.constants.JsonKeys;
+import com.microsoft.live.constants.Paths;
+import com.microsoft.live.test.util.GetAsyncRunnable;
+import com.microsoft.live.test.util.OperationQueueingListener;
+
+/**
+ * Tests all the get operations of the LiveConnectClient.
+ */
+public class GetTest extends ApiTest<LiveOperation, LiveOperationListener> {
+
+ private static final String METHOD = "GET";
+
+ private static final String USERNAME = "username@live.com";
+
+ @Override
+ public void testAsyncResponseBodyInvalid() throws Throwable {
+ this.loadInvalidResponseBody();
+
+ String requestPath = Paths.ME;
+ this.runTestOnUiThread(createAsyncRunnable(requestPath));
+
+ LiveOperation fromMethod = this.responseQueue.take();
+ LiveOperation fromCallback = this.pollResponseQueue();
+ LiveOperationException exception = this.pollExceptionQueue();
+
+ this.checkReturnedException(fromMethod, fromCallback, exception);
+ this.checkOperationMembers(fromMethod, METHOD, requestPath);
+ this.checkResponseBodyInvalid(fromMethod);
+ }
+
+ @Override
+ public void testAsyncResponseBodyValid() throws Throwable {
+ this.loadValidResponseBody();
+
+ String requestPath = Paths.ME;
+ this.runTestOnUiThread(createAsyncRunnable(requestPath));
+
+ LiveOperation fromMethod = this.responseQueue.take();
+ LiveOperation fromCallback = this.pollResponseQueue();
+
+ this.checkReturnedOperations(fromMethod, fromCallback);
+ this.checkOperationMembers(fromMethod, METHOD, requestPath);
+ this.checkValidResponseBody(fromMethod);
+ }
+
+ @Override
+ public void testAsyncResponseBodyValidWithUserState() throws Throwable {
+ this.loadValidResponseBody();
+
+ Object userState = new Object();
+ String requestPath = Paths.ME;
+ this.runTestOnUiThread(createAsyncRunnable(requestPath, userState));
+
+ LiveOperation fromMethod = this.responseQueue.take();
+ LiveOperation fromCallback = this.pollResponseQueue();
+
+ this.checkReturnedOperations(fromMethod, fromCallback);
+ this.checkOperationMembers(fromMethod, METHOD, requestPath, userState);
+ this.checkValidResponseBody(fromMethod);
+ }
+
+
+ @Override
+ public void testSyncResponseBodyInvalid() throws Exception {
+ this.loadInvalidResponseBody();
+
+ try {
+ this.liveConnectClient.get(Paths.ME);
+ this.failNoLiveOperationExceptionThrown();
+ } catch (LiveOperationException e) {
+ assertNotNull(e.getMessage());
+ }
+ }
+
+ @Override
+ public void testSyncResponseBodyValid() throws Exception {
+ this.loadValidResponseBody();
+
+ String requestPath = Paths.ME;
+ LiveOperation operation = this.liveConnectClient.get(requestPath);
+
+ this.checkOperationMembers(operation, METHOD, requestPath);
+ this.checkValidResponseBody(operation);
+ }
+
+ @Override
+ protected void checkValidResponseBody(LiveOperation operation) throws JSONException {
+ JSONObject response = operation.getResult();
+ JSONObject emails = response.getJSONObject(JsonKeys.EMAILS);
+ String account = emails.getString(JsonKeys.ACCOUNT);
+
+ assertEquals(USERNAME, account);
+ }
+
+ @Override
+ protected GetAsyncRunnable createAsyncRunnable(String requestPath) {
+ return new GetAsyncRunnable(this.responseQueue,
+ this.liveConnectClient,
+ requestPath,
+ this.queueingListener);
+ }
+
+ @Override
+ protected GetAsyncRunnable createAsyncRunnable(String requestPath, Object userState) {
+ return new GetAsyncRunnable(this.responseQueue,
+ this.liveConnectClient,
+ requestPath,
+ this.queueingListener,
+ userState);
+ }
+
+ @Override
+ protected String getMethod() {
+ return METHOD;
+ }
+
+ @Override
+ protected void loadValidResponseBody() throws JSONException {
+ String injectedAccount = USERNAME;
+ JSONObject injectedEmails = new JSONObject();
+ injectedEmails.put(JsonKeys.ACCOUNT, injectedAccount);
+
+ JSONObject injectedResponse = new JSONObject();
+ injectedResponse.put(JsonKeys.EMAILS, injectedEmails);
+
+ byte[] bytes = injectedResponse.toString().getBytes();
+ this.mockEntity.setInputStream(new ByteArrayInputStream(bytes));
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ this.responseQueue = new LinkedBlockingQueue<LiveOperation>();
+ this.queueingListener = new OperationQueueingListener(this.exceptionQueue,
+ this.responseQueue);
+ }
+}
45 unittest/src/com/microsoft/live/unittest/JsonEnclosingApiTest.java
View
@@ -0,0 +1,45 @@
+package com.microsoft.live.unittest;
+
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.json.JSONObject;
+
+import com.microsoft.live.LiveOperation;
+import com.microsoft.live.LiveOperationListener;
+import com.microsoft.live.test.util.AsyncRunnable;
+import com.microsoft.live.test.util.AsyncRunnableWithBody;
+import com.microsoft.live.test.util.OperationQueueingListener;
+
+public abstract class JsonEnclosingApiTest extends ApiTest<LiveOperation, LiveOperationListener> {
+ protected abstract AsyncRunnableWithBody<LiveOperation, LiveOperationListener>
+ createAsyncRunnable(String requestPath, JSONObject body);
+
+ protected abstract AsyncRunnableWithBody<LiveOperation, LiveOperationListener>
+ createAsyncRunnable(String requestPath, JSONObject body, Object userState);
+
+ protected abstract AsyncRunnableWithBody<LiveOperation, LiveOperationListener>
+ createAsyncRunnable(String requestPath, String body);
+
+ protected abstract AsyncRunnableWithBody<LiveOperation, LiveOperationListener>
+ createAsyncRunnable(String requestPath, String body, Object userState);
+
+ @Override
+ protected AsyncRunnable<LiveOperation, LiveOperationListener> createAsyncRunnable(String requestPath) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected AsyncRunnable<LiveOperation, LiveOperationListener> createAsyncRunnable(String requestPath,
+ Object userState) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ this.responseQueue = new LinkedBlockingQueue<LiveOperation>();
+ this.queueingListener = new OperationQueueingListener(this.exceptionQueue,
+ this.responseQueue);
+ }
+}
87 unittest/src/com/microsoft/live/unittest/MoveTest.java
View
@@ -0,0 +1,87 @@
+package com.microsoft.live.unittest;
+
+import java.io.ByteArrayInputStream;
+
+import org.json.JSONObject;
+
+import android.text.TextUtils;
+
+import com.microsoft.live.LiveOperation;
+import com.microsoft.live.LiveOperationException;
+import com.microsoft.live.test.util.MoveAsyncRunnable;
+
+public class MoveTest extends FileOperationApiTest {
+
+ private static final String KEY = "key";
+
+ /** HTTP method this class is testing */
+ private static final String METHOD = "MOVE";
+
+ private static final String VALUE = "value";
+
+ @Override
+ public void testSyncResponseBodyInvalid() throws Exception {
+ this.loadInvalidResponseBody();
+
+ try {
+ String requestPath = "folder.12319";
+ String destination = "folder.1239081";
+ this.liveConnectClient.move(requestPath, destination);
+ this.failNoLiveOperationExceptionThrown();
+ } catch (LiveOperationException e) {
+ assertFalse(TextUtils.isEmpty(e.getMessage()));
+ }
+ }
+
+ @Override
+ public void testSyncResponseBodyValid() throws Exception {
+ this.loadValidResponseBody();
+
+ String requestPath = "folder.181231";
+ String destination = "folder.1231";
+ LiveOperation operation = this.liveConnectClient.move(requestPath, destination);
+
+ this.checkOperationMembers(operation, METHOD, requestPath);
+ this.checkValidResponseBody(operation);
+ }
+
+ @Override
+ protected void checkValidResponseBody(LiveOperation operation) throws Exception {
+ JSONObject result = operation.getResult();
+ assertEquals(VALUE, result.getString(KEY));
+ }
+
+ @Override
+ protected MoveAsyncRunnable createAsyncRunnable(String requestPath,
+ String destination) {
+ return new MoveAsyncRunnable(this.responseQueue,
+ this.liveConnectClient,
+ requestPath,
+ destination,
+ this.queueingListener);
+ }
+
+ @Override
+ protected MoveAsyncRunnable createAsyncRunnable(String requestPath,
+ String destination,
+ Object userState) {
+ return new MoveAsyncRunnable(this.responseQueue,
+ this.liveConnectClient,
+ requestPath,
+ destination,
+ this.queueingListener,
+ userState);
+ }
+
+ @Override
+ protected String getMethod() {
+ return METHOD;
+ }
+
+ @Override
+ protected void loadValidResponseBody() throws Exception {
+ JSONObject responseBody = new JSONObject();
+ responseBody.put(KEY, VALUE);
+ this.mockEntity.setInputStream(new ByteArrayInputStream(responseBody.toString().getBytes()));
+ }
+}
212 unittest/src/com/microsoft/live/unittest/PostTest.java
View
@@ -0,0 +1,212 @@
+package com.microsoft.live.unittest;
+
+
+import java.io.ByteArrayInputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.text.TextUtils;
+
+import com.microsoft.live.LiveOperation;
+import com.microsoft.live.LiveOperationException;
+import com.microsoft.live.constants.JsonKeys;
+import com.microsoft.live.constants.Paths;
+import com.microsoft.live.test.util.PostAsyncRunnable;
+
+
+public class PostTest extends JsonEnclosingApiTest {
+
+ /** The body of the post request. */
+ private static final JSONObject CALENDAR;
+
+ private static final String METHOD = "POST";
+
+ /** Name of the calendar to be created */
+ private static final String NAME = "Test Calendar";
+
+ static {
+ Map<String, String> calendar = new HashMap<String, String>();
+ calendar.put(JsonKeys.NAME, NAME);
+
+ CALENDAR = new JSONObject(calendar);
+ }
+
+
+ @Override
+ public void testAsyncResponseBodyInvalid() throws Throwable {
+ this.loadInvalidResponseBody();
+
+ String requestPath = Paths.INVALID;
+
+ this.runTestOnUiThread(createAsyncRunnable(requestPath, CALENDAR));
+
+ LiveOperation fromMethod = this.responseQueue.take();
+ LiveOperation fromCallback = this.pollResponseQueue();
+ LiveOperationException exception = this.pollExceptionQueue();
+
+ this.checkReturnedException(fromMethod, fromCallback, exception);
+ this.checkOperationMembers(fromMethod, METHOD, requestPath);
+ this.checkResponseBodyInvalid(fromMethod);
+ }
+
+ @Override
+ public void testAsyncResponseBodyValid() throws Throwable {
+ this.loadValidResponseBody();
+
+ String requestPath = Paths.ME_CALENDARS;
+
+ this.runTestOnUiThread(createAsyncRunnable(requestPath, CALENDAR));
+
+ LiveOperation fromMethod = this.responseQueue.take();
+ LiveOperation fromCallback = this.pollResponseQueue();
+
+ this.checkReturnedOperations(fromMethod, fromCallback);
+ this.checkOperationMembers(fromMethod, METHOD, requestPath);
+
+ this.checkValidResponseBody(fromMethod);
+ }
+
+ @Override
+ public void testAsyncResponseBodyValidWithUserState() throws Throwable {
+ this.loadValidResponseBody();
+
+ Object userState = new Object();
+ String requestPath = Paths.ME_CALENDARS;
+
+ this.runTestOnUiThread(createAsyncRunnable(requestPath, CALENDAR, userState));
+
+ LiveOperation fromMethod = this.responseQueue.take();
+ LiveOperation fromCallback = this.pollResponseQueue();
+
+ this.checkReturnedOperations(fromMethod, fromCallback);
+ this.checkOperationMembers(fromMethod, METHOD, requestPath, userState);
+
+ this.checkValidResponseBody(fromMethod);
+ }
+
+
+ @Override
+ public void testSyncResponseBodyInvalid() throws Exception {
+ this.loadInvalidResponseBody();
+
+ try {
+ this.liveConnectClient.post(Paths.ME_CALENDARS, CALENDAR);
+ this.failNoLiveOperationExceptionThrown();
+ } catch (LiveOperationException e) {
+ assertFalse(TextUtils.isEmpty(e.getMessage()));
+ }
+ }
+
+ @Override
+ public void testSyncResponseBodyValid() throws Exception {
+ this.loadValidResponseBody();
+
+ String requestPath = Paths.ME_CALENDARS;
+
+ LiveOperation operation = this.liveConnectClient.post(requestPath, CALENDAR);
+
+ this.checkOperationMembers(operation, METHOD, requestPath);
+ this.checkValidResponseBody(operation);
+ }
+
+ @Override
+ protected void checkValidResponseBody(LiveOperation operation) throws JSONException {
+ JSONObject result = operation.getResult();
+ String id = result.getString(JsonKeys.ID);
+ Object description = result.get(JsonKeys.DESCRIPTION);
+ String name = result.getString(JsonKeys.NAME);
+ String permissions = result.getString(JsonKeys.PERMISSIONS);
+ boolean isDefault = result.getBoolean(JsonKeys.IS_DEFAULT);
+
+ JSONObject from = result.getJSONObject(JsonKeys.FROM);
+ String fromId = from.getString(JsonKeys.ID);
+ String fromName = from.getString(JsonKeys.NAME);
+
+ Object subscriptionLocation = result.get(JsonKeys.SUBSCRIPTION_LOCATION);
+ String createdTime = result.getString(JsonKeys.CREATED_TIME);
+ String updatedTime = result.getString(JsonKeys.UPDATED_TIME);
+
+ assertEquals("calendar_id", id);
+ assertEquals(JSONObject.NULL, description);
+ assertEquals("name", name);
+ assertEquals("owner", permissions);
+ assertEquals(false, isDefault);
+ assertEquals("from_id", fromId);
+ assertEquals("from_name", fromName);
+ assertEquals(JSONObject.NULL, subscriptionLocation);
+ assertEquals("2011-12-10T02:48:33+0000", createdTime);
+ assertEquals("2011-12-10T02:48:33+0000", updatedTime);
+ }
+
+ @Override
+ protected PostAsyncRunnable createAsyncRunnable(String requestPath, JSONObject body) {
+ return new PostAsyncRunnable(this.responseQueue,
+ this.liveConnectClient,
+ requestPath,
+ body,
+ this.queueingListener);
+ }
+
+ @Override
+ protected PostAsyncRunnable createAsyncRunnable(String requestPath,
+ JSONObject body,
+ Object userState) {
+ return new PostAsyncRunnable(this.responseQueue,
+ this.liveConnectClient,
+ requestPath,
+ body,
+ this.queueingListener,
+ userState);
+ }
+
+ @Override
+ protected PostAsyncRunnable createAsyncRunnable(String requestPath, String body) {
+ return new PostAsyncRunnable(this.responseQueue,
+ this.liveConnectClient,
+ requestPath,
+ body,
+ this.queueingListener);
+ }
+
+ @Override
+ protected PostAsyncRunnable createAsyncRunnable(String requestPath,
+ String body,
+ Object userState) {
+ return new PostAsyncRunnable(this.responseQueue,
+ this.liveConnectClient,
+ requestPath,
+ body,
+ this.queueingListener,
+ userState);
+ }
+
+ @Override
+ protected String getMethod() {
+ return METHOD;
+ }
+
+ @Override
+ protected void loadValidResponseBody() throws JSONException {
+ JSONObject calendar = new JSONObject();
+ calendar.put(JsonKeys.ID, "calendar_id");
+ calendar.put(JsonKeys.DESCRIPTION, JSONObject.NULL);
+ calendar.put(JsonKeys.NAME, "name");
+ calendar.put(JsonKeys.PERMISSIONS, "owner");
+ calendar.put(JsonKeys.IS_DEFAULT, false);
+
+ JSONObject from = new JSONObject();
+ from.put(JsonKeys.ID, "from_id");
+ from.put(JsonKeys.NAME, "from_name");
+
+ calendar.put(JsonKeys.FROM, from);
+ calendar.put(JsonKeys.SUBSCRIPTION_LOCATION, JSONObject.NULL);
+ calendar.put(JsonKeys.CREATED_TIME, "2011-12-10T02:48:33+0000");
+ calendar.put(JsonKeys.UPDATED_TIME, "2011-12-10T02:48:33+0000");
+
+ byte[] bytes = calendar.toString().getBytes();
+ this.mockEntity.setInputStream(new ByteArrayInputStream(bytes));
+ }
+}
218 unittest/src/com/microsoft/live/unittest/PutTest.java
View
@@ -0,0 +1,218 @@
+package com.microsoft.live.unittest;
+
+import java.io.ByteArrayInputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.text.TextUtils;
+
+import com.microsoft.live.LiveOperation;
+import com.microsoft.live.LiveOperationException;
+import com.microsoft.live.constants.JsonKeys;
+import com.microsoft.live.constants.Paths;
+import com.microsoft.live.test.util.PutAsyncRunnable;
+
+public class PutTest extends JsonEnclosingApiTest {
+
+ /** The Calendar object created. */
+ private static final JSONObject CALENDAR;
+
+ private static final String METHOD = "PUT";
+
+ /** Name of the calendar to be updated */
+ private static final String NAME = "Test Calendar Updated";
+
+ static {
+ Map<String, String> calendar = new HashMap<String, String>();
+ calendar.put(JsonKeys.NAME, NAME);
+
+ CALENDAR = new JSONObject(calendar);
+ }
+
+ private String calendarId;
+
+ @Override
+ public void testAsyncResponseBodyInvalid() throws Throwable {
+ this.loadInvalidResponseBody();
+
+ String requestPath = Paths.INVALID;
+
+ this.runTestOnUiThread(createAsyncRunnable(requestPath, CALENDAR));
+
+ LiveOperation fromMethod = this.responseQueue.take();
+ LiveOperation fromCallback = this.pollResponseQueue();
+ LiveOperationException exception = this.pollExceptionQueue();
+
+ this.checkReturnedException(fromMethod, fromCallback, exception);
+ this.checkOperationMembers(fromMethod, METHOD, requestPath);
+ this.checkResponseBodyInvalid(fromMethod);
+ }
+
+ @Override
+ public void testAsyncResponseBodyValid() throws Throwable {
+ this.loadValidResponseBody();
+
+ String requestPath = this.calendarId;
+
+ this.runTestOnUiThread(createAsyncRunnable(requestPath, CALENDAR));
+
+ LiveOperation fromMethod = this.responseQueue.take();
+ LiveOperation fromCallback = this.pollResponseQueue();
+
+ this.checkReturnedOperations(fromMethod, fromCallback);
+ this.checkOperationMembers(fromMethod, METHOD, requestPath);
+
+ this.checkValidResponseBody(fromMethod);
+ }
+
+ @Override
+ public void testAsyncResponseBodyValidWithUserState() throws Throwable {
+ this.loadValidResponseBody();
+
+ Object userState = new Object();
+ String requestPath = this.calendarId;
+
+ this.runTestOnUiThread(createAsyncRunnable(requestPath, CALENDAR, userState));
+
+ LiveOperation fromMethod = this.responseQueue.take();
+ LiveOperation fromCallback = this.pollResponseQueue();
+
+ this.checkReturnedOperations(fromMethod, fromCallback);
+ this.checkOperationMembers(fromMethod, METHOD, requestPath, userState);
+
+ this.checkValidResponseBody(fromMethod);
+ }
+
+
+ @Override
+ public void testSyncResponseBodyInvalid() throws Exception {
+ this.loadInvalidResponseBody();
+
+ try {
+ this.liveConnectClient.put(Paths.ME_CALENDARS, CALENDAR);
+ this.failNoLiveOperationExceptionThrown();
+ } catch (LiveOperationException e) {
+ assertFalse(TextUtils.isEmpty(e.getMessage()));
+ }
+ }
+
+ @Override
+ public void testSyncResponseBodyValid() throws Exception {
+ this.loadValidResponseBody();
+
+ String requestPath = this.calendarId;
+
+ LiveOperation operation = this.liveConnectClient.put(requestPath, CALENDAR);
+
+ this.checkOperationMembers(operation, METHOD, requestPath);
+ this.checkValidResponseBody(operation);
+ }
+
+ @Override
+ protected void checkValidResponseBody(LiveOperation operation) throws JSONException {
+ JSONObject result = operation.getResult();
+ String id = result.getString(JsonKeys.ID);
+ Object description = result.get(JsonKeys.DESCRIPTION);
+ String name = result.getString(JsonKeys.NAME);
+ String permissions = result.getString(JsonKeys.PERMISSIONS);
+ boolean isDefault = result.getBoolean(JsonKeys.IS_DEFAULT);
+
+ JSONObject from = result.getJSONObject(JsonKeys.FROM);
+ String fromId = from.getString(JsonKeys.ID);
+ String fromName = from.getString(JsonKeys.NAME);
+
+ Object subscriptionLocation = result.get(JsonKeys.SUBSCRIPTION_LOCATION);
+ String createdTime = result.getString(JsonKeys.CREATED_TIME);
+ String updatedTime = result.getString(JsonKeys.UPDATED_TIME);
+
+ assertEquals("calendar_id", id);
+ assertEquals(JSONObject.NULL, description);
+ assertEquals("name", name);
+ assertEquals("owner", permissions);
+ assertEquals(false, isDefault);
+ assertEquals("from_id", fromId);
+ assertEquals("from_name", fromName);
+ assertEquals(JSONObject.NULL, subscriptionLocation);
+ assertEquals("2011-12-10T02:48:33+0000", createdTime);
+ assertEquals("2011-12-10T02:48:33+0000", updatedTime);
+ }
+
+ @Override
+ protected PutAsyncRunnable createAsyncRunnable(String requestPath, JSONObject body) {
+ return new PutAsyncRunnable(this.responseQueue,
+ this.liveConnectClient,
+ requestPath,
+ body,
+ this.queueingListener);
+ }
+
+ @Override
+ protected PutAsyncRunnable createAsyncRunnable(String requestPath,
+ JSONObject body,
+ Object userState) {
+ return new PutAsyncRunnable(this.responseQueue,
+ this.liveConnectClient,
+ requestPath,
+ body,
+ this.queueingListener,
+ userState);
+ }
+
+ @Override
+ protected PutAsyncRunnable createAsyncRunnable(String requestPath, String body) {
+ return new PutAsyncRunnable(this.responseQueue,
+ this.liveConnectClient,
+ requestPath,
+ body,
+ this.queueingListener);
+ }
+
+ @Override
+ protected PutAsyncRunnable createAsyncRunnable(String requestPath,
+ String body,
+ Object userState) {
+ return new PutAsyncRunnable(this.responseQueue,
+ this.liveConnectClient,
+ requestPath,
+ body,
+ this.queueingListener,
+ userState);
+ }
+
+ @Override
+ protected String getMethod() {
+ return METHOD;
+ }
+
+ @Override
+ protected void loadValidResponseBody() throws JSONException {
+ JSONObject calendar = new JSONObject();
+ calendar.put(JsonKeys.ID, "calendar_id");
+ calendar.put(JsonKeys.DESCRIPTION, JSONObject.NULL);
+ calendar.put(JsonKeys.NAME, "name");
+ calendar.put(JsonKeys.PERMISSIONS, "owner");
+ calendar.put(JsonKeys.IS_DEFAULT, false);
+
+ JSONObject from = new JSONObject();
+ from.put(JsonKeys.ID, "from_id");
+ from.put(JsonKeys.NAME, "from_name");
+
+ calendar.put(JsonKeys.FROM, from);
+ calendar.put(JsonKeys.SUBSCRIPTION_LOCATION, JSONObject.NULL);
+ calendar.put(JsonKeys.CREATED_TIME, "2011-12-10T02:48:33+0000");
+ calendar.put(JsonKeys.UPDATED_TIME, "2011-12-10T02:48:33+0000");
+
+ byte[] bytes = calendar.toString().getBytes();
+ this.mockEntity.setInputStream(new ByteArrayInputStream(bytes));
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ this.calendarId = "calendar.123131";
+ }
+}
363 unittest/src/com/microsoft/live/unittest/UploadTest.java
View
@@ -0,0 +1,363 @@
+package com.microsoft.live.unittest;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.InputStream;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.HttpVersion;
+import org.apache.http.StatusLine;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.message.BasicStatusLine;
+import org.json.JSONObject;
+
+import android.text.TextUtils;
+
+import com.microsoft.live.LiveOperation;
+import com.microsoft.live.LiveOperationException;
+import com.microsoft.live.LiveUploadOperationListener;
+import com.microsoft.live.OverwriteOption;
+import com.microsoft.live.constants.JsonKeys;
+import com.microsoft.live.constants.Paths;
+import com.microsoft.live.mock.MockHttpEntity;
+import com.microsoft.live.mock.MockHttpResponse;
+import com.microsoft.live.test.util.UploadAsyncRunnable;
+import com.microsoft.live.test.util.UploadOperationQueueingListener;
+import com.microsoft.live.util.NullLiveUploadOperationListener;
+
+public class UploadTest extends ApiTest<LiveOperation, LiveUploadOperationListener> {
+
+ private static final String SOURCE = "http://download.location.com/some/path";
+ private static final InputStream FILE;
+ private static final String FILE_ID = "file.1231";
+ private static final String FILENAME = "some_file.txt";
+
+ static {
+ FILE = new ByteArrayInputStream("File contents".getBytes());
+ }
+
+
+ public void testAsyncFileNull() {
+ try {
+ this.liveConnectClient.uploadAsync(Paths.ME_SKYDRIVE,
+ null,
+ FILE,
+ NullLiveUploadOperationListener.INSTANCE);
+ this.failNoNullPointerExceptionThrown();
+ } catch (NullPointerException e) {
+ assertNotNull(e.getMessage());
+ }
+ }
+
+ public void testAsyncFilenameNull() {
+ try {
+ this.liveConnectClient.uploadAsync(Paths.ME_SKYDRIVE,
+ FILENAME,
+ (InputStream)null,
+ NullLiveUploadOperationListener.INSTANCE);
+ this.failNoNullPointerExceptionThrown();
+ } catch (NullPointerException e) {
+ assertNotNull(e.getMessage());
+ }
+
+ try {
+ this.liveConnectClient.uploadAsync(Paths.ME_SKYDRIVE,
+ FILENAME,
+ (File)null,
+ NullLiveUploadOperationListener.INSTANCE);
+ this.failNoNullPointerExceptionThrown();
+ } catch (NullPointerException e) {
+ assertNotNull(e.getMessage());
+ }
+ }
+
+ @Override
+ public void testAsyncResponseBodyInvalid() throws Throwable {
+ this.loadInvalidResponseBody();
+
+ String requestPath = Paths.ME_SKYDRIVE;
+ this.runTestOnUiThread(createAsyncRunnable(requestPath, FILENAME, FILE));
+
+ LiveOperation fromMethod = this.responseQueue.take();
+ LiveOperation fromCallback = this.pollResponseQueue();
+ LiveOperationException exception = this.pollExceptionQueue();
+
+ this.checkReturnedException(fromMethod, fromCallback, exception);
+ this.checkOperationMembers(fromMethod, getMethod(), requestPath);
+ this.checkResponseBodyInvalid(fromMethod);
+ }
+
+ @Override
+ public void testAsyncResponseBodyValid() throws Throwable {
+ this.loadUploadLocationResponseBody();
+ this.loadValidResponseBody();
+
+ String requestPath = Paths.ME_SKYDRIVE;
+
+ this.runTestOnUiThread(createAsyncRunnable(requestPath, FILENAME, FILE));
+
+ LiveOperation fromMethod = this.responseQueue.take();
+ LiveOperation fromCallback = this.pollResponseQueue();
+
+ this.checkReturnedOperations(fromMethod, fromCallback);
+ this.checkOperationMembers(fromMethod, getMethod(), requestPath);
+ this.checkValidResponseBody(fromMethod);
+ }
+
+ @Override
+ public void testAsyncResponseBodyValidWithUserState() throws Throwable {
+ this.loadUploadLocationResponseBody();
+ this.loadValidResponseBody();
+
+ String requestPath = Paths.ME_SKYDRIVE;
+ Object userState = new Object();
+
+ this.runTestOnUiThread(createAsyncRunnable(requestPath, FILENAME, FILE, userState));
+
+ LiveOperation fromMethod = this.responseQueue.take();
+ LiveOperation fromCallback = this.pollResponseQueue();
+
+ this.checkReturnedOperations(fromMethod, fromCallback);
+ this.checkOperationMembers(fromMethod, getMethod(), requestPath, userState);
+ this.checkValidResponseBody(fromMethod);
+ }
+
+ public void testAsyncResponseBodyValidWithOverwrite() throws Throwable {
+ this.loadUploadLocationResponseBody();
+ this.loadValidResponseBody();
+
+ String requestPath = Paths.ME_SKYDRIVE;
+ Object userState = new Object();
+
+ this.runTestOnUiThread(createAsyncRunnable(
+ requestPath,
+ FILENAME,
+ OverwriteOption.Overwrite,
+ FILE,
+ userState));
+
+ LiveOperation fromMethod = this.responseQueue.take();
+ LiveOperation fromCallback = this.pollResponseQueue();
+
+ this.checkReturnedOperations(fromMethod, fromCallback);
+ this.checkOperationMembers(fromMethod, getMethod(), requestPath, userState);
+ this.checkValidResponseBody(fromMethod);
+ }
+
+ public void testSyncFileNull() throws Exception {
+ try {
+ this.liveConnectClient.upload(Paths.ME_SKYDRIVE, FILENAME, (InputStream)null);
+ this.failNoNullPointerExceptionThrown();
+ } catch (NullPointerException e) {
+ assertNotNull(e.getMessage());
+ }
+
+ try {
+ this.liveConnectClient.upload(Paths.ME_SKYDRIVE, FILENAME, (File)null);
+ this.failNoNullPointerExceptionThrown();
+ } catch (NullPointerException e) {
+ assertNotNull(e.getMessage());
+ }
+ }
+
+ public void testSyncFilenameNull() throws Exception {
+ try {
+ this.liveConnectClient.upload(Paths.ME_SKYDRIVE, null, FILE);
+ this.failNoNullPointerExceptionThrown();
+ } catch (NullPointerException e) {
+ assertNotNull(e.getMessage());
+ }
+ }
+
+ @Override
+ public void testSyncResponseBodyInvalid() throws Exception {
+ this.loadInvalidResponseBody();
+
+ String requestPath = Paths.ME_SKYDRIVE;
+
+ try {
+ this.liveConnectClient.upload(requestPath, FILENAME, FILE);
+ this.failNoLiveOperationExceptionThrown();
+ } catch (LiveOperationException e) {
+ assertFalse(TextUtils.isEmpty(e.getMessage()));
+ }
+ }
+
+ public void testSyncResponseBodyInvalidWithOverwrite() throws Exception {
+ this.loadInvalidResponseBody();
+
+ String requestPath = Paths.ME_SKYDRIVE;
+
+ try {
+ this.liveConnectClient.upload(requestPath, FILENAME, FILE, OverwriteOption.Overwrite);
+ this.failNoLiveOperationExceptionThrown();
+ } catch (LiveOperationException e) {
+ assertFalse(TextUtils.isEmpty(e.getMessage()));
+ }
+ }
+
+ @Override
+ public void testSyncResponseBodyValid() throws Exception {
+ this.loadUploadLocationResponseBody();
+ this.loadValidResponseBody();
+
+ String requestPath = Paths.ME_SKYDRIVE;
+
+ LiveOperation operation = this.liveConnectClient.upload(requestPath, FILENAME, FILE);
+
+ this.checkOperationMembers(operation, getMethod(), requestPath);
+ this.checkValidResponseBody(operation);
+ }
+
+ public void testSyncResponseBodyValidWithOverwrite() throws Exception {
+ this.loadUploadLocationResponseBody();
+ this.loadValidResponseBody();
+
+ String requestPath = Paths.ME_SKYDRIVE;
+
+ LiveOperation operation = this.liveConnectClient.upload(
+ requestPath,
+ FILENAME,
+ FILE,
+ OverwriteOption.Overwrite);
+
+ this.checkOperationMembers(operation, getMethod(), requestPath);
+ this.checkValidResponseBody(operation);
+ }
+
+ @Override
+ protected void checkValidResponseBody(LiveOperation operation) throws Exception {
+ JSONObject result = operation.getResult();
+
+ assertEquals(2, result.length());
+
+ String id = result.getString(JsonKeys.ID);
+ assertEquals(FILE_ID, id);
+
+ String source = result.getString(JsonKeys.SOURCE);
+ assertEquals(SOURCE, source);
+ }
+
+ protected UploadAsyncRunnable createAsyncRunnable(String requestPath,
+ String filename,
+ InputStream file) {
+ return new UploadAsyncRunnable(this.responseQueue,
+ this.liveConnectClient,
+ requestPath,
+ filename,
+ file,
+ this.queueingListener);
+ }
+
+ protected UploadAsyncRunnable createAsyncRunnable(String requestPath,
+ String filename,
+ InputStream file,
+ Object userState) {
+ return new UploadAsyncRunnable(this.responseQueue,
+ this.liveConnectClient,
+ requestPath,
+ filename,
+ file,
+ this.queueingListener,
+ userState);
+ }
+
+ protected UploadAsyncRunnable createAsyncRunnable(String requestPath,
+ String filename,
+ OverwriteOption overwrite,
+ InputStream file,
+ Object userState) {
+ return new UploadAsyncRunnable(this.responseQueue,
+ this.liveConnectClient,
+ requestPath,
+ filename,
+ overwrite,
+ file,
+ this.queueingListener,
+ userState);
+ }
+
+ @Override
+ protected final UploadAsyncRunnable createAsyncRunnable(String requestPath) {
+ throw new UnsupportedOperationException("Unable to create UploadAsyncRunnable from only " +
+ "a requestPath");
+ }
+
+ @Override
+ protected final UploadAsyncRunnable createAsyncRunnable(String requestPath, Object userState) {
+ throw new UnsupportedOperationException("Unable to create UploadAsyncRunnable from only " +
+ "a requestPath and an userState");
+ }
+
+ @Override
+ protected void loadInvalidResponseBody() throws Exception {
+ super.loadInvalidResponseBody();
+
+ HttpResponse invalidResponse = this.mockClient.getHttpResponse();
+
+ this.mockClient.clearHttpResponseQueue();
+ this.loadUploadLocationResponseBody();
+ this.mockClient.addHttpResponse(invalidResponse);
+ }
+
+ @Override
+ protected void loadPathInvalidResponse(String requestPath) throws Exception {
+ super.loadPathInvalidResponse(requestPath);
+
+ // we have to load the uploadLocationResponse first
+ // so store the invalidResponse and load it in again after the uploadlocation
+ // has been added.
+ HttpResponse invalidResponse = this.mockClient.getHttpResponse();
+
+ this.mockClient.clearHttpResponseQueue();
+ this.loadUploadLocationResponseBody();
+ this.mockClient.addHttpResponse(invalidResponse);
+ }
+
+ @Override
+ protected void loadValidResponseBody() throws Exception {
+ JSONObject jsonResponseBody = new JSONObject();
+ jsonResponseBody.put(JsonKeys.ID, FILE_ID);
+ jsonResponseBody.put(JsonKeys.SOURCE, SOURCE);
+
+ InputStream responseStream =
+ new ByteArrayInputStream(jsonResponseBody.toString().getBytes());
+ MockHttpEntity responseEntity = new MockHttpEntity(responseStream);
+ StatusLine created = new BasicStatusLine(HttpVersion.HTTP_1_1, HttpStatus.SC_CREATED, "");
+ MockHttpResponse response = new MockHttpResponse(responseEntity, created);
+
+ this.mockClient.addHttpResponse(response);
+ }
+
+ protected void loadUploadLocationResponseBody() throws Exception {
+ /* create folder response */
+ JSONObject folder = new JSONObject();
+ folder.put(JsonKeys.UPLOAD_LOCATION, "https://upload.location.com/some/path");
+
+ InputStream uploadLocationStream =
+ new ByteArrayInputStream(folder.toString().getBytes());
+ MockHttpEntity uploadLocationEntity = new MockHttpEntity(uploadLocationStream);
+ StatusLine ok = new BasicStatusLine(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "");
+ MockHttpResponse uploadLocationResponse = new MockHttpResponse(uploadLocationEntity, ok);
+ this.mockClient.setHttpResponse(uploadLocationResponse);
+ }
+
+ @Override
+ protected String getMethod() {
+ return HttpPut.METHOD_NAME;
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // some upload requests perform two http requests, so clear any responses that may have
+ // been entered already. each test here is responsible for loading 1 or two responses.
+ this.mockClient.clearHttpResponseQueue();
+ this.responseQueue = new LinkedBlockingQueue<LiveOperation>();
+ this.queueingListener = new UploadOperationQueueingListener(this.exceptionQueue,
+ this.responseQueue);
+ }
+}
8 utilities/.classpath
View
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="gen"/>
+ <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
+ <classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
+ <classpathentry kind="output" path="bin/classes"/>
+</classpath>
33 utilities/.project
View
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>LiveSdkUtilities</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>com.android.ide.eclipse.adt.ApkBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>com.android.ide.eclipse.adt.AndroidNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
9 utilities/AndroidManifest.xml
View
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.microsoft.live.util"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <uses-sdk android:minSdkVersion="8" />
+
+</manifest>
90 utilities/build.xml
View
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="LiveSdkUtilities" default="help">
+
+ <!-- build.properties has the sdk.dir.
+ Must load environment variables before including it. -->
+ <property environment="env" />
+ <property file="../build.properties" />
+
+ <!-- The local.properties file is created and updated by the 'android' tool.
+ It contains the path to the SDK. It should *NOT* be checked into
+ Version Control Systems. -->
+ <property file="local.properties" />
+
+ <!-- The ant.properties file can be created by you. It is only edited by the
+ 'android' tool to add properties to it.
+ This is the place to change some Ant specific build properties.
+ Here are some properties you may want to change/update:
+
+ source.dir
+ The name of the source directory. Default is 'src'.
+ out.dir
+ The name of the output directory. Default is 'bin'.
+
+ For other overridable properties, look at the beginning of the rules
+ files in the SDK, at tools/ant/build.xml
+
+ Properties related to the SDK location or the project target should
+ be updated using the 'android' tool with the 'update' action.
+
+ This file is an integral part of the build system for your
+ application and should be checked into Version Control Systems.
+
+ -->
+ <property file="ant.properties" />
+
+ <!-- The project.properties file is created and updated by the 'android'
+ tool, as well as ADT.
+
+ This contains project specific properties such as project target, and library
+ dependencies. Lower level build properties are stored in ant.properties
+ (or in .classpath for Eclipse projects).
+
+ This file is an integral part of the build system for your
+ application and should be checked into Version Control Systems. -->
+ <loadproperties srcFile="project.properties" />
+
+ <!-- quick check on sdk.dir -->
+ <fail
+ message="sdk.dir is missing. Make sure to generate local.properties using 'android update project'"
+ unless="sdk.dir"
+ />
+
+
+<!-- extension targets. Uncomment the ones where you want to do custom work
+ in between standard targets -->
+<!--
+ <target name="-pre-build">
+ </target>
+ <target name="-pre-compile">
+ </target>
+
+ /* This is typically used for code obfuscation.
+ Compiled code location: ${out.classes.absolute.dir}
+ If this is not done in place, override ${out.dex.input.absolute.dir} */
+ <target name="-post-compile">
+ </target>
+-->
+
+ <!-- Import the actual build file.
+
+ To customize existing targets, there are two options:
+ - Customize only one target:
+ - copy/paste the target into this file, *before* the
+ <import> task.
+ - customize it to your needs.
+ - Customize the whole content of build.xml
+ - copy/paste the content of the rules files (minus the top node)
+ into this file, replacing the <import> task.
+ - customize to your needs.
+
+ ***********************
+ ****** IMPORTANT ******
+ ***********************
+ In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
+ in order to avoid having your file be overridden by tools such as "android update project"
+ -->
+ <!-- version-tag: custom -->
+ <import file="${sdk.dir}/tools/ant/build.xml" />
+
+</project>
40 utilities/proguard.cfg
View
@@ -0,0 +1,40 @@
+-optimizationpasses 5
+-dontusemixedcaseclassnames
+-dontskipnonpubliclibraryclasses
+-dontpreverify
+-verbose
+-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
+
+-keep public class * extends android.app.Activity
+-keep public class * extends android.app.Application
+-keep public class * extends android.app.Service
+-keep public class * extends android.content.BroadcastReceiver
+-keep public class * extends android.content.ContentProvider
+-keep public class * extends android.app.backup.BackupAgentHelper
+-keep public class * extends android.preference.Preference
+-keep public class com.android.vending.licensing.ILicensingService
+
+-keepclasseswithmembernames class * {
+ native <methods>;
+}
+
+-keepclasseswithmembers class * {
+ public <init>(android.content.Context, android.util.AttributeSet);
+}
+
+-keepclasseswithmembers class * {
+ public <init>(android.content.Context, android.util.AttributeSet, int);
+}
+
+-keepclassmembers class * extends android.app.Activity {
+ public void *(android.view.View);
+}
+
+-keepclassmembers enum * {
+ public static **[] values();
+ public static ** valueOf(java.lang.String);
+}
+
+-keep class * implements android.os.Parcelable {
+ public static final android.os.Parcelable$Creator *;
+}
13 utilities/project.properties
View
@@ -0,0 +1,13 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-8
+android.library.reference.1=../src
+android.library=true
11 utilities/src/com/microsoft/live/constants/ErrorCodes.java
View
@@ -0,0 +1,11 @@
+package com.microsoft.live.constants;
+
+public final class ErrorCodes {
+
+ public static final String REQUEST_PARAMETER_INVALID = "request_parameter_invalid";
+ public static final String REQUEST_PARAMETER_MISSING = "request_parameter_missing";
+ public static final String REQUEST_URL_INVALID = "request_url_invalid";
+ public static final String RESOURCE_NOT_FOUND = "resource_not_found";
+
+ private ErrorCodes() { throw new AssertionError(); }
+}
25 utilities/src/com/microsoft/live/constants/ErrorMessages.java
View
@@ -0,0 +1,25 @@
+package com.microsoft.live.constants;
+
+public final class ErrorMessages {
+
+ public static final String MISSING_REQUIRED_PARAMETER =
+ "The provided request entity body is missing a required parameter. " +
+ "The request must include at least one of the following: %1$s.";
+
+ public static final String MISSING_REQUIRED_PARAMETER_2 =
+ "The provided request entity body is missing a required parameter %1$s. " +
+ "Required parameters are the following: %1$s.";
+
+ public static final String PARAMETER_NOT_VALID =
+ "The provided value for the input resource ID parameter '%s' is not valid. " +
+ "Expected value is a resource ID for one of the following types: %s.";
+
+ public static final String RESOURCE_DOES_NOT_EXIST =
+ "The requested resource '%s' does not exist.";
+
+ public static final String URL_NOT_VALID =
+ "The provided URL is not valid. The requested path '%s' is not supported.";
+
+
+ private ErrorMessages() { throw new AssertionError(); }
+}
37