Flat project hierarchy
[aquarium] / src / test / scala / gr / grnet / aquarium / rest / actor / service / SprayPingServiceTest.scala
1 /*
2  * Copyright 2011 GRNET S.A. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or
5  * without modification, are permitted provided that the following
6  * conditions are met:
7  *
8  *   1. Redistributions of source code must retain the above
9  *      copyright notice, this list of conditions and the following
10  *      disclaimer.
11  *
12  *   2. Redistributions in binary form must reproduce the above
13  *      copyright notice, this list of conditions and the following
14  *      disclaimer in the documentation and/or other materials
15  *      provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
18  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
21  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
24  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  *
30  * The views and conclusions contained in the software and
31  * documentation are those of the authors and should not be
32  * interpreted as representing official policies, either expressed
33  * or implied, of GRNET S.A.
34  */
35
36 package gr.grnet.aquarium.rest.akka.service
37
38 import org.junit.Test
39 import cc.spray.can.HttpClient._
40
41 import cc.spray.can.HttpMethods.GET
42 import gr.grnet.aquarium.util.Loggable
43 import org.junit.Assume._
44 import gr.grnet.aquarium.LogicTestsAssumptions
45 import cc.spray.can._
46 import akka.actor.{Actor, PoisonPill}
47 import org.slf4j.LoggerFactory
48
49 /**
50  * This class is heavily based on the Spray samples.
51  * Copyright is what copyright Spray has.
52  */
53 class SprayPingService(_id: String = "spray-root-service") extends Actor {
54   private[this] val logger = LoggerFactory.getLogger(getClass)
55
56   self.id = _id
57
58   protected def receive = {
59     case RequestContext(HttpRequest(GET, "/", _, _, _), _, responder) =>
60       responder.complete(index)
61
62     case RequestContext(HttpRequest(GET, "/ping", _, _, _), _, responder) =>
63       responder.complete(response("PONG!"))
64
65     case RequestContext(HttpRequest(GET, "/stats", _, _, _), _, responder) => {
66       (serverActor ? GetStats).mapTo[Stats].onComplete {
67         future =>
68           future.value.get match {
69             case Right(stats) => responder.complete {
70               response {
71                 "Uptime              : " + (stats.uptime / 1000.0) + " sec\n" +
72                   "Requests dispatched : " + stats.requestsDispatched + '\n' +
73                   "Requests timed out  : " + stats.requestsTimedOut + '\n' +
74                   "Requests open       : " + stats.requestsOpen + '\n' +
75                   "Open connections    : " + stats.connectionsOpen + '\n'
76               }
77             }
78             case Left(ex) => responder.complete(response("Couldn't get server stats due to " + ex, status = 500))
79           }
80       }
81     }
82
83     case RequestContext(HttpRequest(_, _, _, _, _), _, responder) =>
84       responder.complete(response("Unknown resource!", 404))
85
86     case Timeout(method, uri, _, _, _, complete) => complete {
87       HttpResponse(status = 500).withBody("The " + method + " request to '" + uri + "' has timed out...")
88     }
89   }
90
91   ////////////// helpers //////////////
92
93   val defaultHeaders = List(HttpHeader("Content-Type", "text/plain"))
94
95   lazy val serverActor = Actor.registry.actorsFor("spray-can-server").head
96
97   def response(msg: String, status: Int = 200) = HttpResponse(status, defaultHeaders, msg.getBytes("ISO-8859-1"))
98
99   lazy val index = HttpResponse(
100     headers = List(HttpHeader("Content-Type", "text/html")),
101     body =
102       <html>
103         <body>
104           <h1>Say hello to
105             <i>spray-can</i>
106             !</h1>
107           <p>Defined resources:</p>
108           <ul>
109             <li>
110               <a href="/ping">/ping</a>
111             </li>
112             <li>
113               <a href="/stats">/stats</a>
114             </li>
115           </ul>
116         </body>
117       </html>.toString.getBytes("UTF-8")
118   )
119 }
120
121 /**
122  * 
123  * @author Christos KK Loverdos <loverdos@gmail.com>.
124  */
125 class SprayPingServiceTest extends Loggable {
126   @Test
127   def testPing: Unit = {
128     assumeTrue(LogicTestsAssumptions.EnableSprayTests)
129
130     val service = Actor.actorOf(new SprayPingService("spray-root-service")).start()
131     val server = Actor.actorOf(new HttpServer()).start()
132     val client = Actor.actorOf(new HttpClient()).start()
133
134     val dialog = HttpDialog("localhost", 8080)
135     val result = dialog.send(HttpRequest(method = GET, uri = "/ping", headers = HttpHeader("Content-Type", "text/plain; charset=UTF-8")::Nil)).end
136     result onComplete { future =>
137       future.value match {
138         case Some(Right(response)) =>
139           logger.info("Response class  : %s".format(response.getClass))
140           logger.info("Response status : %s".format(response.status))
141           logger.info("Response headers: %s".format(response.headers.map(hh => (hh.name, hh.value)).mkString(", ")))
142           logger.info("Response body   : %s".format(response.bodyAsString))
143         case other =>
144           logger.error("Error: %s".format(other))
145       }
146
147       service ! PoisonPill
148       client  ! PoisonPill
149     }
150
151     Thread sleep 100
152   }
153 }