Skip to content
Snippets Groups Projects
Commit ea6dce45 authored by James Dubee's avatar James Dubee Committed by Justin Berstler
Browse files

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
parent 1158440f
No related branches found
No related tags found
No related merge requests found
......@@ -225,6 +225,8 @@ class WskAction()
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 @@ class WskAction()
} ++
{ 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 @@ class WskAction()
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 @@ class WskTrigger()
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 @@ class WskTrigger()
{ 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 @@ class WskTrigger()
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 @@ class WskPackage()
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 @@ class WskPackage()
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)
}
......
......@@ -238,6 +238,26 @@ class WskBasicTests
}
}
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 @@ class WskBasicTests
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) {
......
......@@ -24,41 +24,85 @@ import spray.json.JsBoolean
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 getEscapedJSONTestArgOutput() = JsArray(
def getJSONFileOutput() = JsArray(
JsObject(
"key" -> JsString("\"key\"with\\escapes"),
"key" -> JsString("a key"),
"value" -> JsString("a value")
),
JsObject(
"key" -> JsString("a bool"),
"value" -> JsBoolean(true)
),
JsObject(
"key" -> JsString("objKey"),
"value" -> JsObject(
"valid" -> JsString("JSON")
"b" -> JsString("c")
)
),
JsObject(
"key" -> JsString("another\"escape\""),
"key" -> JsString("objKey2"),
"value" -> JsObject(
"another object" -> JsObject(
"some string" -> JsString("1111")
)
)
),
JsObject(
"key" -> JsString("objKey3"),
"value" -> JsObject(
"valid" -> JsString("\nJ\rO\tS\bN\f")
"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("key1"),
"value" -> JsObject(
......@@ -70,6 +114,18 @@ object JsonArgsForTests {
"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")
)
)
)
......
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment