diff --git a/project/build.properties b/project/build.properties index 8b697bb..31334bb 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.1.0 +sbt.version=1.1.1 diff --git a/src/main/scala/me/snov/sns/api/PublishApi.scala b/src/main/scala/me/snov/sns/api/PublishApi.scala index 760ad76..6e4ddcb 100644 --- a/src/main/scala/me/snov/sns/api/PublishApi.scala +++ b/src/main/scala/me/snov/sns/api/PublishApi.scala @@ -16,6 +16,7 @@ import spray.json._ import scala.concurrent.{ExecutionContext, Future} +case class InvalidTopicArnException(msg: String) extends Exception(msg) object PublishApi { private val arnPattern = """([\w+_:-]{1,512})""".r @@ -25,9 +26,9 @@ object PublishApi { formField('Action ! "Publish") { formFieldSeq { fields => val messageAttributes: Map[String, MessageAttribute] = MessageAttribute.parse(fields) - formFields('TopicArn, 'MessageStructure.?, 'Message) { (topicArn, messageStructure, message) => + formFields('TopicArn.?, 'TargetArn.?, 'MessageStructure.?, 'Message) { (topicArnMaybe, targetArnMaybe, messageStructure, message) => try { - topicArn match { + topicArn(topicArnMaybe, targetArnMaybe) match { case arnPattern(topic) => complete { val bodies = messageStructure match { case Some("json") => message.parseJson.asJsObject.convertTo[Map[String, String]] @@ -44,6 +45,7 @@ object PublishApi { case _ => complete(HttpResponse(400, entity = "Invalid topic ARN")) } } catch { + case e: InvalidTopicArnException => complete(HttpResponse(400, entity = e.getMessage)) case e: RuntimeException => complete(HttpResponse(400, entity = e.getMessage)) } } @@ -52,4 +54,9 @@ object PublishApi { } } } + + private def topicArn(topicArnMaybe: Option[String], targetArnMaybe: Option[String]): String = { + topicArnMaybe.getOrElse(targetArnMaybe.getOrElse(throw InvalidTopicArnException("Neither TopicArn nor TargetArn provided"))) + } } + diff --git a/src/test/scala/me/snov/sns/api/PublishSpec.scala b/src/test/scala/me/snov/sns/api/PublishSpec.scala index 4d58efa..e09a01b 100644 --- a/src/test/scala/me/snov/sns/api/PublishSpec.scala +++ b/src/test/scala/me/snov/sns/api/PublishSpec.scala @@ -42,6 +42,24 @@ class PublishSpec extends WordSpec with Matchers with ScalatestRouteTest { } } + "Sends publish command to TargetArn" in { + val params = Map( + "Action" -> "Publish", + "TargetArn" -> "foo", + "Message" -> "bar" + ) + + probe.setAutoPilot(new TestActor.AutoPilot { + def run(sender: ActorRef, msg: Any) = { + sender ! Message(Map("default" -> "foo")) + this + } + }) + Post("/", FormData(params)) ~> route ~> check { + probe.expectMsg(CmdPublish("foo", Map("default" -> "bar"), Map.empty)) + } + } + "Sends publish command with attributes" in { val params = Map( "Action" -> "Publish",