Allow JSON to be Input from a File (#1175)

- Pass JSON files to parameters and annotations
- Refactor parameter and annotation handling
	- Use KeyValueArr data type to store annotations and parameters
- Refactor summaries for get commands
	- Use KeyValueArr data type to get annotations and parameters
- Refactor parameter and annotation tests
	- Order of params and annots are not guaranteed in Go map data structures
- Fixes: #426
diff --git a/tests/src/common/Wsk.scala b/tests/src/common/Wsk.scala
index ede51db..c125a71 100644
--- a/tests/src/common/Wsk.scala
+++ b/tests/src/common/Wsk.scala
@@ -225,6 +225,8 @@
         kind: Option[String] = None, // one of docker, copy, sequence or none for autoselect else an explicit type
         parameters: Map[String, JsValue] = Map(),
         annotations: Map[String, JsValue] = Map(),
+        parameterFile: Option[String] = None,
+        annotationFile: Option[String] = None,
         timeout: Option[Duration] = None,
         memory: Option[ByteSize] = None,
         logsize: Option[ByteSize] = None,
@@ -242,6 +244,8 @@
             } ++
             { parameters flatMap { p => Seq("-p", p._1, p._2.compactPrint) } } ++
             { annotations flatMap { p => Seq("-a", p._1, p._2.compactPrint) } } ++
+            { parameterFile map { pf => Seq("-P", pf) } getOrElse Seq() } ++
+            { annotationFile map { af => Seq("-A", af) } getOrElse Seq() } ++
             { timeout map { t => Seq("-t", t.toMillis.toString) } getOrElse Seq() } ++
             { memory map { m => Seq("-m", m.toMB.toString) } getOrElse Seq() } ++
             { logsize map { l => Seq("-l", l.toMB.toString) } getOrElse Seq() } ++
@@ -259,12 +263,14 @@
     def invoke(
         name: String,
         parameters: Map[String, JsValue] = Map(),
+        parameterFile: Option[String] = None,
         blocking: Boolean = false,
         result: Boolean = false,
         expectedExitCode: Int = SUCCESS_EXIT)(
             implicit wp: WskProps): RunResult = {
         val params = Seq(noun, "invoke", "--auth", wp.authKey, fqn(name)) ++
             { parameters flatMap { p => Seq("-p", p._1, p._2.compactPrint) } } ++
+            { parameterFile map { pf => Seq("-P", pf) } getOrElse Seq() } ++
             { if (blocking) Seq("--blocking") else Seq() } ++
             { if (result) Seq("--result") else Seq() }
         cli(wp.overrides ++ params, expectedExitCode)
@@ -290,6 +296,8 @@
         name: String,
         parameters: Map[String, JsValue] = Map(),
         annotations: Map[String, JsValue] = Map(),
+        parameterFile: Option[String] = None,
+        annotationFile: Option[String] = None,
         feed: Option[String] = None,
         shared: Option[Boolean] = None,
         update: Boolean = false,
@@ -299,6 +307,8 @@
             { feed map { f => Seq("--feed", fqn(f)) } getOrElse Seq() } ++
             { parameters flatMap { p => Seq("-p", p._1, p._2.compactPrint) } } ++
             { annotations flatMap { p => Seq("-a", p._1, p._2.compactPrint) } } ++
+            { parameterFile map { pf => Seq("-P", pf) } getOrElse Seq() } ++
+            { annotationFile map { af => Seq("-A", af) } getOrElse Seq() } ++
             { shared map { s => Seq("--shared", if (s) "yes" else "no") } getOrElse Seq() }
         cli(wp.overrides ++ params, expectedExitCode)
     }
@@ -313,10 +323,12 @@
     def fire(
         name: String,
         parameters: Map[String, JsValue] = Map(),
+        parameterFile: Option[String] = None,
         expectedExitCode: Int = SUCCESS_EXIT)(
             implicit wp: WskProps): RunResult = {
         val params = Seq(noun, "fire", "--auth", wp.authKey, fqn(name)) ++
-            { parameters flatMap { p => Seq("-p", p._1, p._2.compactPrint) } }
+            { parameters flatMap { p => Seq("-p", p._1, p._2.compactPrint) } } ++
+            { parameterFile map { pf => Seq("-P", pf) } getOrElse Seq() }
         cli(wp.overrides ++ params, expectedExitCode)
     }
 }
@@ -650,6 +662,8 @@
         name: String,
         parameters: Map[String, JsValue] = Map(),
         annotations: Map[String, JsValue] = Map(),
+        parameterFile: Option[String] = None,
+        annotationFile: Option[String] = None,
         shared: Option[Boolean] = None,
         update: Boolean = false,
         expectedExitCode: Int = SUCCESS_EXIT)(
@@ -657,6 +671,8 @@
         val params = Seq(noun, if (!update) "create" else "update", "--auth", wp.authKey, fqn(name)) ++
             { parameters flatMap { p => Seq("-p", p._1, p._2.compactPrint) } } ++
             { annotations flatMap { p => Seq("-a", p._1, p._2.compactPrint) } } ++
+            { parameterFile map { pf => Seq("-P", pf) } getOrElse Seq() } ++
+            { annotationFile map { af => Seq("-A", af) } getOrElse Seq() } ++
             { shared map { s => Seq("--shared", if (s) "yes" else "no") } getOrElse Seq() }
         cli(wp.overrides ++ params, expectedExitCode)
     }
