This repository has been archived by the owner on Dec 5, 2023. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rewrote the JUnit Jersey test in Scala (compiler bug has been fixed i…
…n Scala 2.8!)
- Loading branch information
Showing
4 changed files
with
173 additions
and
139 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
51 changes: 51 additions & 0 deletions
51
src/main/scala/com/eptcomputing/neo4j/JerseyConverters.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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
139
src/test/java/com/eptcomputing/neo4j/rest/Neo4jResourceTest.java
This file was deleted.
Oops, something went wrong.
116 changes: 116 additions & 0 deletions
116
src/test/scala/com/eptcomputing/neo4j/rest/Neo4jResourceSpec.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
} | ||
} |