Navigation Menu

Skip to content
This repository has been archived by the owner on Dec 5, 2023. It is now read-only.

Commit

Permalink
Rewrote the JUnit Jersey test in Scala (compiler bug has been fixed i…
Browse files Browse the repository at this point in the history
…n Scala 2.8!)
  • Loading branch information
ept committed May 19, 2010
1 parent 312ba86 commit dd6a6f1
Show file tree
Hide file tree
Showing 4 changed files with 173 additions and 139 deletions.
6 changes: 6 additions & 0 deletions pom.xml
Expand Up @@ -47,6 +47,12 @@
<version>1.1.5</version>
</dependency>

<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.1.5</version>
</dependency>

<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-test-framework</artifactId>
Expand Down
51 changes: 51 additions & 0 deletions src/main/scala/com/eptcomputing/neo4j/JerseyConverters.scala
@@ -0,0 +1,51 @@
package com.eptcomputing.neo4j

import com.sun.jersey.api.client.{ClientResponse, UniformInterface, WebResource}
import javax.ws.rs.core.MediaType
import org.codehaus.jettison.json.JSONObject

/**
* Extend your class with this trait to fix some oddities in the Jersey client API.
* - Jersey defines a method WebResource.type for setting the content type.
* Unfortunately "type" is a reserved word in Scala, so this converter offers
* an alternative "contentType" method instead.
* - If you want to get a response back from a GET/POST/PUT/DELETE/OPTIONS, you have
* to pass an ugly type parameter. With these conversions, you can just use
* e.g. getResponse instead of get, and it defaults to a type of ClientResponse, or
* e.g. getJSON instead of get, and it defaults to a type of JSONObject.
*/
trait JerseyConverters {

class WebResourceMethods(resource: WebResource) {
def contentType(contentType: String) = {
val typeMethod = classOf[WebResource].getMethod("type", classOf[java.lang.String])
typeMethod.invoke(resource, contentType).asInstanceOf[UniformInterface]
}

def contentType(contentType: MediaType) = {
val typeMethod = classOf[WebResource].getMethod("type", classOf[MediaType])
typeMethod.invoke(resource, contentType).asInstanceOf[UniformInterface]
}
}

class UniformInterfaceMethods(uniformInterface: UniformInterface) {
def getResponse = uniformInterface.get (classOf[ClientResponse])
def deleteResponse = uniformInterface.delete (classOf[ClientResponse])
def optionsResponse = uniformInterface.options(classOf[ClientResponse])
def postResponse(entity: java.lang.Object) = uniformInterface.post(classOf[ClientResponse], entity)
def putResponse (entity: java.lang.Object) = uniformInterface.put (classOf[ClientResponse], entity)

def getJSON = uniformInterface.get (classOf[JSONObject])
def deleteJSON = uniformInterface.delete (classOf[JSONObject])
def optionsJSON = uniformInterface.options(classOf[JSONObject])
def postJSON(entity: java.lang.Object) = uniformInterface.post(classOf[JSONObject], entity)
def putJSON (entity: java.lang.Object) = uniformInterface.put (classOf[JSONObject], entity)
}


implicit def addContentTypeMethodToWebResource(resource: WebResource) =
new WebResourceMethods(resource)

implicit def addResponseMethodsToUniformInterface(uniformInterface: UniformInterface) =
new UniformInterfaceMethods(uniformInterface)
}
139 changes: 0 additions & 139 deletions src/test/java/com/eptcomputing/neo4j/rest/Neo4jResourceTest.java

This file was deleted.

116 changes: 116 additions & 0 deletions src/test/scala/com/eptcomputing/neo4j/rest/Neo4jResourceSpec.scala
@@ -0,0 +1,116 @@
package com.eptcomputing.neo4j.rest

import org.scalatest.{BeforeAndAfterAll, FlatSpec}
import org.scalatest.matchers.ShouldMatchers
import org.scalatest.junit.JUnitRunner
import org.junit.runner.RunWith

import com.eptcomputing.neo4j.JerseyConverters

import org.codehaus.jettison.json.{JSONArray, JSONException, JSONObject}
import com.sun.jersey.test.framework.JerseyTest
import com.sun.jersey.api.client.UniformInterfaceException


