Permalink
Browse files

End-to-end tests.

Add tests that hit a running mongo to verify that the queries Rogue
formulates actually do what we expect.

 * Factored test models from QueryTest into TestModels.scala
 * Made EndToEndTest with some simple query tests that I lifted from
   QueryTest.
 * Added a start-test-mongo.sh script to fetch a mongo binary if
   necessary, make a mongo-testdb directory for its data, and start it.
 * Added a RogueTestMongo mongo identifier and made all of the test
   models use it. It connects to localhost:37648 (EROGU), the same port
   that start-test-mongo.sh uses.
 * Added some stuff to gitignore too.
  • Loading branch information...
1 parent f40d13a commit 75a7d4c7a8eba61ab7dabb4e11c917249d44cbd8 @nsanch nsanch committed Dec 14, 2011
View
@@ -9,3 +9,8 @@ sbtlib
target
out
*~
+mongo-testdb
+dependencies
+mongo.log
+tags
+tags.old
View
@@ -1,3 +1,5 @@
+#!/bin/bash
+
# Internal options, always specified
INTERNAL_OPTS="-Dfile.encoding=UTF-8 -Xss8M -Xmx1G -noverify -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC -XX:MaxPermSize=512M"
@@ -0,0 +1,162 @@
+// Copyright 2011 Foursquare Labs Inc. All Rights Reserved.
+package com.foursquare.rogue
+
+import com.foursquare.rogue.Rogue._
+
+import java.util.regex.Pattern
+import net.liftweb.common.{Box, Empty, Full}
+import org.bson.types.ObjectId
+import org.junit.{Before, After, Ignore, Test}
+import org.specs.SpecsMatchers
+
+/**
+ * Contains tests that test the interaction of Rogue with a real mongo.
+ */
+class EndToEndTest extends SpecsMatchers {
+ def baseTestVenue(): Venue = {
+ Venue.createRecord
+ .legacyid(123)
+ .userid(456)
+ .venuename("test venue")
+ .mayor(789)
+ .mayor_count(3)
+ .closed(false)
+ .popularity(List(1L, 2L, 3L))
+ .categories(List(new ObjectId()))
+ .geolatlng(LatLong(40.73, -73.98))
+ .status(VenueStatus.open)
+ .claims(List(VenueClaimBson.createRecord.userid(1234).status(ClaimStatus.pending),
+ VenueClaimBson.createRecord.userid(5678).status(ClaimStatus.approved)))
+ .lastClaim(VenueClaimBson.createRecord.userid(5678).status(ClaimStatus.approved))
+ }
+
+ def baseTestVenueClaim(vid: ObjectId): VenueClaim = {
+ VenueClaim.createRecord
+ .venueid(vid)
+ .userid(123)
+ .status(ClaimStatus.approved)
+ }
+
+ def baseTestTip(): Tip = {
+ Tip.createRecord
+ .legacyid(234)
+ .counts(Map("foo" -> 1L,
+ "bar" -> 2L))
+ }
+
+ @Before
+ def setupMongoConnection: Unit = {
+ RogueTestMongo.connectToMongo
+ }
+
+ @After
+ def cleanupTestData: Unit = {
+ Venue.bulkDelete_!!()
+ Venue.count() must_== 0
+
+ VenueClaim.bulkDelete_!!()
+ VenueClaim.count() must_== 0
+
+ RogueTestMongo.disconnectFromMongo
+ }
+
+ @Test
+ def eqsTests: Unit = {
+ val v = baseTestVenue().save
+ val vc = baseTestVenueClaim(v.id).save
+
+ // eqs
+ Venue.where(_._id eqs v.id).fetch().map(_.id) must_== List(v.id)
+ Venue.where(_.mayor eqs v.mayor.value).fetch().map(_.id) must_== List(v.id)
+ Venue.where(_.mayor eqs v.mayor.value).fetch().map(_.id) must_== List(v.id)
+ Venue.where(_.venuename eqs v.venuename.value).fetch().map(_.id) must_== List(v.id)
+ Venue.where(_.closed eqs false).fetch().map(_.id) must_== List(v.id)
+
+ Venue.where(_.mayor eqs 432432).fetch().map(_.id) must_== Nil
+ Venue.where(_.closed eqs true).fetch().map(_.id) must_== Nil
+
+ VenueClaim.where(_.status eqs ClaimStatus.approved).fetch().map(_.id) must_== List(vc.id)
+ VenueClaim.where(_.venueid eqs v.id).fetch().map(_.id) must_== List(vc.id)
+ VenueClaim.where(_.venueid eqs v).fetch().map(_.id) must_== List(vc.id)
+ }
+
+ @Test
+ def testInequalityQueries: Unit = {
+ val v = baseTestVenue().save
+ val vc = baseTestVenueClaim(v.id).save
+
+ // neq,lt,gt, where the lone Venue has mayor_count=3, and the only
+ // VenueClaim has status approved.
+ Venue.where(_.mayor_count neqs 5).fetch().map(_.id) must_== List(v.id)
+ Venue.where(_.mayor_count < 5).fetch().map(_.id) must_== List(v.id)
+ Venue.where(_.mayor_count lt 5).fetch().map(_.id) must_== List(v.id)
+ Venue.where(_.mayor_count <= 5).fetch().map(_.id) must_== List(v.id)
+ Venue.where(_.mayor_count lte 5).fetch().map(_.id) must_== List(v.id)
+ Venue.where(_.mayor_count > 5).fetch().map(_.id) must_== Nil
+ Venue.where(_.mayor_count gt 5).fetch().map(_.id) must_== Nil
+ Venue.where(_.mayor_count >= 5).fetch().map(_.id) must_== Nil
+ Venue.where(_.mayor_count gte 5).fetch().map(_.id) must_== Nil
+ Venue.where(_.mayor_count between (3, 5)).fetch().map(_.id) must_== List(v.id)
+ VenueClaim.where (_.status neqs ClaimStatus.approved).fetch().map(_.id) must_== Nil
+ VenueClaim.where (_.status neqs ClaimStatus.pending).fetch().map(_.id) must_== List(vc.id)
+ }
+
+ @Test
+ def selectQueries: Unit = {
+ val v = baseTestVenue().save
+
+ val base = Venue.where(_._id eqs v.id)
+ base.select(_.legacyid).fetch() must_== List(v.legacyid.value)
+ base.select(_.legacyid, _.userid).fetch() must_== List((v.legacyid.value, v.userid.value))
+ base.select(_.legacyid, _.userid, _.mayor).fetch() must_== List((v.legacyid.value, v.userid.value, v.mayor.value))
+ base.select(_.legacyid, _.userid, _.mayor, _.mayor_count).fetch() must_== List((v.legacyid.value, v.userid.value, v.mayor.value, v.mayor_count.value))
+ base.select(_.legacyid, _.userid, _.mayor, _.mayor_count, _.closed).fetch() must_== List((v.legacyid.value, v.userid.value, v.mayor.value, v.mayor_count.value, v.closed.value))
+ base.select(_.legacyid, _.userid, _.mayor, _.mayor_count, _.closed, _.tags).fetch() must_== List((v.legacyid.value, v.userid.value, v.mayor.value, v.mayor_count.value, v.closed.value, v.tags.value))
+ }
+
+ @Test
+ def selectEnum: Unit = {
+ val v = baseTestVenue().save
+ Venue.where(_._id eqs v.id).select(_.status).fetch() must_== List(VenueStatus.open)
+ }
+
+ @Test
+ def selectCaseQueries: Unit = {
+ val v = baseTestVenue().save
+
+ val base = Venue.where(_._id eqs v.id)
+ base.selectCase(_.legacyid, V1).fetch() must_== List(V1(v.legacyid.value))
+ base.selectCase(_.legacyid, _.userid, V2).fetch() must_== List(V2(v.legacyid.value, v.userid.value))
+ base.selectCase(_.legacyid, _.userid, _.mayor, V3).fetch() must_== List(V3(v.legacyid.value, v.userid.value, v.mayor.value))
+ base.selectCase(_.legacyid, _.userid, _.mayor, _.mayor_count, V4).fetch() must_== List(V4(v.legacyid.value, v.userid.value, v.mayor.value, v.mayor_count.value))
+ base.selectCase(_.legacyid, _.userid, _.mayor, _.mayor_count, _.closed, V5).fetch() must_== List(V5(v.legacyid.value, v.userid.value, v.mayor.value, v.mayor_count.value, v.closed.value))
+ base.selectCase(_.legacyid, _.userid, _.mayor, _.mayor_count, _.closed, _.tags, V6).fetch() must_== List(V6(v.legacyid.value, v.userid.value, v.mayor.value, v.mayor_count.value, v.closed.value, v.tags.value))
+ }
+
+ @Test
+ def selectSubfieldQueries: Unit = {
+ val v = baseTestVenue().save
+ val t = baseTestTip().save
+
+ // select subfields
+ Tip.where(_._id eqs t.id).select(_.counts at "foo").fetch() must_== List(Full(1L))
+
+ Venue.where(_._id eqs v.id).select(_.geolatlng.unsafeField[Double]("lat")).fetch() must_== List(Full(40.73))
+ }
+
+ @Ignore("These tests are broken because DummyField doesn't know how to convert a String to an Enum")
+ def testSelectEnumSubfield: Unit = {
+ val v = baseTestVenue().save
+
+ // This behavior is broken because we get a String back from mongo, and at
+ // that point we only have a DummyField for the subfield, and that doesn't
+ // know how to convert the String to an Enum.
+
+ val statuses: List[Box[VenueClaimBson.status.MyType]] =
+ Venue.where(_._id eqs v.id).select(_.lastClaim.subfield(_.status)) .fetch()
+ // This assertion works.
+ statuses must_== List(Full("Approved"))
+ // This assertion is what we want, and it fails.
+ // statuses must_== List(Full(ClaimStatus.approved))
+ }
+}
@@ -14,107 +14,6 @@ import org.joda.time.{DateTime, DateTimeZone}
import org.junit._
import org.specs.SpecsMatchers
-/////////////////////////////////////////////////
-// Sample records for testing
-/////////////////////////////////////////////////
-object VenueStatus extends Enumeration {
- val open = Value("Open")
- val closed = Value("Closed")
-}
-
-class Venue extends MongoRecord[Venue] with MongoId[Venue] {
- def meta = Venue
- object legacyid extends LongField(this) { override def name = "legid" }
- object userid extends LongField(this)
- object venuename extends StringField(this, 255)
- object mayor extends LongField(this)
- object mayor_count extends LongField(this)
- object closed extends BooleanField(this)
- object tags extends MongoListField[Venue, String](this)
- object popularity extends MongoListField[Venue, Long](this)
- object categories extends MongoListField[Venue, ObjectId](this)
- object geolatlng extends MongoCaseClassField[Venue, LatLong](this) { override def name = "latlng" }
- object last_updated extends DateTimeField(this)
- object status extends EnumNameField(this, VenueStatus) { override def name = "status" }
- object claims extends BsonRecordListField(this, VenueClaimBson)
- object lastClaim extends BsonRecordField(this, VenueClaimBson)
-}
-object Venue extends Venue with MongoMetaRecord[Venue] {
- object CustomIndex extends IndexModifier("custom")
- val idIdx = Venue.index(_._id, Asc)
- val legIdx = Venue.index(_.legacyid, Desc)
- val geoIdx = Venue.index(_.geolatlng, TwoD)
- val geoCustomIdx = Venue.index(_.geolatlng, CustomIndex, _.tags, Asc)
-
- trait FK[T <: FK[T]] extends MongoRecord[T] {
- self: T=>
- object venueid extends ObjectIdField[T](this) with HasMongoForeignObjectId[Venue] {
- override def name = "vid"
- }
- }
-}
-
-object ClaimStatus extends Enumeration {
- val pending = Value("Pending approval")
- val approved = Value("Approved")
-}
-
-class VenueClaim extends MongoRecord[VenueClaim] with MongoId[VenueClaim] with Venue.FK[VenueClaim] {
- def meta = VenueClaim
- object userid extends LongField(this) { override def name = "uid" }
- object status extends EnumNameField(this, ClaimStatus)
-}
-object VenueClaim extends VenueClaim with MongoMetaRecord[VenueClaim] {
- override def fieldOrder = List(status, _id, userid, venueid)
-}
-
-class VenueClaimBson extends BsonRecord[VenueClaimBson] {
- def meta = VenueClaimBson
- object userid extends LongField(this) { override def name = "uid" }
- object status extends EnumNameField(this, ClaimStatus)
-}
-object VenueClaimBson extends VenueClaimBson with BsonMetaRecord[VenueClaimBson] {
- override def fieldOrder = List(status, userid)
-}
-
-
-case class OneComment(timestamp: String, userid: Long, comment: String)
-class Comment extends MongoRecord[Comment] with MongoId[Comment] {
- def meta = Comment
- object comments extends MongoCaseClassListField[Comment, OneComment](this)
-}
-object Comment extends Comment with MongoMetaRecord[Comment] {
- val idx1 = Comment.index(_._id, Asc)
-}
-
-class Tip extends MongoRecord[Tip] with MongoId[Tip] {
- def meta = Tip
- object legacyid extends LongField(this) { override def name = "legid" }
- object counts extends MongoMapField[Tip, Long](this)
-}
-object Tip extends Tip with MongoMetaRecord[Tip]
-
-object ConsumerPrivilege extends Enumeration {
- val awardBadges = Value("Award badges")
-}
-
-class OAuthConsumer extends MongoRecord[OAuthConsumer] with MongoId[OAuthConsumer] {
- def meta = OAuthConsumer
- object privileges extends MongoListField[OAuthConsumer, ConsumerPrivilege.Value](this)
-}
-object OAuthConsumer extends OAuthConsumer with MongoMetaRecord[OAuthConsumer]
-
-case class V1(legacyid: Long)
-case class V2(legacyid: Long, userid: Long)
-case class V3(legacyid: Long, userid: Long, mayor: Long)
-case class V4(legacyid: Long, userid: Long, mayor: Long, mayor_count: Long)
-case class V5(legacyid: Long, userid: Long, mayor: Long, mayor_count: Long, closed: Boolean)
-case class V6(legacyid: Long, userid: Long, mayor: Long, mayor_count: Long, closed: Boolean, tags: List[String])
-
-/////////////////////////////////////////////////
-// Actual tests
-/////////////////////////////////////////////////
-
class QueryTest extends SpecsMatchers {
@Test
Oops, something went wrong.

0 comments on commit 75a7d4c

Please sign in to comment.