Repository: Azure/azure-functions-java-worker
Pull request #316 (2019-07-25 21:49:29)

Cardinality

amamounelsayed: @pragnagopa Files look good. Thank you!

Patch:
diff --git a/src/main/azure-functions-language-worker-protobuf/README.md b/src/main/azure-functions-language-worker-protobuf/README.md
index a490b96..0f0f234 100644
--- a/src/main/azure-functions-language-worker-protobuf/README.md
+++ b/src/main/azure-functions-language-worker-protobuf/README.md
@@ -26,19 +26,30 @@ From within the Azure Functions language worker repo:
 1.	Define remote branch for cleaner git commands
     -	`git remote add proto-file https://github.com/azure/azure-functions-language-worker-protobuf.git`
     -	`git fetch proto-file`
-2.	Merge updates
-    -   `git merge -s subtree proto-file/<version branch> --squash --allow-unrelated-histories` 
-        -   You can also merge with an explicit path to subtree: `git merge -X subtree=<path in language worker repo> --squash proto-file/<version branch> --allow-unrelated-histories`
-3.	Finalize with commit
-    -	`git commit -m "Updated subtree from https://github.com/azure/azure-functions-language-worker-protobuf. Branch: <version branch>. Commit: <latest protobuf commit hash>"`
+2.	Pull a specific release tag
+    -   `git fetch proto-file refs/tags/<tag-name>`
+        -   Example: `git fetch proto-file refs/tags/v1.1.0-protofile`
+3.	Merge updates
+    -   Merge with an explicit path to subtree: `git merge -X subtree=<path in language worker repo> --squash <tag-name> --allow-unrelated-histories --strategy-option theirs`
+        -   Example: `git merge -X subtree=src/WebJobs.Script.Grpc/azure-functions-language-worker-protobuf --squash v1.1.0-protofile --allow-unrelated-histories --strategy-option theirs`
+4.	Finalize with commit
+    -	`git commit -m "Updated subtree from https://github.com/azure/azure-functions-language-worker-protobuf. Tag: <tag-name>. Commit: <commit hash>"`
     -	`git push`