@RunWith(classOf[JUnitRunner])
class Neo4jResourceSpec extends JerseyTest("com.eptcomputing.neo4j.rest.test")
with FlatSpec with ShouldMatchers with BeforeAndAfterAll with JerseyConverters {

// Run Jersey server while running tests
override def beforeAll { setUp }
override def afterAll { tearDown }

// Helper which creates a new entity via the API, and returns its ID.
def createEntity(entity: JSONObject) = {
val created = resource.path("/neo_resource").contentType("application/json").postResponse(entity)
created.getStatus should equal(201)
created.getLocation.getPath.replaceAll(".*/", "").toLong
}

// Helper which creates a JSON object from a list of key-value pairs
def json(pairs: Tuple2[String, Any]*) = {
val obj = new JSONObject
for ((key, value) <- pairs.toList) obj.put(key, value.asInstanceOf[AnyRef])
obj
}


"A Neo4jResource" should "return the new resource URL on POST" in {
val id = createEntity(json(("key", "value")))
val read = resource.path("/neo_resource/%d".format(id)).getJSON
read.get("key") should equal("value")
}


it should "update resource properties on PUT" in {
// Create new entity
val id = createEntity(json(("one", 1), ("two", 2), ("three", 3)))

// Delete one, update two, leave three unchanged, add four
val updated = json(("two", 22), ("three", 3), ("four", 4))
val readBack = resource.path("/neo_resource/%d".format(id)).contentType("application/json").putJSON(updated)

// Also do a separate read, and make sure both have the right contents
val readSeparate = resource.path("/neo_resource/%d".format(id)).getJSON
for (read <- Array(readBack, readSeparate)) {
evaluating { read.getInt("one") } should produce [JSONException]
read.getInt("two") should equal(22)
read.getInt("three") should equal(3)
read.getInt("four") should equal(4)
}
}


it should "update relationships on PUT" in {
// 1 <-- 2 <--> 3 and 1 <-- 3
val one = createEntity(json())
val two = createEntity(json(("_out", json(("ONE_TWO", one)))))
val three = createEntity(json(
("_in", json(("TWO_THREE", two))),
("_out", json(("TWO_THREE", two), ("ONE_TWO", json(("_end", one), ("foo", "bar")))))
))
val four = createEntity(json())

// Update to: 1 <--> 2 --> 3 and 1 <-- 3 and 2 --> 4
val twoUpdate = json(
("_in", json(("ONE_TWO", json(("_start", one), ("foo", "bar"))))),
("_out", json(("ONE_TWO", one), ("TWO_THREE", (new JSONArray).put(three).put(four))))
)
val readBack = resource.path("/neo_resource/%d".format(two)).contentType("application/json").putJSON(twoUpdate)

// Also do a separate read, and make sure both have the right contents
val readSeparate = resource.path("/neo_resource/%d".format(two)).getJSON
for (read <- Array(readBack, readSeparate)) {
val in = read.getJSONObject("_in")
val out = read.getJSONObject("_out")

in.getJSONObject("ONE_TWO").getInt("_start") should equal(one)
in.getJSONObject("ONE_TWO").getString("foo") should equal("bar")
out.getJSONObject("ONE_TWO").getInt("_end") should equal(one)

evaluating { in.getJSONObject("TWO_THREE") } should produce [JSONException]
evaluating { out.getJSONObject("ONE_TWO").getString("foo") } should produce [JSONException]

Set(
out.getJSONArray("TWO_THREE").getJSONObject(0).getInt("_end"),
out.getJSONArray("TWO_THREE").getJSONObject(1).getInt("_end")
) should equal(Set(three, four))
}
}


it should "delete a resource on DELETE" in {
// Create two new entities with a relationship
val id = createEntity(json(("key", "value")))
createEntity(json(("something", "else"), ("_out", json(("KNOWS", id)))))

// Delete the first and check that it has gone
val response = resource.path("/neo_resource/%d".format(id)).deleteJSON
response.get("key") should equal("value")

val thrown = evaluating {
resource.path("/neo_resource/%d".format(id)).getJSON
} should produce [UniformInterfaceException]
thrown.getResponse.getStatus should equal(404)
}
}

0 comments on commit dd6a6f1

Please sign in to comment.