diff --git a/tests/src/system/basic/WskBasicTests.scala b/tests/src/system/basic/WskBasicTests.scala
index 36886e9..24492e9 100644
--- a/tests/src/system/basic/WskBasicTests.scala
+++ b/tests/src/system/basic/WskBasicTests.scala
@@ -238,6 +238,26 @@
             }
     }
 
+    it should "create, and invoke an action using a parameter file" in withAssetCleaner(wskprops) {
+        val name = "paramFileAction"
+        val file = Some(TestUtils.getTestActionFilename("argCheck.js"))
+        val argInput = Some(TestUtils.getTestActionFilename("validInput2.json"))
+
+        (wp, assetHelper) =>
+            assetHelper.withCleaner(wsk.action, name) {
+                (action, _) => action.create(name, file)
+            }
+
+            val expectedOutput = JsObject(
+                "payload" -> JsString("test")
+            )
+            val run = wsk.action.invoke(name, parameterFile = argInput)
+            withActivation(wsk.activation, run) {
+                activation =>
+                    activation.response.result shouldBe Some(expectedOutput)
+            }
+    }
+
     /**
      * Tests creating an action from a malformed js file. This should fail in
      * some way - preferably when trying to create the action. If not, then
@@ -394,6 +414,27 @@
             res.stdout should include regex(s"ok: created trigger $name")
     }
 
+    it should "create, and fire a trigger using a parameter file" in withAssetCleaner(wskprops) {
+        val name = "paramFileTrigger"
+        val file = Some(TestUtils.getTestActionFilename("argCheck.js"))
+        val argInput = Some(TestUtils.getTestActionFilename("validInput2.json"))
+
+        (wp, assetHelper) =>
+            assetHelper.withCleaner(wsk.trigger, name) {
+                (trigger, _) =>
+                    trigger.create(name)
+            }
+
+            val expectedOutput = JsObject(
+                    "payload" -> JsString("test")
+            )
+            val run = wsk.trigger.fire(name, parameterFile = argInput)
+            withActivation(wsk.activation, run) {
+                activation =>
+                    activation.response.result shouldBe Some(expectedOutput)
+            }
+    }
+
     behavior of "Wsk Rule CLI"
 
     it should "create rule, get rule, update rule and list rule" in withAssetCleaner(wskprops) {
diff --git a/tests/src/whisk/core/cli/test/JsonArgsForTests.scala b/tests/src/whisk/core/cli/test/JsonArgsForTests.scala
index e2cf23b..4e41b85 100644
--- a/tests/src/whisk/core/cli/test/JsonArgsForTests.scala
+++ b/tests/src/whisk/core/cli/test/JsonArgsForTests.scala
@@ -24,42 +24,86 @@
 
 object JsonArgsForTests {
 
-    def getEscapedJSONTestArgInput(parameters: Boolean = true) = Seq(
-        if (parameters) "-p" else "-a",
-        "\"key\"with\\escapes",                 // key:   key"with\escapes (will be converted to JSON string "key\"with\\escapes")
-        "{\"valid\": \"JSON\"}",                // value: {"valid":"JSON"}
-        if (parameters) "-p" else "-a",
-        "another\"escape\"",                    // key:   another"escape" (will be converted to JSON string "another\"escape\"")
-        "{\"valid\": \"\\nJ\\rO\\tS\\bN\\f\"}", // value: {"valid":"\nJ\rO\tS\bN\f"}  JSON strings can escape: \n, \r, \t, \b, \f
-        // NOTE: When uncommentting these tests, be sure to include the expected response in getEscapedJSONTestArgOutput()
-        //        if (parameters) "-p" else "-a",
-        //        "escape\\again",                        // key:   escape\again (will be converted to JSON string "escape\\again")
-        //        "{\"valid\": \"JS\\u2312ON\"}",         // value: {"valid":"JS\u2312ON"}   JSON strings can have escaped 4 digit unicode
-        //        if (parameters) "-p" else "-a",
-        //        "mykey",                                // key:   mykey  (will be converted to JSON string "key")
-        //        "{\"valid\": \"JS\\/ON\"}",             // value: {"valid":"JS\/ON"}   JSON strings can have escaped \/
-        if (parameters) "-p" else "-a",
-        "key1",                                 // key:   key  (will be converted to JSON string "key")
-        "{\"nonascii\": \"日本語\"}",           // value: {"nonascii":"日本語"}   JSON strings can have non-ascii
-        if (parameters) "-p" else "-a",
-        "key2",                                 // key:   key  (will be converted to JSON string "key")
-        "{\"valid\": \"J\\\\SO\\\"N\"}"         // value: {"valid":"J\\SO\"N"}   JSON strings can have escaped \\ and \"
+    def getInvalidJSONInput = Seq(
+        "{\"invalid1\": }",
+        "{\"invalid2\": bogus}",
+        "{\"invalid1\": \"aKey\"",
+        "invalid \"string\"",
+        "{\"invalid1\": [1, 2, \"invalid\"\"arr\"]}"
+    )
+
+    def getJSONFileOutput() = JsArray(
+        JsObject(
+            "key" -> JsString("a key"),
+            "value" -> JsString("a value")
+        ),
+        JsObject(
+            "key" -> JsString("a bool"),
+            "value" -> JsBoolean(true)
+        ),
+        JsObject(
+            "key" -> JsString("objKey"),
+            "value" -> JsObject(
+                "b" -> JsString("c")
+            )
+        ),
+        JsObject(
+            "key" -> JsString("objKey2"),
+            "value" -> JsObject(
+                "another object" -> JsObject(
+                    "some string" -> JsString("1111")
+                )
+            )
+        ),
+        JsObject(
+            "key" -> JsString("objKey3"),
+            "value" -> JsObject(
+                "json object" -> JsObject(
+                    "some int" -> JsNumber(1111)
+                )
+            )
+        ),
+        JsObject(
+            "key" -> JsString("a number arr"),
+            "value" -> JsArray(
+                JsNumber(1), JsNumber(2), JsNumber(3)
+            )
+        ),
+        JsObject(
+            "key" -> JsString("a string arr"),
+            "value" -> JsArray(
+                JsString("1"), JsString("2"), JsString("3")
+            )
+        ),
+        JsObject(
+            "key" -> JsString("a bool arr"),
+            "value" -> JsArray(
+                JsBoolean(true), JsBoolean(false), JsBoolean(true)
+            )
+        ),
+        JsObject(
+            "key" -> JsString("strThatLooksLikeJSON"),
+            "value" -> JsString("{\"someKey\": \"someValue\"}")
+        )
+    )
+
+    def getEscapedJSONTestArgInput() = Map(
+        "key1" -> JsObject(
+            "nonascii" -> JsString("日本語")
+        ),
+        "key2" -> JsObject(
+            "valid" -> JsString("J\\SO\"N")
+        ),
+        "\"key\"with\\escapes" -> JsObject(
+            "valid" -> JsString("JSON")
+        ),
+        "another\"escape\"" -> JsObject(
+            "valid" -> JsString("\\nJ\\rO\\tS\\bN\\f")
+        )
     )
 
     def getEscapedJSONTestArgOutput() = JsArray(
         JsObject(
-            "key" -> JsString("\"key\"with\\escapes"),
-            "value" -> JsObject(
-                "valid" -> JsString("JSON")
-            )
-        ),
-        JsObject(
-            "key" -> JsString("another\"escape\""),
-            "value" -> JsObject(
-                "valid" -> JsString("\nJ\rO\tS\bN\f")
-            )
-        ),
-        JsObject(
             "key" -> JsString("key1"),
             "value" -> JsObject(
                 "nonascii" -> JsString("日本語")
@@ -70,6 +114,18 @@
             "value" -> JsObject(
                 "valid" -> JsString("J\\SO\"N")
             )
+        ),
+        JsObject(
+            "key" -> JsString("\"key\"with\\escapes"),
+            "value" -> JsObject(
+                "valid" -> JsString("JSON")
+            )
+        ),
+        JsObject(
+            "key" -> JsString("another\"escape\""),
+            "value" -> JsObject(
+                "valid" -> JsString("\\nJ\\rO\\tS\\bN\\f")
+            )
         )
     )
 
diff --git a/tests/src/whisk/core/cli/test/WskBasicUsageTests.scala b/tests/src/whisk/core/cli/test/WskBasicUsageTests.scala
index 5e6f5f7..f2aa959 100644
--- a/tests/src/whisk/core/cli/test/WskBasicUsageTests.scala
+++ b/tests/src/whisk/core/cli/test/WskBasicUsageTests.scala
@@ -261,68 +261,76 @@
             wsk.action.create("updateMissingFile", Some("notfound"), update = true, expectedExitCode = MISUSE_EXIT)
     }
 
-    it should "create, and get an action to verify annotation parsing" in withAssetCleaner(wskprops) {
+    it should "create, and get an action to verify parameter and annotation parsing" in withAssetCleaner(wskprops) {
         (wp, assetHelper) =>
             val name = "actionAnnotations"
-
             val file = Some(TestUtils.getTestActionFilename("hello.js"))
+
             assetHelper.withCleaner(wsk.action, name) {
                 (action, _) =>
-                    action.create(name, file, annotations = getValidJSONTestArgInput)
+                    action.create(name, file, annotations = getValidJSONTestArgInput,
+                        parameters = getValidJSONTestArgInput)
             }
 
             val stdout = wsk.action.get(name).stdout
             assert(stdout.startsWith(s"ok: got action $name\n"))
 
-            wsk.parseJsonString(stdout).fields("annotations") shouldBe getValidJSONTestArgOutput
+            val receivedParams = wsk.parseJsonString(stdout).fields("parameters").convertTo[JsArray].elements
+            val receivedAnnots = wsk.parseJsonString(stdout).fields("annotations").convertTo[JsArray].elements
+            val escapedJSONArr = getValidJSONTestArgOutput.convertTo[JsArray].elements
+
+            for (expectedItem <- escapedJSONArr) {
+                receivedParams should contain(expectedItem)
+                receivedAnnots should contain(expectedItem)
+            }
     }
 
-    it should "create, and get an action to verify parameter parsing" in withAssetCleaner(wskprops) {
+    it should "create, and get an action to verify file parameter and annotation parsing" in withAssetCleaner(wskprops) {
         (wp, assetHelper) =>
-            val name = "actionParameters"
-
+            val name = "actionAnnotAndParamParsing"
             val file = Some(TestUtils.getTestActionFilename("hello.js"))
+            val argInput = Some(TestUtils.getTestActionFilename("validInput1.json"))
+
             assetHelper.withCleaner(wsk.action, name) {
                 (action, _) =>
-                    action.create(name, file, parameters = getValidJSONTestArgInput)
+                    action.create(name, file, annotationFile = argInput, parameterFile = argInput)
             }
 
             val stdout = wsk.action.get(name).stdout
             assert(stdout.startsWith(s"ok: got action $name\n"))
 
-            wsk.parseJsonString(stdout).fields("parameters") shouldBe getValidJSONTestArgOutput
+            val receivedParams = wsk.parseJsonString(stdout).fields("parameters").convertTo[JsArray].elements
+            val receivedAnnots = wsk.parseJsonString(stdout).fields("annotations").convertTo[JsArray].elements
+            val escapedJSONArr = getJSONFileOutput.convertTo[JsArray].elements
+
+            for (expectedItem <- escapedJSONArr) {
+                receivedParams should contain(expectedItem)
+                receivedAnnots should contain(expectedItem)
+            }
     }
 
-    it should "create an action with the proper parameter escapes" in withAssetCleaner(wskprops) {
+    it should "create an action with the proper parameter and annotation escapes" in withAssetCleaner(wskprops) {
         (wp, assetHelper) =>
-            val name = "actionName"
-            val file = TestUtils.getTestActionFilename("hello.js")
+            val name = "actionEscapes"
+            val file = Some(TestUtils.getTestActionFilename("hello.js"))
+
             assetHelper.withCleaner(wsk.action, name) {
                 (action, _) =>
-                    wsk.cli(wskprops.overrides ++ Seq("action", "create", wsk.action.fqn(name), file, "--auth", wp.authKey) ++
-                        getEscapedJSONTestArgInput())
+                    action.create(name, file, parameters = getEscapedJSONTestArgInput,
+                        annotations = getEscapedJSONTestArgInput)
             }
 
             val stdout = wsk.action.get(name).stdout
             assert(stdout.startsWith(s"ok: got action $name\n"))
 
-            wsk.parseJsonString(stdout).fields("parameters") shouldBe getEscapedJSONTestArgOutput
-    }
+            val receivedParams = wsk.parseJsonString(stdout).fields("parameters").convertTo[JsArray].elements
+            val receivedAnnots = wsk.parseJsonString(stdout).fields("annotations").convertTo[JsArray].elements
+            val escapedJSONArr = getEscapedJSONTestArgOutput.convertTo[JsArray].elements
 
-    it should "create an action with the proper annotation escapes" in withAssetCleaner(wskprops) {
-        (wp, assetHelper) =>
-            val name = "actionName"
-            val file = TestUtils.getTestActionFilename("hello.js")
-            assetHelper.withCleaner(wsk.action, name) {
-                (action, _) =>
-                    wsk.cli(wskprops.overrides ++ Seq("action", "create", wsk.action.fqn(name), file, "--auth", wp.authKey) ++
-                        getEscapedJSONTestArgInput(false))
+            for (expectedItem <- escapedJSONArr) {
+                receivedParams should contain(expectedItem)
+                receivedAnnots should contain(expectedItem)
             }
-
-            val stdout = wsk.action.get(name).stdout
-            assert(stdout.startsWith(s"ok: got action $name\n"))
-
-            wsk.parseJsonString(stdout).fields("annotations") shouldBe getEscapedJSONTestArgOutput
     }
 
     it should "invoke an action that exits during init and get appropriate error" in withAssetCleaner(wskprops) {
@@ -443,96 +451,121 @@
 
     behavior of "Wsk packages"
 
-    it should "create, and get a package to verify annotation parsing" in withAssetCleaner(wskprops) {
+    it should "create, and get a package to verify parameter and annotation parsing" in withAssetCleaner(wskprops) {
         (wp, assetHelper) =>
-            val name = "packageAnnotations"
+            val name = "packageAnnotAndParamParsing"
 
             assetHelper.withCleaner(wsk.pkg, name) {
                 (pkg, _) =>
-                    pkg.create(name, annotations = getValidJSONTestArgInput)
+                    pkg.create(name, annotations = getValidJSONTestArgInput, parameters = getValidJSONTestArgInput)
             }
 
             val stdout = wsk.pkg.get(name).stdout
             assert(stdout.startsWith(s"ok: got package $name\n"))
 
-            wsk.parseJsonString(stdout).fields("annotations") shouldBe getValidJSONTestArgOutput
+            val receivedParams = wsk.parseJsonString(stdout).fields("parameters").convertTo[JsArray].elements
+            val receivedAnnots = wsk.parseJsonString(stdout).fields("annotations").convertTo[JsArray].elements
+            val escapedJSONArr = getValidJSONTestArgOutput.convertTo[JsArray].elements
+
+            for (expectedItem <- escapedJSONArr) {
+                receivedParams should contain(expectedItem)
+                receivedAnnots should contain(expectedItem)
+            }
     }
 
-    it should "create, and get a package to verify parameter parsing" in withAssetCleaner(wskprops) {
+    it should "create, and get a package to verify file parameter and annotation parsing" in withAssetCleaner(wskprops) {
         (wp, assetHelper) =>
-            val name = "packageParameters"
+            val name = "packageAnnotAndParamFileParsing"
+            val file = Some(TestUtils.getTestActionFilename("hello.js"))
+            val argInput = Some(TestUtils.getTestActionFilename("validInput1.json"))
 
             assetHelper.withCleaner(wsk.pkg, name) {
                 (pkg, _) =>
-                    pkg.create(name, parameters = getValidJSONTestArgInput)
+                    pkg.create(name, annotationFile = argInput, parameterFile = argInput)
             }
 
             val stdout = wsk.pkg.get(name).stdout
             assert(stdout.startsWith(s"ok: got package $name\n"))
 
-            wsk.parseJsonString(stdout).fields("parameters") shouldBe getValidJSONTestArgOutput
+            val receivedParams = wsk.parseJsonString(stdout).fields("parameters").convertTo[JsArray].elements
+            val receivedAnnots = wsk.parseJsonString(stdout).fields("annotations").convertTo[JsArray].elements
+            val escapedJSONArr = getJSONFileOutput.convertTo[JsArray].elements
+
+            for (expectedItem <- escapedJSONArr) {
+                receivedParams should contain(expectedItem)
+                receivedAnnots should contain(expectedItem)
+            }
     }
 
-    it should "create a package with the proper parameter escapes" in withAssetCleaner(wskprops) {
+    it should "create a package with the proper parameter and annotation escapes" in withAssetCleaner(wskprops) {
         (wp, assetHelper) =>
-            val name = "packageName"
+            val name = "packageEscapses"
+
             assetHelper.withCleaner(wsk.pkg, name) {
                 (pkg, _) =>
-                    wsk.cli(wskprops.overrides ++ Seq("package", "create", wsk.pkg.fqn(name), "--auth", wp.authKey) ++
-                        getEscapedJSONTestArgInput())
+                    pkg.create(name, parameters = getEscapedJSONTestArgInput,
+                        annotations = getEscapedJSONTestArgInput)
             }
 
             val stdout = wsk.pkg.get(name).stdout
             assert(stdout.startsWith(s"ok: got package $name\n"))
 
-            wsk.parseJsonString(stdout).fields("parameters") shouldBe getEscapedJSONTestArgOutput
-    }
+            val receivedParams = wsk.parseJsonString(stdout).fields("parameters").convertTo[JsArray].elements
+            val receivedAnnots = wsk.parseJsonString(stdout).fields("annotations").convertTo[JsArray].elements
+            val escapedJSONArr = getEscapedJSONTestArgOutput.convertTo[JsArray].elements
 
-    it should "create an package with the proper annotation escapes" in withAssetCleaner(wskprops) {
-        (wp, assetHelper) =>
-            val name = "packageName"
-            assetHelper.withCleaner(wsk.pkg, name) {
-                (pkg, _) =>
-                    wsk.cli(wskprops.overrides ++ Seq("package", "create", wsk.pkg.fqn(name), "--auth", wp.authKey) ++
-                        getEscapedJSONTestArgInput(false))
+            for (expectedItem <- escapedJSONArr) {
+                receivedParams should contain(expectedItem)
+                receivedAnnots should contain(expectedItem)
             }
-
-            val stdout = wsk.pkg.get(name).stdout
-            assert(stdout.startsWith(s"ok: got package $name\n"))
-
-            wsk.parseJsonString(stdout).fields("annotations") shouldBe getEscapedJSONTestArgOutput
     }
 
     behavior of "Wsk triggers"
 
-    it should "create, and get a trigger to verify annotation parsing" in withAssetCleaner(wskprops) {
+    it should "create, and get a trigger to verify parameter and annotation parsing" in withAssetCleaner(wskprops) {
         (wp, assetHelper) =>
-            val name = "triggerAnnotations"
+            val name = "triggerAnnotAndParamParsing"
 
             assetHelper.withCleaner(wsk.trigger, name) {
                 (trigger, _) =>
-                    trigger.create(name, annotations = getValidJSONTestArgInput)
+                    trigger.create(name, annotations = getValidJSONTestArgInput, parameters = getValidJSONTestArgInput)
             }
 
             val stdout = wsk.trigger.get(name).stdout
             assert(stdout.startsWith(s"ok: got trigger $name\n"))
 
-            wsk.parseJsonString(stdout).fields("annotations") shouldBe getValidJSONTestArgOutput
+            val receivedParams = wsk.parseJsonString(stdout).fields("parameters").convertTo[JsArray].elements
+            val receivedAnnots = wsk.parseJsonString(stdout).fields("annotations").convertTo[JsArray].elements
+            val escapedJSONArr = getValidJSONTestArgOutput.convertTo[JsArray].elements
+
+            for (expectedItem <- escapedJSONArr) {
+                receivedParams should contain(expectedItem)
+                receivedAnnots should contain(expectedItem)
+            }
     }
 
-    it should "create, and get a trigger to verify parameter parsing" in withAssetCleaner(wskprops) {
+    it should "create, and get a trigger to verify file parameter and annotation parsing" in withAssetCleaner(wskprops) {
         (wp, assetHelper) =>
-            val name = "triggerParameters"
+            val name = "triggerAnnotAndParamFileParsing"
+            val file = Some(TestUtils.getTestActionFilename("hello.js"))
+            val argInput = Some(TestUtils.getTestActionFilename("validInput1.json"))
 
             assetHelper.withCleaner(wsk.trigger, name) {
                 (trigger, _) =>
-                    trigger.create(name, parameters = getValidJSONTestArgInput)
+                    trigger.create(name, annotationFile = argInput, parameterFile = argInput)
             }
 
             val stdout = wsk.trigger.get(name).stdout
             assert(stdout.startsWith(s"ok: got trigger $name\n"))
 
-            wsk.parseJsonString(stdout).fields("parameters") shouldBe getValidJSONTestArgOutput
+            val receivedParams = wsk.parseJsonString(stdout).fields("parameters").convertTo[JsArray].elements
+            val receivedAnnots = wsk.parseJsonString(stdout).fields("annotations").convertTo[JsArray].elements
+            val escapedJSONArr = getJSONFileOutput.convertTo[JsArray].elements
+
+            for (expectedItem <- escapedJSONArr) {
+                receivedParams should contain(expectedItem)
+                receivedAnnots should contain(expectedItem)
+            }
     }
 
     it should "display a trigger summary when --summary flag is used with 'wsk trigger get'" in withAssetCleaner(wskprops) {
@@ -548,34 +581,27 @@
             stdout should include regex (s"(?i)trigger\\s+/${ns_regex_list}/${triggerName}")
     }
 
-    it should "create a trigger with the proper parameter escapes" in withAssetCleaner(wskprops) {
+    it should "create a trigger with the proper parameter and annotation escapes" in withAssetCleaner(wskprops) {
         (wp, assetHelper) =>
-            val name = "triggerName"
+            val name = "triggerEscapes"
+
             assetHelper.withCleaner(wsk.trigger, name) {
                 (trigger, _) =>
-                    wsk.cli(wskprops.overrides ++ Seq("trigger", "create", wsk.trigger.fqn(name), "--auth", wp.authKey) ++
-                        getEscapedJSONTestArgInput())
+                    trigger.create(name, parameters = getEscapedJSONTestArgInput,
+                        annotations = getEscapedJSONTestArgInput)
             }
 
             val stdout = wsk.trigger.get(name).stdout
             assert(stdout.startsWith(s"ok: got trigger $name\n"))
 
-            wsk.parseJsonString(stdout).fields("parameters") shouldBe getEscapedJSONTestArgOutput
-    }
+            val receivedParams = wsk.parseJsonString(stdout).fields("parameters").convertTo[JsArray].elements
+            val receivedAnnots = wsk.parseJsonString(stdout).fields("annotations").convertTo[JsArray].elements
+            val escapedJSONArr = getEscapedJSONTestArgOutput.convertTo[JsArray].elements
 
-    it should "create a trigger with the proper annotation escapes" in withAssetCleaner(wskprops) {
-        (wp, assetHelper) =>
-            val name = "triggerName"
-            assetHelper.withCleaner(wsk.trigger, name) {
-                (trigger, _) =>
-                    wsk.cli(wskprops.overrides ++ Seq("trigger", "create", wsk.trigger.fqn(name), "--auth", wp.authKey) ++
-                        getEscapedJSONTestArgInput(false))
+            for (expectedItem <- escapedJSONArr) {
+                receivedParams should contain(expectedItem)
+                receivedAnnots should contain(expectedItem)
             }
-
-            val stdout = wsk.trigger.get(name).stdout
-            assert(stdout.startsWith(s"ok: got trigger $name\n"))
-
-            wsk.parseJsonString(stdout).fields("annotations") shouldBe getEscapedJSONTestArgOutput
     }
 
     it should "not create a trigger when feed fails to initialize" in withAssetCleaner(wskprops) {
@@ -653,46 +679,179 @@
 
     behavior of "Wsk params and annotations"
 
-    it should "reject commands that are executed with params or annot that are not key/value pairs" in {
+    it should "reject commands that are executed with invalid JSON for annotations and parameters" in {
+        val invalidJSONInputs = getInvalidJSONInput
+        val invalidJSONFiles = Seq(
+            TestUtils.getTestActionFilename("malformed.js"),
+            TestUtils.getTestActionFilename("invalidInput1.json"),
+            TestUtils.getTestActionFilename("invalidInput2.json"),
+            TestUtils.getTestActionFilename("invalidInput3.json"),
+            TestUtils.getTestActionFilename("invalidInput4.json")
+        )
+        val paramCmds = Seq(
+            Seq("action", "create", "actionName", TestUtils.getTestActionFilename("hello.js")),
+            Seq("action", "update", "actionName", TestUtils.getTestActionFilename("hello.js")),
+            Seq("action", "invoke", "actionName"),
+            Seq("package", "create", "packageName"),
+            Seq("package", "update", "packageName"),
+            Seq("package", "bind", "packageName", "boundPackageName"),
+            Seq("trigger", "create", "triggerName"),
+            Seq("trigger", "update", "triggerName"),
+            Seq("trigger", "fire", "triggerName")
+        )
+        val annotCmds = Seq(
+            Seq("action", "create", "actionName", TestUtils.getTestActionFilename("hello.js")),
+            Seq("action", "update", "actionName", TestUtils.getTestActionFilename("hello.js")),
+            Seq("package", "create", "packageName"),
+            Seq("package", "update", "packageName"),
+            Seq("package", "bind", "packageName", "boundPackageName"),
+            Seq("trigger", "create", "triggerName"),
+            Seq("trigger", "update", "triggerName")
+        )
+
+        for (cmd <- paramCmds) {
+            for (invalid <- invalidJSONInputs) {
+                wsk.cli(cmd ++ Seq("-p", "key", invalid), expectedExitCode = ERROR_EXIT)
+                  .stderr should include("Invalid parameter argument")
+            }
+
+            for (invalid <- invalidJSONFiles) {
+                wsk.cli(cmd ++ Seq("-P", invalid), expectedExitCode = ERROR_EXIT)
+                  .stderr should include("Invalid parameter argument")
+
+            }
+        }
+
+        for (cmd <- annotCmds) {
+            for (invalid <- invalidJSONInputs) {
+                wsk.cli(cmd ++ Seq("-a", "key", invalid), expectedExitCode = ERROR_EXIT)
+                  .stderr should include("Invalid annotation argument")
+            }
+
+            for (invalid <- invalidJSONFiles) {
+                wsk.cli(cmd ++ Seq("-A", invalid), expectedExitCode = ERROR_EXIT)
+                  .stderr should include("Invalid annotation argument")
+            }
+        }
+    }
+
+    it should "reject commands that are executed with a missing or invalid parameter or annotation file" in {
+        val emptyFile = TestUtils.getTestActionFilename("emtpy.js")
+        val missingFile = "notafile"
+        val emptyFileMsg = s"File '$emptyFile' is not a valid file or it does not exist"
+        val missingFileMsg = s"File '$missingFile' is not a valid file or it does not exist"
+        val invalidArgs = Seq(
+            (Seq("action", "create", "actionName", TestUtils.getTestActionFilename("hello.js"), "-P", emptyFile),
+              emptyFileMsg),
+            (Seq("action", "update", "actionName", TestUtils.getTestActionFilename("hello.js"), "-P", emptyFile),
+              emptyFileMsg),
+            (Seq("action", "invoke", "actionName", "-P", emptyFile), emptyFileMsg),
+            (Seq("action", "create", "actionName", "-P", emptyFile), emptyFileMsg),
+            (Seq("action", "update", "actionName", "-P", emptyFile), emptyFileMsg),
+            (Seq("action", "invoke", "actionName", "-P", emptyFile), emptyFileMsg),
+            (Seq("package", "create", "packageName", "-P", emptyFile), emptyFileMsg),
+            (Seq("package", "update", "packageName", "-P", emptyFile), emptyFileMsg),
+            (Seq("package", "bind", "packageName", "boundPackageName", "-P", emptyFile), emptyFileMsg),
+            (Seq("package", "create", "packageName", "-P", emptyFile), emptyFileMsg),
+            (Seq("package", "update", "packageName", "-P", emptyFile), emptyFileMsg),
+            (Seq("package", "bind", "packageName", "boundPackageName", "-P", emptyFile), emptyFileMsg),
+            (Seq("trigger", "create", "triggerName", "-P", emptyFile), emptyFileMsg),
+            (Seq("trigger", "update", "triggerName", "-P", emptyFile), emptyFileMsg),
+            (Seq("trigger", "fire", "triggerName", "-P", emptyFile), emptyFileMsg),
+            (Seq("trigger", "create", "triggerName", "-P", emptyFile), emptyFileMsg),
+            (Seq("trigger", "update", "triggerName", "-P", emptyFile), emptyFileMsg),
+            (Seq("trigger", "fire", "triggerName", "-P", emptyFile), emptyFileMsg),
+            (Seq("action", "create", "actionName", TestUtils.getTestActionFilename("hello.js"), "-A", missingFile),
+              missingFileMsg),
+            (Seq("action", "update", "actionName", TestUtils.getTestActionFilename("hello.js"), "-A", missingFile),
+              missingFileMsg),
+            (Seq("action", "invoke", "actionName", "-A", missingFile), missingFileMsg),
+            (Seq("action", "create", "actionName", "-A", missingFile), missingFileMsg),
+            (Seq("action", "update", "actionName", "-A", missingFile), missingFileMsg),
+            (Seq("action", "invoke", "actionName", "-A", missingFile), missingFileMsg),
+            (Seq("package", "create", "packageName", "-A", missingFile), missingFileMsg),
+            (Seq("package", "update", "packageName", "-A", missingFile), missingFileMsg),
+            (Seq("package", "bind", "packageName", "boundPackageName", "-A", missingFile), missingFileMsg),
+            (Seq("package", "create", "packageName", "-A", missingFile), missingFileMsg),
+            (Seq("package", "update", "packageName", "-A", missingFile), missingFileMsg),
+            (Seq("package", "bind", "packageName", "boundPackageName", "-A", missingFile), missingFileMsg),
+            (Seq("trigger", "create", "triggerName", "-A", missingFile), missingFileMsg),
+            (Seq("trigger", "update", "triggerName", "-A", missingFile), missingFileMsg),
+            (Seq("trigger", "fire", "triggerName", "-A", missingFile), missingFileMsg),
+            (Seq("trigger", "create", "triggerName", "-A", missingFile), missingFileMsg),
+            (Seq("trigger", "update", "triggerName", "-A", missingFile), missingFileMsg),
+            (Seq("trigger", "fire", "triggerName", "-A", missingFile), missingFileMsg)
+        )
+
+        invalidArgs foreach {
+            case (cmd, err) =>
+            val stderr = wsk.cli(cmd, expectedExitCode = MISUSE_EXIT).stderr
+            stderr should include(err)
+            stderr should include("Run 'wsk --help' for usage.")
+        }
+    }
+
+    it should "reject commands that are executed with not enough param or annot arguments" in {
         val invalidParamMsg = "Arguments for '-p' must be a key/value pair"
         val invalidAnnotMsg = "Arguments for '-a' must be a key/value pair"
+        val invalidParamFileMsg = "An argument must be provided for '-P'"
+        val invalidAnnotFileMsg = "An argument must be provided for '-A'"
         val invalidArgs = Seq(
             (Seq("action", "create", "actionName", "-p"), invalidParamMsg),
             (Seq("action", "create", "actionName", "-p", "key"), invalidParamMsg),
+            (Seq("action", "create", "actionName", "-P"), invalidParamFileMsg),
             (Seq("action", "update", "actionName", "-p"), invalidParamMsg),
             (Seq("action", "update", "actionName", "-p", "key"), invalidParamMsg),
+            (Seq("action", "update", "actionName", "-P"), invalidParamFileMsg),
             (Seq("action", "invoke", "actionName", "-p"), invalidParamMsg),
             (Seq("action", "invoke", "actionName", "-p", "key"), invalidParamMsg),
+            (Seq("action", "invoke", "actionName", "-P"), invalidParamFileMsg),
             (Seq("action", "create", "actionName", "-a"), invalidAnnotMsg),
             (Seq("action", "create", "actionName", "-a", "key"), invalidAnnotMsg),
+            (Seq("action", "create", "actionName", "-A"), invalidAnnotFileMsg),
             (Seq("action", "update", "actionName", "-a"), invalidAnnotMsg),
             (Seq("action", "update", "actionName", "-a", "key"), invalidAnnotMsg),
+            (Seq("action", "update", "actionName", "-A"), invalidAnnotFileMsg),
             (Seq("action", "invoke", "actionName", "-a"), invalidAnnotMsg),
             (Seq("action", "invoke", "actionName", "-a", "key"), invalidAnnotMsg),
+            (Seq("action", "invoke", "actionName", "-A"), invalidAnnotFileMsg),
             (Seq("package", "create", "packageName", "-p"), invalidParamMsg),
             (Seq("package", "create", "packageName", "-p", "key"), invalidParamMsg),
+            (Seq("package", "create", "packageName", "-P"), invalidParamFileMsg),
             (Seq("package", "update", "packageName", "-p"), invalidParamMsg),
             (Seq("package", "update", "packageName", "-p", "key"), invalidParamMsg),
+            (Seq("package", "update", "packageName", "-P"), invalidParamFileMsg),
             (Seq("package", "bind", "packageName", "boundPackageName", "-p"), invalidParamMsg),
             (Seq("package", "bind", "packageName", "boundPackageName", "-p", "key"), invalidParamMsg),
+            (Seq("package", "bind", "packageName", "boundPackageName", "-P"), invalidParamFileMsg),
             (Seq("package", "create", "packageName", "-a"), invalidAnnotMsg),
             (Seq("package", "create", "packageName", "-a", "key"), invalidAnnotMsg),
+            (Seq("package", "create", "packageName", "-A"), invalidAnnotFileMsg),
             (Seq("package", "update", "packageName", "-a"), invalidAnnotMsg),
             (Seq("package", "update", "packageName", "-a", "key"), invalidAnnotMsg),
+            (Seq("package", "update", "packageName", "-A"), invalidAnnotFileMsg),
             (Seq("package", "bind", "packageName", "boundPackageName", "-a"), invalidAnnotMsg),
             (Seq("package", "bind", "packageName", "boundPackageName", "-a", "key"), invalidAnnotMsg),
+            (Seq("package", "bind", "packageName", "boundPackageName", "-A"), invalidAnnotFileMsg),
             (Seq("trigger", "create", "triggerName", "-p"), invalidParamMsg),
             (Seq("trigger", "create", "triggerName", "-p", "key"), invalidParamMsg),
+            (Seq("trigger", "create", "triggerName", "-P"), invalidParamFileMsg),
             (Seq("trigger", "update", "triggerName", "-p"), invalidParamMsg),
             (Seq("trigger", "update", "triggerName", "-p", "key"), invalidParamMsg),
+            (Seq("trigger", "update", "triggerName", "-P"), invalidParamFileMsg),
             (Seq("trigger", "fire", "triggerName", "-p"), invalidParamMsg),
             (Seq("trigger", "fire", "triggerName", "-p", "key"), invalidParamMsg),
+            (Seq("trigger", "fire", "triggerName", "-P"), invalidParamFileMsg),
             (Seq("trigger", "create", "triggerName", "-a"), invalidAnnotMsg),
             (Seq("trigger", "create", "triggerName", "-a", "key"), invalidAnnotMsg),
+            (Seq("trigger", "create", "triggerName", "-A"), invalidAnnotFileMsg),
             (Seq("trigger", "update", "triggerName", "-a"), invalidAnnotMsg),
             (Seq("trigger", "update", "triggerName", "-a", "key"), invalidAnnotMsg),
+            (Seq("trigger", "update", "triggerName", "-A"), invalidAnnotFileMsg),
             (Seq("trigger", "fire", "triggerName", "-a"), invalidAnnotMsg),
-            (Seq("trigger", "fire", "triggerName", "-a", "key"), invalidAnnotMsg))
+            (Seq("trigger", "fire", "triggerName", "-a", "key"), invalidAnnotMsg),
+            (Seq("trigger", "fire", "triggerName", "-A"), invalidAnnotFileMsg)
+        )
 
         invalidArgs foreach {
             case (cmd, err) =>