diff --git a/project/Build.scala b/project/Build.scala index ab05ea56..3936f852 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -28,15 +28,9 @@ import AssemblyKeys._ object StorehausBuild extends Build { def withCross(dep: ModuleID) = dep cross CrossVersion.binaryMapped { - case "2.9.3" => "2.9.2" // TODO: hack because twitter hasn't built things against 2.9.3 case version if version startsWith "2.10" => "2.10" // TODO: hack because sbt is broken case x => x } - - def specs2Import(scalaVersion: String) = scalaVersion match { - case version if version startsWith "2.9" => "org.specs2" %% "specs2" % "1.12.4.1" % "test" - case version if version startsWith "2.10" => "org.specs2" %% "specs2" % "1.13" % "test" - } val extraSettings = Project.defaultSettings ++ Boilerplate.settings ++ assemblySettings ++ mimaDefaultSettings @@ -62,7 +56,7 @@ object StorehausBuild extends Build { crossScalaVersions := Seq("2.10.4"), javacOptions ++= Seq("-source", "1.6", "-target", "1.6"), javacOptions in doc := Seq("-source", "1.6"), - libraryDependencies <+= scalaVersion(specs2Import(_)), + libraryDependencies += "org.scalatest" %% "scalatest" % scalatestVersion % "test", resolvers ++= Seq( Opts.resolver.sonatypeSnapshots, Opts.resolver.sonatypeReleases, @@ -123,6 +117,8 @@ object StorehausBuild extends Build { val utilVersion = "6.22.0" val scaldingVersion = "0.13.1" val finagleVersion = "6.22.0" + val scalatestVersion = "2.2.4" + val specs2Version = "1.13" lazy val storehaus = Project( id = "storehaus", @@ -238,7 +234,8 @@ object StorehausBuild extends Build { ExclusionRule("com.sun.jdmk","jmxtools"), ExclusionRule( "com.sun.jmx","jmxri"), ExclusionRule( "javax.jms","jms") - ) + ), + "org.specs2" %% "specs2" % specs2Version % "test" ), // we don't want various tests clobbering each others keys parallelExecution in Test := false @@ -251,7 +248,8 @@ object StorehausBuild extends Build { "org.apache.kafka" % "kafka_2.9.2" % "0.8.0" % "provided" excludeAll( ExclusionRule(organization = "com.sun.jdmk"), ExclusionRule(organization = "com.sun.jmx"), - ExclusionRule(organization = "javax.jms")) + ExclusionRule(organization = "javax.jms")), + "org.specs2" %% "specs2" % specs2Version % "test" ), // we don't want various tests clobbering each others keys parallelExecution in Test := false @@ -283,8 +281,10 @@ object StorehausBuild extends Build { settings = sharedSettings ++ Seq( name := "storehaus-testing", previousArtifact := youngestForwardCompatible("testing"), - libraryDependencies ++= Seq("org.scalacheck" %% "scalacheck" % "1.10.0" withSources(), - withCross("com.twitter" %% "util-core" % utilVersion)) + libraryDependencies ++= Seq( + "org.scalacheck" %% "scalacheck" % "1.10.0" withSources(), + withCross("com.twitter" %% "util-core" % utilVersion) + ) ) ) @@ -293,8 +293,9 @@ object StorehausBuild extends Build { "com.google.code.java-allocation-instrumenter" % "java-allocation-instrumenter" % "2.0", "com.google.code.gson" % "gson" % "1.7.1", "com.twitter" %% "bijection-core" % bijectionVersion, - "com.twitter" %% "algebird-core" % algebirdVersion), - javaOptions in run <++= (fullClasspath in Runtime) map { cp => Seq("-cp", sbt.Build.data(cp).mkString(":")) } + "com.twitter" %% "algebird-core" % algebirdVersion + ), + javaOptions in run <++= (fullClasspath in Runtime) map { cp => Seq("-cp", sbt.Build.data(cp).mkString(":")) } ).dependsOn(storehausCore, storehausAlgebra, storehausCache) lazy val storehausHttp = module("http").settings( diff --git a/storehaus-cache/src/test/scala/com/twitter/storehaus/cache/HHFilteredCacheTest.scala b/storehaus-cache/src/test/scala/com/twitter/storehaus/cache/HHFilteredCacheTest.scala index 08b6c3e4..a0042b03 100644 --- a/storehaus-cache/src/test/scala/com/twitter/storehaus/cache/HHFilteredCacheTest.scala +++ b/storehaus-cache/src/test/scala/com/twitter/storehaus/cache/HHFilteredCacheTest.scala @@ -16,14 +16,14 @@ package com.twitter.storehaus.cache -import org.specs2.mutable._ +import org.scalatest.{Matchers, WordSpec} -class HHFilteredCacheTest extends Specification { +class HHFilteredCacheTest extends WordSpec with Matchers { def checkCache[K, V](pairs: Seq[(K, V)], m: Map[K, V])(implicit cache: MutableCache[K, V]) = { pairs.foldLeft(cache)(_ += _) val res = cache.iterator.toMap cache.clear - res must be_==(m) + res should equal(m) } "HHFilteredCache works properly" in { diff --git a/storehaus-cache/src/test/scala/com/twitter/storehaus/cache/LRUCacheTest.scala b/storehaus-cache/src/test/scala/com/twitter/storehaus/cache/LRUCacheTest.scala index 24cd3cc3..0941c83e 100644 --- a/storehaus-cache/src/test/scala/com/twitter/storehaus/cache/LRUCacheTest.scala +++ b/storehaus-cache/src/test/scala/com/twitter/storehaus/cache/LRUCacheTest.scala @@ -16,11 +16,11 @@ package com.twitter.storehaus.cache -import org.specs2.mutable._ +import org.scalatest.{Matchers, WordSpec} -class LRUCacheTest extends Specification { +class LRUCacheTest extends WordSpec with Matchers { def checkCache[K, V](pairs: Seq[(K, V)], m: Map[K, V])(implicit cache: Cache[K, V]) = - pairs.foldLeft(cache)(_ + _).toMap must be_==(m) + pairs.foldLeft(cache)(_ + _).toMap should equal(m) "LRUCache works properly with threshold 2" in { implicit val cache = Cache.lru[String, Int](2) @@ -36,7 +36,7 @@ class LRUCacheTest extends Specification { Seq("a" -> 1, "b" -> 2, "b" -> 3), Map("a" -> 1, "b" -> 3) ) - ((cache + ("a" -> 1) + ("b" -> 2)).hit("a") + ("c" -> 3)).toMap - .must(be_==(Map("a" -> 1, "c" -> 3))) + val result = ((cache + ("a" -> 1) + ("b" -> 2)).hit("a") + ("c" -> 3)).toMap + result should equal(Map("a" -> 1, "c" -> 3)) } } diff --git a/storehaus-cache/src/test/scala/com/twitter/storehaus/cache/MutableLRUCacheTest.scala b/storehaus-cache/src/test/scala/com/twitter/storehaus/cache/MutableLRUCacheTest.scala index 9abf39fc..200b5c7b 100644 --- a/storehaus-cache/src/test/scala/com/twitter/storehaus/cache/MutableLRUCacheTest.scala +++ b/storehaus-cache/src/test/scala/com/twitter/storehaus/cache/MutableLRUCacheTest.scala @@ -16,15 +16,15 @@ package com.twitter.storehaus.cache -import org.specs2.mutable._ +import org.scalatest.{Matchers, WordSpec} -class MutableLRUCacheTest extends Specification { +class MutableLRUCacheTest extends WordSpec with Matchers { def freshCache = MutableLRUCache[String, Int](2) def checkCache(pairs: Seq[(String, Int)], results: Seq[Boolean]) = { val cache = freshCache pairs.foreach(cache += _) - pairs.map { case (k, _) => cache.contains(k) } must be_==(results) + pairs.map { case (k, _) => cache.contains(k) } should equal(results) } "MutableLRUCache works properly with threshold 2" in { diff --git a/storehaus-cache/src/test/scala/com/twitter/storehaus/cache/MutableTTLCacheTest.scala b/storehaus-cache/src/test/scala/com/twitter/storehaus/cache/MutableTTLCacheTest.scala index 385e18c5..3c190965 100644 --- a/storehaus-cache/src/test/scala/com/twitter/storehaus/cache/MutableTTLCacheTest.scala +++ b/storehaus-cache/src/test/scala/com/twitter/storehaus/cache/MutableTTLCacheTest.scala @@ -16,28 +16,28 @@ package com.twitter.storehaus.cache -import org.specs2.mutable._ +import org.scalatest.{Matchers, WordSpec} import com.twitter.util.Duration -class MutableTTLCacheTest extends Specification { +class MutableTTLCacheTest extends WordSpec with Matchers { "TTLCache exhibits proper TTL-ness" in { val ttl: Duration = Duration.fromMilliseconds(500) val cache = MutableCache.ttl[String, Int](ttl, 100) cache += ("a" -> 1) cache += ("b" -> 2) - cache.toNonExpiredMap must be_==(Map("a" -> 1, "b" -> 2)) + cache.toNonExpiredMap should equal(Map("a" -> 1, "b" -> 2)) Thread.sleep(ttl.inMilliseconds) cache += ("c" -> 3) - cache.toNonExpiredMap must be_==(Map("c" -> 3)) + cache.toNonExpiredMap should equal(Map("c" -> 3)) } "TTLCache does not return an expired value" in { val ttl: Duration = Duration.fromMilliseconds(500) val cache = MutableCache.ttl[String, Int](ttl, 100) cache += ("a" -> 10) - cache.get("a") must be_==(Some(10)) + cache.get("a") should equal(Some(10)) Thread.sleep(ttl.inMilliseconds) - cache.get("a") must be_==(None) + cache.get("a") should equal(None) } } diff --git a/storehaus-cache/src/test/scala/com/twitter/storehaus/cache/TTLCacheTest.scala b/storehaus-cache/src/test/scala/com/twitter/storehaus/cache/TTLCacheTest.scala index 1c915dec..9bc66585 100644 --- a/storehaus-cache/src/test/scala/com/twitter/storehaus/cache/TTLCacheTest.scala +++ b/storehaus-cache/src/test/scala/com/twitter/storehaus/cache/TTLCacheTest.scala @@ -16,25 +16,24 @@ package com.twitter.storehaus.cache -import org.specs2.mutable._ +import org.scalatest.{Matchers, WordSpec} import com.twitter.util.Duration - -class TTLCacheTest extends Specification { +class TTLCacheTest extends WordSpec with Matchers { val ttlMS = 600 val cache = Cache.ttl[String, Int](Duration.fromMilliseconds(ttlMS)) "TTLCache exhibits proper TTL-ness" in { val abCache = cache.putClocked("a" -> 1)._2.putClocked("b" -> 2)._2 - abCache.toNonExpiredMap must be_==(Map("a" -> 1, "b" -> 2)) + abCache.toNonExpiredMap should equal(Map("a" -> 1, "b" -> 2)) Thread.sleep(ttlMS) - (abCache.putClocked("c" -> 3)._2).toNonExpiredMap must be_==(Map("c" -> 3)) + (abCache.putClocked("c" -> 3)._2).toNonExpiredMap should equal(Map("c" -> 3)) } "TTLCache does not return an expired value" in { val withV = cache.putClocked("a" -> 10)._2 - withV.getNonExpired("a") must be_==(Some(10)) + withV.getNonExpired("a") should equal(Some(10)) Thread.sleep(ttlMS) - withV.getNonExpired("a") must be_==(None) + withV.getNonExpired("a") should equal(None) } } diff --git a/storehaus-elasticsearch/src/test/scala/com/twitter/storehaus/elasticsearch/DefaultElasticContext.scala b/storehaus-elasticsearch/src/test/scala/com/twitter/storehaus/elasticsearch/DefaultElasticContext.scala index eabf89b3..778a35c2 100644 --- a/storehaus-elasticsearch/src/test/scala/com/twitter/storehaus/elasticsearch/DefaultElasticContext.scala +++ b/storehaus-elasticsearch/src/test/scala/com/twitter/storehaus/elasticsearch/DefaultElasticContext.scala @@ -20,15 +20,13 @@ import org.elasticsearch.common.settings.ImmutableSettings import java.util.UUID import java.io.File import org.elasticsearch.node.NodeBuilder._ -import org.specs2.specification.Scope import org.json4s.{native, NoTypeHints} - /** * @author Mansur Ashraf * @since 1/13/14 */ -trait DefaultElasticContext extends Scope { +trait DefaultElasticContext { val tempFile = File.createTempFile("elasticsearchtests", "tmp") val homeDir = new File(tempFile.getParent + "/" + UUID.randomUUID().toString) diff --git a/storehaus-elasticsearch/src/test/scala/com/twitter/storehaus/elasticsearch/ElasticSearchStoreSpecs.scala b/storehaus-elasticsearch/src/test/scala/com/twitter/storehaus/elasticsearch/ElasticSearchStoreSpecs.scala index 18dd8336..9b87f907 100644 --- a/storehaus-elasticsearch/src/test/scala/com/twitter/storehaus/elasticsearch/ElasticSearchStoreSpecs.scala +++ b/storehaus-elasticsearch/src/test/scala/com/twitter/storehaus/elasticsearch/ElasticSearchStoreSpecs.scala @@ -16,7 +16,7 @@ package com.twitter.storehaus.elasticsearch -import org.specs2.mutable.Specification +import org.scalatest.{OneInstancePerTest, Matchers, WordSpec} import com.twitter.util.{Future, Await} import com.twitter.storehaus.FutureOps import org.elasticsearch.action.search.SearchRequestBuilder @@ -28,8 +28,7 @@ import org.json4s.{native, NoTypeHints} * @author Mansur Ashraf * @since 1/13/14 */ -class ElasticSearchStoreSpecs extends Specification { - sequential +class ElasticSearchStoreSpecs extends WordSpec with Matchers with OneInstancePerTest with DefaultElasticContext { private implicit val formats = native.Serialization.formats(NoTypeHints) @@ -37,49 +36,49 @@ class ElasticSearchStoreSpecs extends Specification { "ElasticSearch Store" should { - "Put a value" in new DefaultElasticContext { - private val key = "put_key" + "Put a value" in { + val key = "put_key" store.put((key, Some(person))) blockAndRefreshIndex val result = Await.result(store.get(key)) - result === Some(person) + result should equal(Some(person)) } - "Retrieve a value that doesnt exist" in new DefaultElasticContext { - private val key = "put_key" + "Retrieve a value that doesnt exist" in { + val key = "put_key" store.put((key, Some(person))) blockAndRefreshIndex val result = Await.result(store.get("missing_key")) - result === None + result should equal(None) } - "Update a value" in new DefaultElasticContext { - private val key = "update_key" + "Update a value" in { + val key = "update_key" store.put(key, Some(person)) store.put(key, Some(person.copy(age = 30))) blockAndRefreshIndex val result = Await.result(store.get(key)) - result === Some(person.copy(age = 30)) + result should equal(Some(person.copy(age = 30))) } "Delete a value" in new DefaultElasticContext { - private val key = "delete_key" + val key = "delete_key" store.put(key, Some(person)) store.put(key, None) blockAndRefreshIndex val result = Await.result(store.get(key)) - result === None + result should equal (None) } - "Put multiple values" in new DefaultElasticContext { + "Put multiple values" in { val key = "_put_key" val persons = (1 to 10).map(i => i + key -> Some(person.copy(age = i))).toMap @@ -89,10 +88,10 @@ class ElasticSearchStoreSpecs extends Specification { val response = store.multiGet(persons.keySet) val result = Await.result(FutureOps.mapCollect(response)) - result === persons + result should equal (persons) } - "Retrieve values that do not exist" in new DefaultElasticContext { + "Retrieve values that do not exist" in { val key = "_put_key" val persons = (1 to 10).map(i => i + key -> Some(person.copy(age = i))).toMap @@ -102,10 +101,10 @@ class ElasticSearchStoreSpecs extends Specification { val response = store.multiGet(Set[String]()) val result = Await.result(FutureOps.mapCollect(response)) - result === Map[String,Future[Option[String]]]() + result should equal(Map[String,Future[Option[String]]]()) } - "Update multiple values" in new DefaultElasticContext { + "Update multiple values" in { val key = "_update_key" val persons = (1 to 10).map(i => i + key -> Some(person.copy(age = i))).toMap @@ -117,10 +116,10 @@ class ElasticSearchStoreSpecs extends Specification { val response = store.multiGet(persons_updated.keySet) val result = Await.result(FutureOps.mapCollect(response)) - result === persons_updated + result should equal(persons_updated) } - "Delete multiple values" in new DefaultElasticContext { + "Delete multiple values" in { val key = "_delete_key" val persons = (1 to 10).map(i => i + key -> Some(person.copy(age = i))).toMap @@ -132,10 +131,10 @@ class ElasticSearchStoreSpecs extends Specification { val response = store.multiGet(deleted_persons.keySet) val result = Await.result(FutureOps.mapCollect(response)) - result === deleted_persons + result should equal(deleted_persons) } - "Search for values" in new DefaultElasticContext { + "Search for values" in { val bookStore = ElasticSearchCaseClassStore[Book]("books", "programming", client) val books = Map( @@ -152,8 +151,8 @@ class ElasticSearchStoreSpecs extends Specification { //search for a particular author val request1 = new SearchRequestBuilder(client).setQuery(termQuery("authors", "josh")).request() val response1 = Await.result(bookStore.queryable.get(request1)) - response1 !== None - response1.get.head.name === "Effective Java" + response1 should not equal(None) + response1.get.head.name should equal("Effective Java") //find all the books published after 2001 where author is not Josh Bloch @@ -167,8 +166,8 @@ class ElasticSearchStoreSpecs extends Specification { ).request() val response2 = Await.result(bookStore.queryable.get(request2)) - response2 !== None - response2.get.size === 2 + response2 should not equal(None) + response2.get.size should equal(2) } } diff --git a/storehaus-redis/src/test/scala/com/twitter/storehaus/redis/RedisSortedSetSpec.scala b/storehaus-redis/src/test/scala/com/twitter/storehaus/redis/RedisSortedSetSpec.scala index ceb1c47d..050ba889 100644 --- a/storehaus-redis/src/test/scala/com/twitter/storehaus/redis/RedisSortedSetSpec.scala +++ b/storehaus-redis/src/test/scala/com/twitter/storehaus/redis/RedisSortedSetSpec.scala @@ -6,10 +6,10 @@ import com.twitter.storehaus.algebra.MergeableStore import com.twitter.storehaus.testing.CloseableCleanup import com.twitter.util.{ Await, Future } import org.jboss.netty.buffer.ChannelBuffer -import org.specs2.mutable._ +import org.scalatest.{Matchers, WordSpec} import scala.util.Try -class RedisSortedSetSpec extends Specification +class RedisSortedSetSpec extends WordSpec with Matchers with CloseableCleanup[RedisSortedSetStore] with DefaultRedisClient { import com.twitter.bijection.Bijection._ @@ -38,14 +38,12 @@ class RedisSortedSetSpec extends Specification if (xs.isEmpty) None else Some(xs.init, xs.last) } - sequential // Required as tests mutate the store in order - "RedisSortedSet" should { "support Store operations" in { Await.result(for { put <- sets.put(("commits", Some(commits))) commits <- sets.get("commits") - } yield commits) must beSome(commits.sortWith(_._2 < _._2)) + } yield commits) should be(Some(commits.sortWith(_._2 < _._2))) } "support merge operations" in { @@ -53,14 +51,14 @@ class RedisSortedSetSpec extends Specification _ <- sets.merge(("commits", Seq(("sritchie", 1.0)))) commits <- sets.get("commits") } yield commits) - (for (_ ::> last <- merged) yield last) must beSome( - ("sritchie", 138.0)) + (for (_ ::> last <- merged) yield last) should be(Some( + ("sritchie", 138.0))) } "support delete operation" in { Await.result(for { _ <- sets.put(("commits", None)) commits <- sets.get("commits") - } yield commits) must beNone + } yield commits) should be(None) } } @@ -74,7 +72,7 @@ class RedisSortedSetSpec extends Specification Await.result(Future.collect(members.multiPut(putting).values.toSeq)) putting.foreach { case (k, v) => - Await.result(members.get(k)) aka("key %s" format k) must_==(v) + Await.result(members.get(k)) should equal(v) } } "support merge operations" in { @@ -82,14 +80,14 @@ class RedisSortedSetSpec extends Specification Await.result(for { _ <- members.merge((who, 1.0)) score <- members.get(who) - } yield score) aka("score of %s" format who) must beSome(138.0) + } yield score) should be(Some(138.0)) } "support delete operation" in { val who = ("commits", "sritchie") Await.result(for { _ <- members.put((who, None)) score <- members.get(who) - } yield score) aka("score of %s" format who) must beNone + } yield score) should be(None) } } }