-	
+
+## Releasing a Language Worker Protobuf version
+
+1.	Draft a release in the GitHub UI
+    -   Be sure to inculde details of the release
+2.	Create a release version, following semantic versioning guidelines ([semver.org](https://semver.org/))
+3.	Tag the version with the pattern: `v<M>.<m>.<p>-protofile` (example: `v1.1.0-protofile`)
+3.	Merge `dev` to `master`
+
 ## Consuming FunctionRPC.proto
 *Note: Update versionNumber before running following commands*
 
 ## CSharp
 ```
-set NUGET_PATH=%UserProfile%\.nuget\packages
+set NUGET_PATH="%UserProfile%\.nuget\packages"
 set GRPC_TOOLS_PATH=%NUGET_PATH%\grpc.tools\<versionNumber>\tools\windows_x86
 set PROTO_PATH=.\azure-functions-language-worker-protobuf\src\proto
 set PROTO=.\azure-functions-language-worker-protobuf\src\proto\FunctionRpc.proto
diff --git a/src/main/azure-functions-language-worker-protobuf/src/proto/FunctionRpc.proto b/src/main/azure-functions-language-worker-protobuf/src/proto/FunctionRpc.proto
index 44857b8..2d54cf9 100644
--- a/src/main/azure-functions-language-worker-protobuf/src/proto/FunctionRpc.proto
+++ b/src/main/azure-functions-language-worker-protobuf/src/proto/FunctionRpc.proto
@@ -10,6 +10,8 @@ option go_package ="github.com/Azure/azure-functions-go-worker/internal/rpc";
 package AzureFunctionsRpcMessages;
 
 import "google/protobuf/duration.proto";
+import "identity/ClaimsIdentityRpc.proto";
+import "shared/NullableTypes.proto";
 
 // Interface exported by the server.
 service FunctionRpc {
@@ -201,6 +203,9 @@ message FunctionLoadRequest {
 
   // Metadata for the request
   RpcFunctionMetadata metadata = 2;
+
+  // A flag indicating if managed dependency is enabled or not
+  bool managed_dependency_enabled = 3;
 }
 
 // Worker tells host result of reload
@@ -211,6 +216,9 @@ message FunctionLoadResponse {
   // Result of load operation
   StatusResult result = 2;
   // TODO: return type expected?
+
+  // Result of load operation
+  bool is_dependency_downloaded = 3;
 }
 
 // Information on how a Function should be loaded and its bindings
@@ -229,6 +237,9 @@ message RpcFunctionMetadata {
 
   // Bindings info
   map<string, BindingInfo> bindings = 6;
+
+  // Is set to true for proxy
+  bool is_proxy = 7;
 }
 
 // Host requests worker to invoke a Function
@@ -278,11 +289,35 @@ message TypedData {
     bytes bytes = 3;
     bytes stream = 4;
     RpcHttp http = 5;
-	  sint64 int = 6;
+    sint64 int = 6;
     double double = 7;
+    CollectionBytes collection_bytes = 8;
+    CollectionString collection_string = 9;
+    CollectionDouble collection_double = 10;
+    CollectionSInt64 collection_sint64 = 11;
   }
 }
 
+// Used to encapsulate collection string
+message CollectionString {
+  repeated string string = 1;
+}
+
+// Used to encapsulate collection bytes
+message CollectionBytes {
+  repeated bytes bytes = 1;
+}
+
+// Used to encapsulate collection double
+message CollectionDouble {
+  repeated double double = 1;
+}
+
+// Used to encapsulate collection sint64
+message CollectionSInt64 {
+  repeated sint64 sint64 = 1;
+}
+
 // Used to describe a given binding on invocation
 message ParameterBinding {
   // Name for the binding
@@ -368,6 +403,44 @@ message RpcException {
   string message = 2;
 }
 
+// Http cookie type. Note that only name and value are used for Http requests
+message RpcHttpCookie {
+  // Enum that lets servers require that a cookie shouoldn't be sent with cross-site requests
+  enum SameSite {
+      None = 0;
+      Lax = 1;
+      Strict = 2;
+  }
+
+  // Cookie name
+  string name = 1;
+
+  // Cookie value
+  string value = 2;
+
+  // Specifies allowed hosts to receive the cookie
+  NullableString domain = 3;
+
+  // Specifies URL path that must exist in the requested URL
+  NullableString path = 4;
+
+  // Sets the cookie to expire at a specific date instead of when the client closes.
+  // It is generally recommended that you use "Max-Age" over "Expires".
+  NullableTimestamp expires = 5;
+
+  // Sets the cookie to only be sent with an encrypted request
+  NullableBool secure = 6;
+
+  // Sets the cookie to be inaccessible to JavaScript's Document.cookie API
+  NullableBool http_only = 7;
+
+  // Allows servers to assert that a cookie ought not to be sent along with cross-site requests
+  SameSite same_site = 8;
+
+  // Number of seconds until the cookie expires. A zero or negative number will expire the cookie immediately.
+  NullableDouble max_age = 9;
+}
+
 // TODO - solidify this or remove it
 message RpcHttp {
   string method = 1;
@@ -379,4 +452,6 @@ message RpcHttp {
   map<string,string> query = 15;
   bool enable_content_negotiation= 16;
   TypedData rawBody = 17;
+  repeated RpcClaimsIdentity identities = 18;
+  repeated RpcHttpCookie cookies = 19;
 }
diff --git a/src/main/azure-functions-language-worker-protobuf/src/proto/identity/ClaimsIdentityRpc.proto b/src/main/azure-functions-language-worker-protobuf/src/proto/identity/ClaimsIdentityRpc.proto
new file mode 100644
index 0000000..c3945bb
--- /dev/null
+++ b/src/main/azure-functions-language-worker-protobuf/src/proto/identity/ClaimsIdentityRpc.proto
@@ -0,0 +1,26 @@
+syntax = "proto3";
+// protobuf vscode extension: https://marketplace.visualstudio.com/items?itemName=zxh404.vscode-proto3
+
+option java_package = "com.microsoft.azure.functions.rpc.messages";
+
+import "shared/NullableTypes.proto";
+
+// Light-weight representation of a .NET System.Security.Claims.ClaimsIdentity object.
+// This is the same serialization as found in EasyAuth, and needs to be kept in sync with
+// its ClaimsIdentitySlim definition, as seen in the WebJobs extension:
+// https://github.com/Azure/azure-webjobs-sdk-extensions/blob/dev/src/WebJobs.Extensions.Http/ClaimsIdentitySlim.cs
+message RpcClaimsIdentity {
+  NullableString authentication_type = 1;
+  NullableString name_claim_type = 2;
+  NullableString role_claim_type = 3;
+  repeated RpcClaim claims = 4;
+}
+
+// Light-weight representation of a .NET System.Security.Claims.Claim object.
+// This is the same serialization as found in EasyAuth, and needs to be kept in sync with
+// its ClaimSlim definition, as seen in the WebJobs extension:
+// https://github.com/Azure/azure-webjobs-sdk-extensions/blob/dev/src/WebJobs.Extensions.Http/ClaimSlim.cs
+message RpcClaim {
+  string value = 1;
+  string type = 2;
+}
diff --git a/src/main/azure-functions-language-worker-protobuf/src/proto/shared/NullableTypes.proto b/src/main/azure-functions-language-worker-protobuf/src/proto/shared/NullableTypes.proto
new file mode 100644
index 0000000..4fb4765
--- /dev/null
+++ b/src/main/azure-functions-language-worker-protobuf/src/proto/shared/NullableTypes.proto
@@ -0,0 +1,30 @@
+syntax = "proto3";
+// protobuf vscode extension: https://marketplace.visualstudio.com/items?itemName=zxh404.vscode-proto3
+
+option java_package = "com.microsoft.azure.functions.rpc.messages";
+
+import "google/protobuf/timestamp.proto";
+
+message NullableString {
+	oneof string {
+		string value = 1;
+	}
+}
+
+message NullableDouble {
+	oneof double {
+		double value = 1;
+	}
+}
+
+message NullableBool {
+	oneof bool {
+		bool value = 1;
+	}
+}
+
+message NullableTimestamp {
+	oneof timestamp {
+		google.protobuf.Timestamp value = 1;
+	}
+}
diff --git a/src/main/java/com/microsoft/azure/functions/worker/binding/BindingDataStore.java b/src/main/java/com/microsoft/azure/functions/worker/binding/BindingDataStore.java
index 5c3e823..7539747 100644
--- a/src/main/java/com/microsoft/azure/functions/worker/binding/BindingDataStore.java
+++ b/src/main/java/com/microsoft/azure/functions/worker/binding/BindingDataStore.java
@@ -1,6 +1,5 @@
 package com.microsoft.azure.functions.worker.binding;
 
-import java.io.IOException;
 import java.lang.reflect.*;
 import java.util.*;
 
@@ -35,7 +34,7 @@ public final class BindingDataStore {
     }
 
     public void addTriggerMetadataSource(Map<String, TypedData> metadata) {        
-        for (Map.Entry<String,TypedData> entry : metadata.entrySet())  
+        for (Map.Entry<String,TypedData> entry : metadata.entrySet())
         {
         	DataSource<?> inputValue = rpcSourceFromTypedData(entry.getKey(), entry.getValue());            
             this.metadataSources.put(entry.getKey(), inputValue);        	
@@ -66,6 +65,10 @@ public final class BindingDataStore {
             case BYTES:  return new RpcByteArrayDataSource(name, data.getBytes());
             case JSON:   return new RpcJsonDataSource(name, data.getJson());
             case HTTP:   return new RpcHttpRequestDataSource(name, data.getHttp());
+            case COLLECTION_STRING: return new RpcCollectionStringDataSource(name, data.getCollectionString());
+            case COLLECTION_DOUBLE: return new RpcCollectionDoubleDataSource(name, data.getCollectionDouble());
+            case COLLECTION_BYTES: return new RpcCollectionByteArrayDataSource(name, data.getCollectionBytes());
+            case COLLECTION_SINT64: return new RpcCollectionLongDataSource(name, data.getCollectionSint64());
             case DATA_NOT_SET: return new RpcEmptyDataSource(name);
             default:     throw new UnsupportedOperationException("Input data type \"" + data.getDataCase() + "\" is not supported");
         }
diff --git a/src/main/java/com/microsoft/azure/functions/worker/binding/RpcCollectionByteArrayDataSource.java b/src/main/java/com/microsoft/azure/functions/worker/binding/RpcCollectionByteArrayDataSource.java
new file mode 100644
index 0000000..408361c
--- /dev/null
+++ b/src/main/java/com/microsoft/azure/functions/worker/binding/RpcCollectionByteArrayDataSource.java
@@ -0,0 +1,54 @@
+package com.microsoft.azure.functions.worker.binding;
+
+import com.google.protobuf.ByteString;
+import com.microsoft.azure.functions.rpc.messages.CollectionBytes;
+import org.apache.commons.lang3.ArrayUtils;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public final class RpcCollectionByteArrayDataSource extends DataSource<List<ByteString>> {
+	public RpcCollectionByteArrayDataSource(String name, CollectionBytes value) {
+		super(name, value.getBytesList(), COLLECTION_DATA_OPERATIONS);
+	}
+	private static final DataOperations<List<ByteString>, Object> COLLECTION_DATA_OPERATIONS = new DataOperations<>();
+
+	public static Object convertToByteList(List<ByteString> sourceValue, Type targetType) {
+		if(targetType == List.class) {
+			return sourceValue.stream().map(element -> element.toByteArray()).collect(Collectors.toCollection(ArrayList::new));
+		}
+		else if(targetType instanceof ParameterizedType){
+			Type targetActualType = ((ParameterizedType) targetType).getActualTypeArguments()[0];
+			if (targetActualType == byte[].class) {
+				return sourceValue.stream().map(element -> element.toByteArray()).collect(Collectors.toCollection(ArrayList::new));
+			} else if (targetActualType == Byte[].class) {
+				return sourceValue.stream().map(element -> (ArrayUtils.toObject(element.toByteArray()))).collect(Collectors.toList());
+			}
+			throw new UnsupportedOperationException("Input data type \"" + targetActualType + "\" is not supported");
+		}
+		throw new UnsupportedOperationException("Input data type \"" + targetType + "\" is not supported");
+	}
+
+	public static Object convertToByteListDefault(List<ByteString> sourceValue, Type targetType) {
+		return sourceValue.stream().map(element -> element.toByteArray()).collect(Collectors.toCollection(ArrayList::new));
+	}
+
+	public static Object convertToBytesArray(List<ByteString> sourceValue, Type targetType) {
+		return sourceValue.stream().map(element -> element.toByteArray()).collect(Collectors.toCollection(ArrayList::new)).toArray(new byte[0][]);
+	}
+
+	public static Object convertToBytesObjectArray(List<ByteString> sourceValue, Type targetType) {
+		return sourceValue.stream().map(element ->  (ArrayUtils.toObject(element.toByteArray()))).collect(Collectors.toCollection(ArrayList::new)).toArray(new Byte[0][]);
+	}
+
+	static {
+		COLLECTION_DATA_OPERATIONS.addGenericOperation(List.class, (v, t) -> convertToByteList(v, t));
+		COLLECTION_DATA_OPERATIONS.addGenericOperation(byte[][].class, (v, t) -> convertToBytesArray(v, t));
+		COLLECTION_DATA_OPERATIONS.addGenericOperation(Byte[][].class, (v, t) -> convertToBytesObjectArray(v, t));
+		COLLECTION_DATA_OPERATIONS.addGenericOperation(String.class, (v, t) -> convertToByteListDefault(v, t));
+	}
+}
+
diff --git a/src/main/java/com/microsoft/azure/functions/worker/binding/RpcCollectionDoubleDataSource.java b/src/main/java/com/microsoft/azure/functions/worker/binding/RpcCollectionDoubleDataSource.java
new file mode 100644
index 0000000..71ada30
--- /dev/null
+++ b/src/main/java/com/microsoft/azure/functions/worker/binding/RpcCollectionDoubleDataSource.java
@@ -0,0 +1,49 @@
+package com.microsoft.azure.functions.worker.binding;
+
+import com.microsoft.azure.functions.rpc.messages.CollectionDouble;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.List;
+
+public final class RpcCollectionDoubleDataSource extends DataSource<List<Double>> {
+	public RpcCollectionDoubleDataSource(String name, CollectionDouble value) {
+		super(name, value.getDoubleList(), COLLECTION_DATA_OPERATIONS);
+	}
+	private static final DataOperations<List<Double>, Object> COLLECTION_DATA_OPERATIONS = new DataOperations<>();
+
+	public static Object convertToDoubleListDefault(List<Double> sourceValue, Type targetType) {
+		return new ArrayList<>(sourceValue);
+	}
+
+	public static Object convertToDoubleList(List<Double> sourceValue, Type targetType) {
+		if(targetType == List.class) {
+			return new ArrayList<>(sourceValue);
+		}
+		else if(targetType instanceof ParameterizedType) {
+			Type targetActualType = ((ParameterizedType) targetType).getActualTypeArguments()[0];
+			if (targetActualType == Double.class) {
+				return new ArrayList<>(sourceValue);
+			}
+			throw new UnsupportedOperationException("Input data type \"" + targetActualType + "\" is not supported");
+		}
+		throw new UnsupportedOperationException("Input data type \"" + targetType + "\" is not supported");
+	}
+
+    public static Object convertToDoubleObjectArray(List<Double> sourceValue, Type targetType) {
+        return new ArrayList<>(sourceValue).toArray(new Double[0]);
+    }
+
+    public static Object convertToDoubleArray(List<Double> sourceValue, Type targetType) {
+        return sourceValue.stream().mapToDouble(Double::doubleValue).toArray();
+    }
+
+	static {
+		COLLECTION_DATA_OPERATIONS.addGenericOperation(List.class, (v, t) -> convertToDoubleList(v, t));
+		COLLECTION_DATA_OPERATIONS.addGenericOperation(Double[].class, (v, t) -> convertToDoubleObjectArray(v, t));
+		COLLECTION_DATA_OPERATIONS.addGenericOperation(double[].class, (v, t) -> convertToDoubleArray(v, t));
+		COLLECTION_DATA_OPERATIONS.addGenericOperation(String.class, (v, t) -> convertToDoubleListDefault(v, t));
+    }
+}
+
diff --git a/src/main/java/com/microsoft/azure/functions/worker/binding/RpcCollectionLongDataSource.java b/src/main/java/com/microsoft/azure/functions/worker/binding/RpcCollectionLongDataSource.java
new file mode 100644
index 0000000..d22ec2b
--- /dev/null
+++ b/src/main/java/com/microsoft/azure/functions/worker/binding/RpcCollectionLongDataSource.java
@@ -0,0 +1,49 @@
+package com.microsoft.azure.functions.worker.binding;
+
+import com.microsoft.azure.functions.rpc.messages.CollectionSInt64;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.List;
+
+public final class RpcCollectionLongDataSource extends DataSource<List<Long>> {
+	public RpcCollectionLongDataSource(String name, CollectionSInt64 value) {
+		super(name, value.getSint64List(), COLLECTION_DATA_OPERATIONS);
+	}
+	private static final DataOperations<List<Long>, Object> COLLECTION_DATA_OPERATIONS = new DataOperations<>();
+
+	public static Object convertToLongList(List<Long> sourceValue, Type targetType) {
+		if(targetType == List.class) {
+			return new ArrayList<>(sourceValue);
+		}
+		else if(targetType instanceof ParameterizedType) {
+			Type targetActualType = ((ParameterizedType) targetType).getActualTypeArguments()[0];
+			if (targetActualType == Long.class) {
+				return new ArrayList<>(sourceValue);
+			}
+			throw new UnsupportedOperationException("Input data type \"" + targetActualType + "\" is not supported");
+		}
+		throw new UnsupportedOperationException("Input data type \"" + targetType + "\" is not supported");
+	}
+
+	public static Object convertToLongListDefault(List<Long> sourceValue, Type targetType) {
+		return new ArrayList<>(sourceValue);
+	}
+
+	public static Object convertToLongObjectArray(List<Long> sourceValue, Type targetType) {
+		return new ArrayList<>(sourceValue).toArray(new Long[0]);
+	}
+
+	public static Object convertToLongArray(List<Long> sourceValue, Type targetType) {
+		return sourceValue.stream().mapToLong(Long::longValue).toArray();
+	}
+
+	static {
+		COLLECTION_DATA_OPERATIONS.addGenericOperation(List.class, (v, t) -> convertToLongList(v, t));
+		COLLECTION_DATA_OPERATIONS.addGenericOperation(Long[].class, (v, t) -> convertToLongObjectArray(v, t));
+		COLLECTION_DATA_OPERATIONS.addGenericOperation(long[].class, (v, t) -> convertToLongArray(v, t));
+		COLLECTION_DATA_OPERATIONS.addGenericOperation(String.class, (v, t) -> convertToLongListDefault(v, t));
+	}
+}
+
diff --git a/src/main/java/com/microsoft/azure/functions/worker/binding/RpcCollectionStringDataSource.java b/src/main/java/com/microsoft/azure/functions/worker/binding/RpcCollectionStringDataSource.java
new file mode 100644
index 0000000..bb4708f
--- /dev/null
+++ b/src/main/java/com/microsoft/azure/functions/worker/binding/RpcCollectionStringDataSource.java
@@ -0,0 +1,44 @@
+package com.microsoft.azure.functions.worker.binding;
+
+import com.microsoft.azure.functions.rpc.messages.CollectionString;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.List;
+
+public final class RpcCollectionStringDataSource extends DataSource<List<String>> {
+	public RpcCollectionStringDataSource(String name, CollectionString value) {
+		super(name, value.getStringList(), COLLECTION_DATA_OPERATIONS);
+	}
+	private static final DataOperations<List<String>, Object> COLLECTION_DATA_OPERATIONS = new DataOperations<>();
+
+	public static Object convertToStringList(List<String> sourceValue, Type targetType) {
+		if(targetType == List.class) {
+			return new ArrayList<>(sourceValue);
+		}
+		else if(targetType instanceof ParameterizedType) {
+			Type targetActualType = ((ParameterizedType) targetType).getActualTypeArguments()[0];
+			if (targetActualType == String.class) {
+				return new ArrayList<>(sourceValue);
+			}
+			throw new UnsupportedOperationException("Input data type \"" + targetActualType + "\" is not supported");
+		}
+		throw new UnsupportedOperationException("Input data type \"" + targetType + "\" is not supported");
+	}
+
+	public static Object convertToStringArray(List<String> sourceValue, Type targetType) {
+		return new ArrayList<>(sourceValue).toArray(new String[0]);
+	}
+
+	public static Object convertToStringListDefault(List<String> sourceValue, Type targetType) {
+		return new ArrayList<>(sourceValue);
+	}
+
+	static {
+		COLLECTION_DATA_OPERATIONS.addGenericOperation(List.class, (v, t) -> convertToStringList(v, t));
+		COLLECTION_DATA_OPERATIONS.addGenericOperation(String[].class, (v, t) -> convertToStringArray(v, t));
+		COLLECTION_DATA_OPERATIONS.addGenericOperation(String.class, (v, t) -> convertToStringListDefault(v, t));
+	}
+}
+
diff --git a/src/main/java/com/microsoft/azure/functions/worker/handler/WorkerInitRequestHandler.java b/src/main/java/com/microsoft/azure/functions/worker/handler/WorkerInitRequestHandler.java
index eb89639..993860b 100644
--- a/src/main/java/com/microsoft/azure/functions/worker/handler/WorkerInitRequestHandler.java
+++ b/src/main/java/com/microsoft/azure/functions/worker/handler/WorkerInitRequestHandler.java
@@ -14,6 +14,7 @@ public class WorkerInitRequestHandler extends MessageHandler<WorkerInitRequest,
     @Override
     String execute(WorkerInitRequest request, WorkerInitResponse.Builder response) {
         response.setWorkerVersion(Application.version());
+        response.putCapabilities("TypedDataCollection", "TypedDataCollection");
         return "Worker initialized";
     }
 }


Test patch:
diff --git a/endtoendtests/Azure.Functions.Java.Tests.E2E/Azure.Functions.Java.Tests.E2E/Constants.cs b/endtoendtests/Azure.Functions.Java.Tests.E2E/Azure.Functions.Java.Tests.E2E/Constants.cs
index a6aec7a..7fed4d3 100644
--- a/endtoendtests/Azure.Functions.Java.Tests.E2E/Azure.Functions.Java.Tests.E2E/Constants.cs
+++ b/endtoendtests/Azure.Functions.Java.Tests.E2E/Azure.Functions.Java.Tests.E2E/Constants.cs
@@ -37,10 +37,26 @@ namespace Azure.Functions.Java.Tests.E2E
         // EventHubs
         public static string OutputEventHubQueueName = "test-eventhuboutput-java";
         public static string InputEventHubName = "test-input-java";
+
         public static string OutputJsonEventHubQueueName = "test-eventhuboutputjson-java";
         public static string InputJsonEventHubName = "test-inputjson-java";
+
         public static string OutputOneEventHubQueueName = "test-eventhuboutputone-java";
         public static string InputCardinalityOneEventHubName = "test-inputOne-java";
+
+        public static string OutputBinaryOneQueueName = "test-binary-output-cardinality-one-java";
+        public static string InputBinaryOneEventHubQueueName = "test-binary-input-cardinality-one-java";
+
+        public static string OutputBinaryManyQueueName = "test-binary-output-cardinality-many-list-java";
+        public static string InputBinaryManyEventHubQueueName = "test-binary-input-cardinality-many-list-java";
+
+        public static string OutputBinaryArrayManyQueueName = "test-binary-output-cardinality-many-array-java";
+        public static string InputBinaryManyArrayEventHubQueueName = "test-binary-input-cardinality-many-array-java";
+
+        // Settings
+        public static string EventHubsConnectionStringSenderSetting = Environment.GetEnvironmentVariable("AzureWebJobsEventHubSender");
+        public static string EventHubsConnectionStringSenderSetting2 = Environment.GetEnvironmentVariable("AzureWebJobsEventHubSender_2");
+
         public static string EventHubsConnectionStringSetting = Environment.GetEnvironmentVariable("AzureWebJobsEventHubSender");
 
         // Xunit Fixtures and Collections
diff --git a/endtoendtests/Azure.Functions.Java.Tests.E2E/Azure.Functions.Java.Tests.E2E/EventHubsEndToEndTests.cs b/endtoendtests/Azure.Functions.Java.Tests.E2E/Azure.Functions.Java.Tests.E2E/EventHubsEndToEndTests.cs
index 6e1ec18..55e59ee 100644
--- a/endtoendtests/Azure.Functions.Java.Tests.E2E/Azure.Functions.Java.Tests.E2E/EventHubsEndToEndTests.cs
+++ b/endtoendtests/Azure.Functions.Java.Tests.E2E/Azure.Functions.Java.Tests.E2E/EventHubsEndToEndTests.cs
@@ -5,6 +5,7 @@ using Newtonsoft.Json.Linq;
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using System.Reflection.Metadata;
 using System.Threading.Tasks;
 using Xunit;
 
@@ -29,7 +30,7 @@ namespace Azure.Functions.Java.Tests.E2E
                 await SetupQueue(Constants.OutputJsonEventHubQueueName);
 
                 // Need to setup EventHubs: test-inputjson-java and test-outputjson-java
-                await EventHubsHelpers.SendJSONMessagesAsync(expectedEventId);
+                await EventHubsHelpers.SendJSONMessagesAsync(expectedEventId, Constants.EventHubsConnectionStringSenderSetting);
 
                 //Verify
                 var queueMessage = await StorageHelpers.ReadFromQueue(Constants.OutputJsonEventHubQueueName);
@@ -52,7 +53,7 @@ namespace Azure.Functions.Java.Tests.E2E
                 await SetupQueue(Constants.OutputEventHubQueueName);
 
                 // Need to setup EventHubs: test-input-java and test-output-java
-                await EventHubsHelpers.SendMessagesAsync(expectedEventId, Constants.InputEventHubName);
+                await EventHubsHelpers.SendMessagesAsync(expectedEventId, Constants.InputEventHubName, Constants.EventHubsConnectionStringSenderSetting);
 
                 //Verify
                 var queueMessage = await StorageHelpers.ReadFromQueue(Constants.OutputEventHubQueueName);
@@ -74,7 +75,7 @@ namespace Azure.Functions.Java.Tests.E2E
                 await SetupQueue(Constants.OutputOneEventHubQueueName);
 
                 // Need to setup EventHubs: test-inputOne-java and test-outputone-java
-                await EventHubsHelpers.SendMessagesAsync(expectedEventId, Constants.InputCardinalityOneEventHubName);
+                await EventHubsHelpers.SendMessagesAsync(expectedEventId, Constants.InputCardinalityOneEventHubName, Constants.EventHubsConnectionStringSenderSetting);
 
                 //Verify
                 IEnumerable<string> queueMessages = await StorageHelpers.ReadMessagesFromQueue(Constants.OutputOneEventHubQueueName);
@@ -87,6 +88,72 @@ namespace Azure.Functions.Java.Tests.E2E
             }
         }
 
+        /*
+        [Fact]
+        public async Task EventHubTriggerAndOutputBinaryListMany_Succeeds()
+        {
+            string expectedEventId = Guid.NewGuid().ToString();
+            try
+            {
+                await SetupQueue(Constants.OutputBinaryManyQueueName);
+
+                await EventHubsHelpers.SendMessagesAsync(expectedEventId, Constants.InputBinaryManyEventHubQueueName, Constants.EventHubsConnectionStringSenderSetting2);
+
+                //Verify
+                var queueMessage = await StorageHelpers.ReadFromQueue(Constants.OutputBinaryManyQueueName);
+                Assert.Contains(expectedEventId, queueMessage);
+            }
+            finally
+            {
+                //Clear queue
+                await StorageHelpers.ClearQueue(Constants.OutputEventHubQueueName);
+            }
+        }
+        */
+        [Fact]
+       public async Task EventHubTriggerAndOutputBinaryOne_Succeeds()
+        {
+            string expectedEventId = Guid.NewGuid().ToString();
+            try
+            {
+                await SetupQueue(Constants.OutputBinaryOneQueueName);
+
+                await EventHubsHelpers.SendMessagesAsync(expectedEventId, Constants.InputBinaryOneEventHubQueueName, Constants.EventHubsConnectionStringSenderSetting2);
+
+                //Verify
+                var queueMessage = await StorageHelpers.ReadFromQueue(Constants.OutputBinaryOneQueueName);
+                Assert.Contains(expectedEventId, queueMessage);
+            }
+            finally
+            {
+                //Clear queue
+                await StorageHelpers.ClearQueue(Constants.OutputEventHubQueueName);
+            }
+        }
+        /*
+        [Fact]
+        public async Task EventHubTriggerAndOutputBinaryArrayMany_Succeeds()
+        {
+            string expectedEventId = Guid.NewGuid().ToString();
+            try
+            {
+                await SetupQueue(Constants.OutputBinaryArrayManyQueueName);
+
+                await EventHubsHelpers.SendMessagesAsync(expectedEventId, Constants.InputBinaryManyArrayEventHubQueueName, Constants.EventHubsConnectionStringSenderSetting2);
+
+                //Verify
+                var queueMessage = await StorageHelpers.ReadFromQueue(Constants.OutputBinaryArrayManyQueueName);
+                Assert.Contains(expectedEventId, queueMessage);
+            }
+            finally
+            {
+                //Clear queue
+                await StorageHelpers.ClearQueue(Constants.OutputEventHubQueueName);
+            }
+        }
+        */
+       
+
         private static async Task SetupQueue(string queueName)
         {
             //Clear queue
diff --git a/endtoendtests/Azure.Functions.Java.Tests.E2E/Azure.Functions.Java.Tests.E2E/Helpers/EventHubsHelpers.cs b/endtoendtests/Azure.Functions.Java.Tests.E2E/Azure.Functions.Java.Tests.E2E/Helpers/EventHubsHelpers.cs
index d73d7b2..e1f350e 100644
--- a/endtoendtests/Azure.Functions.Java.Tests.E2E/Azure.Functions.Java.Tests.E2E/Helpers/EventHubsHelpers.cs
+++ b/endtoendtests/Azure.Functions.Java.Tests.E2E/Azure.Functions.Java.Tests.E2E/Helpers/EventHubsHelpers.cs
@@ -12,7 +12,7 @@ namespace Azure.Functions.Java.Tests.E2E
 {
     public class EventHubsHelpers
     {
-        public static async Task SendJSONMessagesAsync(string eventId)
+        public static async Task SendJSONMessagesAsync(string eventId, string connectionString)
         {
             // write 3 events
             List<EventData> events = new List<EventData>();
@@ -29,13 +29,13 @@ namespace Azure.Functions.Java.Tests.E2E
                 events.Add(evt);
             }
 
-            EventHubsConnectionStringBuilder builder = new EventHubsConnectionStringBuilder(Constants.EventHubsConnectionStringSetting);
+            EventHubsConnectionStringBuilder builder = new EventHubsConnectionStringBuilder(connectionString);
             builder.EntityPath = Constants.InputJsonEventHubName;
             EventHubClient eventHubClient = EventHubClient.CreateFromConnectionString(builder.ToString());
             await eventHubClient.SendAsync(events);
         }
 
-        public static async Task SendMessagesAsync(string eventId, string evenHubName)
+        public static async Task SendMessagesAsync(string eventId, string evenHubName, string connectionString)
         {
             // write 3 events
             List<EventData> events = new List<EventData>();
@@ -48,7 +48,7 @@ namespace Azure.Functions.Java.Tests.E2E
                 events.Add(evt);
             }
 
-            EventHubsConnectionStringBuilder builder = new EventHubsConnectionStringBuilder(Constants.EventHubsConnectionStringSetting);
+            EventHubsConnectionStringBuilder builder = new EventHubsConnectionStringBuilder(connectionString);
             builder.EntityPath = evenHubName;
             EventHubClient eventHubClient = EventHubClient.CreateFromConnectionString(builder.ToString());
             await eventHubClient.SendAsync(events);
diff --git a/endtoendtests/local.settings.json b/endtoendtests/local.settings.json
index 25a28df..920e6ce 100644
--- a/endtoendtests/local.settings.json
+++ b/endtoendtests/local.settings.json
@@ -4,6 +4,7 @@
     "AzureWebJobsServiceBus": "",
     "AzureWebJobsEventHubReceiver":"",
     "AzureWebJobsEventHubSender":"",
+    "AzureWebJobsEventHubSender_2":"",
     "AzureWebJobsEventHubPath":"",
     "CosmosDBDatabaseName":"",
     "CosmosDBCollectionName":"",
diff --git a/endtoendtests/src/main/java/com/microsoft/azure/functions/endtoend/EventHubTriggerTests.java b/endtoendtests/src/main/java/com/microsoft/azure/functions/endtoend/EventHubTriggerTests.java
index a2e9efd..3f1f784 100644
--- a/endtoendtests/src/main/java/com/microsoft/azure/functions/endtoend/EventHubTriggerTests.java
+++ b/endtoendtests/src/main/java/com/microsoft/azure/functions/endtoend/EventHubTriggerTests.java
@@ -47,7 +47,7 @@ public class EventHubTriggerTests {
     /**
      * This function verifies the above functions
      */
-    @FunctionName("TestEventHubOutputJson")
+    @FunctionName("EventHubOutputJson")
     public void TestEventHubOutputJson(
         @EventHubTrigger(name = "message", eventHubName = "test-outputjson-java", connection = "AzureWebJobsEventHubSender") String message,
         @QueueOutput(name = "output", queueName = "test-eventhuboutputjson-java", connection = "AzureWebJobsStorage") OutputBinding<String> output,
@@ -57,7 +57,7 @@ public class EventHubTriggerTests {
         output.setValue(message);
     }
 
-    @FunctionName("TestEventHubOutput")
+    @FunctionName("EventHubOutput")
     public void TestEventHubOutput(
         @EventHubTrigger(name = "message", eventHubName = "test-output-java", connection = "AzureWebJobsEventHubSender", cardinality = Cardinality.ONE) String message,
         @QueueOutput(name = "output", queueName = "test-eventhuboutput-java", connection = "AzureWebJobsStorage") OutputBinding<String> output,
@@ -67,7 +67,7 @@ public class EventHubTriggerTests {
         output.setValue(message);
     }
 
-    @FunctionName("TestEventHubOutputInputOne")
+    @FunctionName("EventHubOutputInputOne")
     public void TestEventHubOutputInputOne(
         @EventHubTrigger(name = "message", eventHubName = "test-outputone-java", connection = "AzureWebJobsEventHubSender", cardinality = Cardinality.ONE) String message,
         @QueueOutput(name = "output", queueName = "test-eventhuboutputone-java", connection = "AzureWebJobsStorage") OutputBinding<String> output,
@@ -77,11 +77,40 @@ public class EventHubTriggerTests {
         output.setValue(message);
     }
 
+    @FunctionName("EventHubTriggerAndOutputBinaryCardinalityManyListBinary")
+    public void EventHubTriggerAndOutputBinaryCardinalityManyListBinary(
+            @EventHubTrigger(name = "messages", eventHubName = "test-binary-input-cardinality-many-list-java", connection = "AzureWebJobsEventHubSender_2", dataType = "binary", cardinality = Cardinality.MANY) List<byte[]> messages,
+            @QueueOutput(name = "output", queueName = "test-binary-output-cardinality-many-list-java", connection = "AzureWebJobsStorage") OutputBinding<byte[]> output,
+            final ExecutionContext context
+    ) {
+        context.getLogger().info("Java Event Hub trigger received " + messages.size() +" messages");
+        output.setValue(messages.get(0));
+    }
+
+    @FunctionName("EventHubTriggerAndOutputBinaryCardinalityOne")
+    public void EventHubTriggerAndOutputBinaryCardinalityOne(
+            @EventHubTrigger(name = "message", eventHubName = "test-binary-input-cardinality-one-java", connection = "AzureWebJobsEventHubSender_2", dataType = "binary", cardinality = Cardinality.ONE) byte[] message,
+            @QueueOutput(name = "output", queueName = "test-binary-output-cardinality-one-java",connection = "AzureWebJobsStorage") OutputBinding<byte[]> output,
+            final ExecutionContext context
+    ) {
+        context.getLogger().info("Java Event Hub trigger received message" + message);
+        output.setValue(message);
+    }
+
+    @FunctionName("EventHubTriggerAndOutputBinaryCardinalityManyArrayBinary")
+    public void EventHubTriggerAndOutputBinaryCardinalityManyArrayBinary(
+            @EventHubTrigger(name = "messages", eventHubName = "test-binary-input-cardinality-many-array-java", connection = "AzureWebJobsEventHubSender_2", dataType = "binary", cardinality = Cardinality.MANY) byte[][] messages,
+            @QueueOutput(name = "output", queueName = "test-binary-output-cardinality-many-array-java", connection = "AzureWebJobsStorage") OutputBinding<byte[]> output,
+            final ExecutionContext context
+    ) {
+        context.getLogger().info("Java Event Hub trigger received " + messages.length +" messages");
+        output.setValue(messages[0]);
+    }
+
     public static class SystemProperty {
       public String SequenceNumber;
       public String Offset;
       public String PartitionKey;        
       public String EnqueuedTimeUtc;
   }
-   
 }
diff --git a/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionByteArrayDataSourceTest.java b/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionByteArrayDataSourceTest.java
new file mode 100644
index 0000000..e29c1f2
--- /dev/null
+++ b/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionByteArrayDataSourceTest.java
@@ -0,0 +1,167 @@
+package com.microsoft.azure.functions.worker.binding.tests;
+
+import com.google.protobuf.ByteString;
+import com.microsoft.azure.functions.worker.binding.BindingData;
+import com.microsoft.azure.functions.worker.binding.RpcCollectionByteArrayDataSource;
+import com.microsoft.azure.functions.rpc.messages.CollectionBytes;
+import com.microsoft.azure.functions.rpc.messages.CollectionBytes.Builder;
+
+import org.apache.commons.lang3.ArrayUtils;
+import org.junit.Test;
+
+import java.lang.invoke.WrongMethodTypeException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+import static org.junit.Assert.assertEquals;
+
+public class RpcCollectionByteArrayDataSourceTest {
+    @Test
+    public void rpcByteArrayDataSource_To_byte_Array() {
+        String sourceKey = "sourceKey";
+        String expectedString = "Example String";
+        byte[] expctedStingBytes = expectedString.getBytes();
+        ByteString inputByteString = ByteString.copyFrom(expctedStingBytes);
+
+        List<ByteString> input = new ArrayList<ByteString>();
+        input.add(inputByteString);
+
+        Builder a = CollectionBytes.newBuilder();
+        a.addAllBytes(input);
+
+        CollectionBytes typedDataCollectionBytes = a.build();
+
+        RpcCollectionByteArrayDataSource stringData = new RpcCollectionByteArrayDataSource(sourceKey, typedDataCollectionBytes);
+
+        Optional<BindingData> actualBindingData = stringData.computeByName(sourceKey, byte[][].class);
+        BindingData actualArg = actualBindingData.orElseThrow(WrongMethodTypeException::new);
+        byte[][] actualBytes = (byte[][]) actualArg.getValue();
+        String actualString = new String(actualBytes[0]);
+        assertEquals(actualString, expectedString);
+    }
+
+    @Test
+    public void rpcByteArrayDataSource_To_Byte_Array() {
+        String sourceKey = "sourceKey";
+        String expectedString = "Example String";
+        byte[] expctedStingBytes = expectedString.getBytes();
+        ByteString inputByteString = ByteString.copyFrom(expctedStingBytes);
+
+        List<ByteString> input = new ArrayList<ByteString>();
+        input.add(inputByteString);
+
+        Builder a = CollectionBytes.newBuilder();
+        a.addAllBytes(input);
+
+        CollectionBytes typedDataCollectionBytes = a.build();
+
+        RpcCollectionByteArrayDataSource stringData = new RpcCollectionByteArrayDataSource(sourceKey, typedDataCollectionBytes);
+
+        Optional<BindingData> actualBindingData = stringData.computeByName(sourceKey, Byte[][].class);
+        BindingData actualArg = actualBindingData.orElseThrow(WrongMethodTypeException::new);
+        Byte[][] actualBytes = (Byte[][]) actualArg.getValue();
+        String actualString = new String(ArrayUtils.toPrimitive(actualBytes[0]));
+        assertEquals(actualString, expectedString);
+    }
+
+    @Test
+    public void rpcByteArrayDataSource_default_To_List_byte() {
+        String sourceKey = "sourceKey";
+        String expectedString = "Example String";
+        byte[] expctedStingBytes = expectedString.getBytes();
+        ByteString inputByteString = ByteString.copyFrom(expctedStingBytes);
+
+        List<ByteString> input = new ArrayList<ByteString>();
+        input.add(inputByteString);
+
+        Builder a = CollectionBytes.newBuilder();
+        a.addAllBytes(input);
+
+        CollectionBytes typedDataCollectionBytes = a.build();
+
+        RpcCollectionByteArrayDataSource stringData = new RpcCollectionByteArrayDataSource(sourceKey, typedDataCollectionBytes);
+
+        Optional<BindingData> actualBindingData = stringData.computeByName(sourceKey, String.class);
+        BindingData actualArg = actualBindingData.orElseThrow(WrongMethodTypeException::new);
+        List<byte[]> actualBytes = (List) actualArg.getValue();
+        String actualString = new String(actualBytes.get(0));
+        assertEquals(actualString, expectedString);
+    }
+
+    @Test
+    public void rpcByteArrayDataSource_To_List_byte() {
+        String sourceKey = "sourceKey";
+        String expectedString = "Example String";
+        byte[] expctedStingBytes = expectedString.getBytes();
+        ByteString inputByteString = ByteString.copyFrom(expctedStingBytes);
+
+        List<ByteString> input = new ArrayList<ByteString>();
+        input.add(inputByteString);
+
+        Builder a = CollectionBytes.newBuilder();
+        a.addAllBytes(input);
+
+        CollectionBytes typedDataCollectionBytes = a.build();
+
+        RpcCollectionByteArrayDataSource stringData = new RpcCollectionByteArrayDataSource(sourceKey, typedDataCollectionBytes);
+
+        Optional<BindingData> actualBindingData = stringData.computeByName(sourceKey, Utility.getActualType(byte[].class));
+        BindingData actualArg = actualBindingData.orElseThrow(WrongMethodTypeException::new);
+        List<byte[]> actualBytes = (List) actualArg.getValue();
+        String actualString = new String(actualBytes.get(0));
+        assertEquals(actualString, expectedString);
+    }
+
+    @Test
+    public void rpcByteArrayDataSource_To_List_Byte() {
+        String sourceKey = "sourceKey";
+        String expectedString = "Example String";
+        byte[] expctedStingBytes = expectedString.getBytes();
+        ByteString inputByteString = ByteString.copyFrom(expctedStingBytes);
+
+        List<ByteString> input = new ArrayList<ByteString>();
+        input.add(inputByteString);
+
+        Builder a = CollectionBytes.newBuilder();
+        a.addAllBytes(input);
+
+        CollectionBytes typedDataCollectionBytes = a.build();
+
+        RpcCollectionByteArrayDataSource stringData = new RpcCollectionByteArrayDataSource(sourceKey, typedDataCollectionBytes);
+
+        Optional<BindingData> actualBindingData = stringData.computeByName(sourceKey, Utility.getActualType(Byte[].class));
+        BindingData actualArg = actualBindingData.orElseThrow(WrongMethodTypeException::new);
+        List<Byte[]> actualBytes = (List) actualArg.getValue();
+        String actualString = new String(ArrayUtils.toPrimitive(actualBytes.get(0)));
+        assertEquals(actualString, expectedString);
+    }
+
+    @Test
+    public void rpcByteArrayDataSource_No_Generic_To_List_byte() {
+        String sourceKey = "sourceKey";
+        String expectedString = "Example String";
+        byte[] expctedStingBytes = expectedString.getBytes();
+        ByteString inputByteString = ByteString.copyFrom(expctedStingBytes);
+
+        List<ByteString> input = new ArrayList<ByteString>();
+        input.add(inputByteString);
+
+        Builder a = CollectionBytes.newBuilder();
+        a.addAllBytes(input);
+
+        CollectionBytes typedDataCollectionBytes = a.build();
+
+        RpcCollectionByteArrayDataSource stringData = new RpcCollectionByteArrayDataSource(sourceKey, typedDataCollectionBytes);
+
+        Optional<BindingData> actualBindingData = stringData.computeByName(sourceKey, List.class);
+        BindingData actualArg = actualBindingData.orElseThrow(WrongMethodTypeException::new);
+        List<byte[]> actualBytes = (List) actualArg.getValue();
+        String actualString = new String(actualBytes.get(0));
+        assertEquals(actualString, expectedString);
+    }
+
+
+
+
+}
diff --git a/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionDoubleDataSourceTest.java b/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionDoubleDataSourceTest.java
new file mode 100644
index 0000000..e18b4a4
--- /dev/null
+++ b/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionDoubleDataSourceTest.java
@@ -0,0 +1,127 @@
+
+package com.microsoft.azure.functions.worker.binding.tests;
+
+import com.microsoft.azure.functions.rpc.messages.CollectionDouble;
+import com.microsoft.azure.functions.worker.binding.BindingData;
+import com.microsoft.azure.functions.worker.binding.RpcCollectionDoubleDataSource;
+import org.junit.Test;
+
+import java.lang.invoke.WrongMethodTypeException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+import static org.junit.Assert.assertEquals;
+
+public class RpcCollectionDoubleDataSourceTest {
+    @Test
+    public void rpcCollectionDoubleDataSource_To_Double_Object_Array() {
+        String sourceKey = "sourceKey";
+        Double expectedDouble = 1.1;
+
+        List<Double> input = new ArrayList<Double>();
+        input.add(expectedDouble);
+
+        CollectionDouble.Builder a = CollectionDouble.newBuilder();
+        a.addAllDouble(input);
+
+        CollectionDouble typedDataCollectionDouble = a.build();
+
+        RpcCollectionDoubleDataSource data = new RpcCollectionDoubleDataSource(sourceKey, typedDataCollectionDouble);
+
+        Optional<BindingData> actualBindingData = data.computeByName(sourceKey, Double[].class);
+        BindingData actualArg = actualBindingData.orElseThrow(WrongMethodTypeException::new);
+        Double[] actualDoublegArray = (Double[]) actualArg.getValue();
+        Double actualDouble = actualDoublegArray[0];
+        assertEquals(actualDouble, expectedDouble);
+    }
+
+    @Test
+    public void rpcCollectionDoubleDataSource_To_double_Array() {
+        String sourceKey = "sourceKey";
+        double expectedDouble = 1.1;
+
+        List<Double> input = new ArrayList<Double>();
+        input.add(expectedDouble);
+
+        CollectionDouble.Builder a = CollectionDouble.newBuilder();
+        a.addAllDouble(input);
+
+        CollectionDouble typedDataCollectionDouble = a.build();
+
+        RpcCollectionDoubleDataSource data = new RpcCollectionDoubleDataSource(sourceKey, typedDataCollectionDouble);
+
+        Optional<BindingData> actualBindingData = data.computeByName(sourceKey, double[].class);
+        BindingData actualArg = actualBindingData.orElseThrow(WrongMethodTypeException::new);
+        double[] actualDoubleArray = (double[]) actualArg.getValue();
+        double actualDouble = actualDoubleArray[0];
+        assertEquals("" + actualDouble, "" + expectedDouble);
+    }
+
+    @Test
+    public void rpcCollectionDoubleDataSource_default_To_List_Double() {
+        String sourceKey = "sourceKey";
+        Double expectedDouble = 1.1;
+
+        List<Double> input = new ArrayList<Double>();
+        input.add(expectedDouble);
+
+        CollectionDouble.Builder a = CollectionDouble.newBuilder();
+        a.addAllDouble(input);
+
+        CollectionDouble typedDataCollectionDouble = a.build();
+
+        RpcCollectionDoubleDataSource data = new RpcCollectionDoubleDataSource(sourceKey, typedDataCollectionDouble);
+
+        Optional<BindingData> actualBindingData = data.computeByName(sourceKey, String.class);
+        BindingData actualArg = actualBindingData.orElseThrow(WrongMethodTypeException::new);
+        List<Double> actualDoubleList  = (List) actualArg.getValue();
+        Double actualLong = actualDoubleList.get(0);
+        assertEquals(actualLong, expectedDouble);
+    }
+
+    @Test
+    public void rpcCollectionDoubleDataSource_To_List_Double() {
+        String sourceKey = "sourceKey";
+        Double expectedDouble = 1.1;
+
+        List<Double> input = new ArrayList<Double>();
+        input.add(expectedDouble);
+
+        CollectionDouble.Builder a = CollectionDouble.newBuilder();
+        a.addAllDouble(input);
+
+        CollectionDouble typedDataCollectionDouble = a.build();
+
+        RpcCollectionDoubleDataSource data = new RpcCollectionDoubleDataSource(sourceKey, typedDataCollectionDouble);
+
+        Optional<BindingData> actualBindingData = data.computeByName(sourceKey, Utility.getActualType(Double.class));
+        BindingData actualArg = actualBindingData.orElseThrow(WrongMethodTypeException::new);
+        List<Double> actualDoubleList  = (List) actualArg.getValue();
+        Double actualLong = actualDoubleList.get(0);
+        assertEquals(actualLong, expectedDouble);
+    }
+
+    @Test
+    public void rpcCollectionDoubleDataSource_No_Generic_To_List_Long() {
+        String sourceKey = "sourceKey";
+        Double expectedDouble = 1.1;
+
+        List<Double> input = new ArrayList<Double>();
+        input.add(expectedDouble);
+
+        CollectionDouble.Builder a = CollectionDouble.newBuilder();
+        a.addAllDouble(input);
+
+        CollectionDouble typedDataCollectionDouble = a.build();
+
+        RpcCollectionDoubleDataSource data = new RpcCollectionDoubleDataSource(sourceKey, typedDataCollectionDouble);
+
+        Optional<BindingData> actualBindingData = data.computeByName(sourceKey, List.class);
+        BindingData actualArg = actualBindingData.orElseThrow(WrongMethodTypeException::new);
+        List<Double> actualDoubleList  = (List) actualArg.getValue();
+        Double actualLong = actualDoubleList.get(0);
+        assertEquals(actualLong, expectedDouble);
+    }
+}
+
diff --git a/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionLongDataSourceTest.java b/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionLongDataSourceTest.java
new file mode 100644
index 0000000..a16d547
--- /dev/null
+++ b/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionLongDataSourceTest.java
@@ -0,0 +1,128 @@
+package com.microsoft.azure.functions.worker.binding.tests;
+
+import com.microsoft.azure.functions.rpc.messages.CollectionSInt64;
+import com.microsoft.azure.functions.rpc.messages.CollectionSInt64.Builder;
+import com.microsoft.azure.functions.worker.binding.BindingData;
+import com.microsoft.azure.functions.worker.binding.RpcCollectionLongDataSource;
+import org.junit.Test;
+
+import java.lang.invoke.WrongMethodTypeException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+import static org.junit.Assert.assertEquals;
+
+public class  RpcCollectionLongDataSourceTest{
+    @Test
+    public void rpcCollectionSInt64DataSource_To_Long_Object_Array() {
+        String sourceKey = "sourceKey";
+        Long expectedLong = 1L;
+
+        List<Long> input = new ArrayList<Long>();
+        input.add(expectedLong);
+
+        Builder a = CollectionSInt64.newBuilder();
+        a.addAllSint64(input);
+
+        CollectionSInt64 typedDataCollectionLong = a.build();
+
+        RpcCollectionLongDataSource stringData = new RpcCollectionLongDataSource(sourceKey, typedDataCollectionLong);
+
+        Optional<BindingData> actualBindingData = stringData.computeByName(sourceKey, Long[].class);
+        BindingData actualArg = actualBindingData.orElseThrow(WrongMethodTypeException::new);
+        Long[] actualLongArray = (Long[]) actualArg.getValue();
+        Long actualLong = actualLongArray[0];
+        assertEquals(actualLong, expectedLong);
+    }
+
+    @Test
+    public void rpcCollectionDoubleDataSource_To_long_Array() {
+        String sourceKey = "sourceKey";
+        Long expectedLong = 1L;
+
+        List<Long> input = new ArrayList<Long>();
+        input.add(expectedLong);
+
+        Builder a = CollectionSInt64.newBuilder();
+        a.addAllSint64(input);
+
+        CollectionSInt64 typedDataCollectionLong = a.build();
+
+        RpcCollectionLongDataSource stringData = new RpcCollectionLongDataSource(sourceKey, typedDataCollectionLong);
+
+        Optional<BindingData> actualBindingData = stringData.computeByName(sourceKey, long[].class);
+        BindingData actualArg = actualBindingData.orElseThrow(WrongMethodTypeException::new);
+        long[] actualLongArray = (long[]) actualArg.getValue();
+        Long actualLong = actualLongArray[0];
+        assertEquals(actualLong, expectedLong);
+    }
+
+    @Test
+    public void rpcCollectionSInt64DataSource_default_To_List_Long() {
+        String sourceKey = "sourceKey";
+        Long expectedLong = 1L;
+
+        List<Long> input = new ArrayList<Long>();
+        input.add(expectedLong);
+
+        Builder a = CollectionSInt64.newBuilder();
+        a.addAllSint64(input);
+
+        CollectionSInt64 typedDataCollectionLong = a.build();
+
+        RpcCollectionLongDataSource stringData = new RpcCollectionLongDataSource(sourceKey, typedDataCollectionLong);
+
+        Optional<BindingData> actualBindingData = stringData.computeByName(sourceKey, String.class);
+        BindingData actualArg = actualBindingData.orElseThrow(WrongMethodTypeException::new);
+        List<Long> actualLongList  = (List) actualArg.getValue();
+        Long actualLong = actualLongList.get(0);
+        assertEquals(actualLong, expectedLong);
+    }
+
+    @Test
+    public void rpcCollectionSInt64DataSource_To_List_Long() {
+        String sourceKey = "sourceKey";
+        Long expectedLong = 1L;
+
+        List<Long> input = new ArrayList<Long>();
+        input.add(expectedLong);
+
+        Builder a = CollectionSInt64.newBuilder();
+        a.addAllSint64(input);
+
+        CollectionSInt64 typedDataCollectionLong = a.build();
+
+        RpcCollectionLongDataSource stringData = new RpcCollectionLongDataSource(sourceKey, typedDataCollectionLong);
+
+
+        Optional<BindingData> actualBindingData = stringData.computeByName(sourceKey, Utility.getActualType(Long.class));
+        BindingData actualArg = actualBindingData.orElseThrow(WrongMethodTypeException::new);
+        List<Long> actualLongList  = (List) actualArg.getValue();
+        Long actualLong = actualLongList.get(0);
+        assertEquals(actualLong, expectedLong);
+    }
+
+    @Test
+    public void rpcCollectionSInt64DataSource_No_Generic_To_List_Long() {
+        String sourceKey = "sourceKey";
+        Long expectedLong = 1L;
+
+        List<Long> input = new ArrayList<Long>();
+        input.add(expectedLong);
+
+        Builder a = CollectionSInt64.newBuilder();
+        a.addAllSint64(input);
+
+        CollectionSInt64 typedDataCollectionLong = a.build();
+
+        RpcCollectionLongDataSource stringData = new RpcCollectionLongDataSource(sourceKey, typedDataCollectionLong);
+
+
+        Optional<BindingData> actualBindingData = stringData.computeByName(sourceKey, List.class);
+        BindingData actualArg = actualBindingData.orElseThrow(WrongMethodTypeException::new);
+        List<Long> actualLongList  = (List) actualArg.getValue();
+        Long actualLong = actualLongList.get(0);
+        assertEquals(actualLong, expectedLong);
+    }
+}
diff --git a/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionStringDataSourceTest.java b/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionStringDataSourceTest.java
new file mode 100644
index 0000000..17a6e07
--- /dev/null
+++ b/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionStringDataSourceTest.java
@@ -0,0 +1,108 @@
+package com.microsoft.azure.functions.worker.binding.tests;
+
+import com.microsoft.azure.functions.rpc.messages.CollectionString.Builder;
+import com.microsoft.azure.functions.rpc.messages.CollectionString;
+import com.microsoft.azure.functions.worker.binding.BindingData;
+import com.microsoft.azure.functions.worker.binding.RpcCollectionStringDataSource;
+import org.junit.Test;
+
+import java.lang.invoke.WrongMethodTypeException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+import static org.junit.Assert.assertEquals;
+
+public class RpcCollectionStringDataSourceTest {
+    @Test
+    public void rpcStringCollectionDataSource_To_string_Array() {
+        String sourceKey = "sourceKey";
+        String expectedString = "Example String";
+
+        List<String> input = new ArrayList<String>();
+        input.add(expectedString);
+
+        Builder a = CollectionString.newBuilder();
+        a.addAllString(input);
+
+        CollectionString typedDataCollectionString = a.build();
+
+        RpcCollectionStringDataSource stringData = new RpcCollectionStringDataSource(sourceKey, typedDataCollectionString);
+
+        Optional<BindingData> actualBindingData = stringData.computeByName(sourceKey, String[].class);
+        BindingData actualArg = actualBindingData.orElseThrow(WrongMethodTypeException::new);
+        String[] actualStringArray = (String[]) actualArg.getValue();
+        String actualString = actualStringArray[0];
+        assertEquals(actualString, expectedString);
+    }
+
+    @Test
+    public void rpcStringCollectionDataSource_default_To_List_string() {
+        String sourceKey = "sourceKey";
+        String expectedString = "Example String";
+
+        List<String> input = new ArrayList<String>();
+        input.add(expectedString);
+
+        Builder a = CollectionString.newBuilder();
+        a.addAllString(input);
+
+        CollectionString typedDataCollectionString = a.build();
+
+        RpcCollectionStringDataSource stringData = new RpcCollectionStringDataSource(sourceKey, typedDataCollectionString);
+
+        Optional<BindingData> actualBindingData = stringData.computeByName(sourceKey, String.class);
+        BindingData actualArg = actualBindingData.orElseThrow(WrongMethodTypeException::new);
+        List<String> actualStringList  = (List) actualArg.getValue();
+        String actualString = actualStringList.get(0);
+        assertEquals(actualString, expectedString);
+    }
+
+    @Test
+    public void rpcStringCollectionDataSource_To_List_string() {
+        String sourceKey = "sourceKey";
+        String expectedString = "Example String";
+
+        List<String> input = new ArrayList<String>();
+        input.add(expectedString);
+
+        Builder a = CollectionString.newBuilder();
+        a.addAllString(input);
+
+        CollectionString typedDataCollectionString = a.build();
+
+        RpcCollectionStringDataSource stringData = new RpcCollectionStringDataSource(sourceKey, typedDataCollectionString);
+
+        Optional<BindingData> actualBindingData = stringData.computeByName(sourceKey, Utility.getActualType(String.class));
+        BindingData actualArg = actualBindingData.orElseThrow(WrongMethodTypeException::new);
+        List<String> actualStringList  = (List) actualArg.getValue();
+        String actualString = actualStringList.get(0);
+        assertEquals(actualString, expectedString);
+    }
+
+    @Test
+    public void rpcStringCollectionDataSource_No_Generic_To_List_String() {
+        String sourceKey = "sourceKey";
+        String expectedString = "Example String";
+
+        List<String> input = new ArrayList<String>();
+        input.add(expectedString);
+
+        Builder a = CollectionString.newBuilder();
+        a.addAllString(input);
+
+        CollectionString typedDataCollectionString = a.build();
+
+        RpcCollectionStringDataSource stringData = new RpcCollectionStringDataSource(sourceKey, typedDataCollectionString);
+
+        Optional<BindingData> actualBindingData = stringData.computeByName(sourceKey, List.class);
+        BindingData actualArg = actualBindingData.orElseThrow(WrongMethodTypeException::new);
+        List<String> actualStringList  = (List) actualArg.getValue();
+        String actualString = actualStringList.get(0);
+        assertEquals(actualString, expectedString);
+    }
+
+
+
+
+}
diff --git a/src/test/java/com/microsoft/azure/functions/worker/binding/tests/Utility.java b/src/test/java/com/microsoft/azure/functions/worker/binding/tests/Utility.java
new file mode 100644
index 0000000..703faee
--- /dev/null
+++ b/src/test/java/com/microsoft/azure/functions/worker/binding/tests/Utility.java
@@ -0,0 +1,12 @@
+package com.microsoft.azure.functions.worker.binding.tests;
+
+import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
+
+import java.lang.reflect.Type;
+import java.util.List;
+
+public class Utility {
+    public static Type getActualType(Class clazz) {
+        return ParameterizedTypeImpl.make(List.class, new Type[]{clazz}, null);
+    }
+}