Skip to content
This repository has been archived by the owner on Sep 18, 2021. It is now read-only.

Commit

Permalink
Merge pull request #46 from twitter/birdcageable
Browse files Browse the repository at this point in the history
changes to allow mirroring in the birdcage, building in CI, and using latest finagle and util.

everything should continue to work normally when not in the birdcage, but if there are any problems, just ping me!
  • Loading branch information
Jeremy Cloud committed Mar 28, 2012
2 parents 35407a1 + 6d4c8fa commit b6cbe0c
Show file tree
Hide file tree
Showing 11 changed files with 241 additions and 180 deletions.
27 changes: 17 additions & 10 deletions project/build/QuerulousProject.scala
@@ -1,9 +1,12 @@
import sbt._
import com.twitter.sbt._

class QuerulousProject(info: ProjectInfo) extends StandardParentProject(info)
with DefaultRepos
with SubversionPublisher {
class QuerulousProject(info: ProjectInfo)
extends StandardParentProject(info)
with DefaultRepos
with SubversionPublisher
with ParentProjectDependencies
{

lazy val coreProject = project(
"querulous-core", "querulous-core",
Expand All @@ -28,16 +31,16 @@ with SubversionPublisher {
with DefaultRepos
with SubversionPublisher

val utilVersion = "1.12.13"
val finagleVersion = "1.11.0"

class CoreProject(info: ProjectInfo) extends StandardLibraryProject(info) with Defaults {
val utilCore = "com.twitter" % "util-core" % utilVersion
projectDependencies(
"util" ~ "util-core"
)

val dbcp = "commons-dbcp" % "commons-dbcp" % "1.4"
val mysqljdbc = "mysql" % "mysql-connector-java" % "5.1.18"
val pool = "commons-pool" % "commons-pool" % "1.5.4"

val utilEval = "com.twitter" % "util-eval" % utilVersion % "test"
val utilEval = "com.twitter" % "util-eval" % "3.0.0" % "test"
val scalaTools = "org.scala-lang" % "scala-compiler" % "2.8.1" % "test"
val hamcrest = "org.hamcrest" % "hamcrest-all" % "1.1" % "test"
val specs = "org.scala-tools.testing" % "specs_2.8.0" % "1.6.5" % "test"
Expand All @@ -49,12 +52,16 @@ with SubversionPublisher {
}

class TracingProject(info: ProjectInfo) extends StandardLibraryProject(info) with Defaults {
val finagle = "com.twitter" % "finagle-core" % finagleVersion
projectDependencies(
"finagle" ~ "finagle-core"
)
}

class Ostrich4Project(info: ProjectInfo) extends StandardLibraryProject(info) with Defaults {
// rely on finagle to pull in ostrich, for compat w/ tracing version.
val ostrich = "com.twitter" % "finagle-ostrich4" % finagleVersion
projectDependencies(
"finagle" ~ "finagle-ostrich4"
)
}

override def subversionRepository = Some("https://svn.twitter.biz/maven-public/")
Expand Down
17 changes: 15 additions & 2 deletions project/plugins/Plugins.scala
@@ -1,6 +1,19 @@
import sbt._
import scala.collection.jcl

class Plugins(info: ProjectInfo) extends PluginDefinition(info) {
val twitter = "twitter.com" at "http://maven.twttr.com/"
val standardProject = "com.twitter" % "standard-project" % "0.12.7"
val environment = jcl.Map(System.getenv())
def isSBTOpenTwitter = environment.get("SBT_OPEN_TWITTER").isDefined
def isSBTTwitter = environment.get("SBT_TWITTER").isDefined

override def repositories = if (isSBTOpenTwitter) {
Set("twitter.artifactory" at "http://artifactory.local.twitter.com/open-source/")
} else if (isSBTTwitter) {
Set("twitter.artifactory" at "http://artifactory.local.twitter.com/repo/")
} else {
super.repositories ++ Seq("twitter.com" at "http://maven.twttr.com/")
}
override def ivyRepositories = Seq(Resolver.defaultLocal(None)) ++ repositories

val defaultProject = "com.twitter" % "standard-project" % "1.0.4"
}
8 changes: 8 additions & 0 deletions project/versions.properties
@@ -0,0 +1,8 @@
#Automatically generated by ProjectDependencies
#Wed Jan 25 09:06:45 PST 2012
com.twitter/finagle-core=3.0.0
com.twitter/finagle-ostrich4=3.0.0
com.twitter/util-core=3.0.0
finagle|finagle-core=com.twitter/finagle-core
finagle|finagle-ostrich4=com.twitter/finagle-ostrich4
util|util-core=com.twitter/util-core
Expand Up @@ -4,21 +4,41 @@ import com.twitter.querulous.database.SingleConnectionDatabaseFactory
import com.twitter.querulous.query.SqlQueryFactory
import com.twitter.querulous.evaluator.{QueryEvaluator, StandardQueryEvaluatorFactory}
import com.twitter.util.Eval
import java.io.File
import java.io.{File, FileNotFoundException}
import java.util.concurrent.CountDownLatch
import org.specs.Specification

import config.Connection

trait ConfiguredSpecification extends Specification {
val config = try {
lazy val config = try {
val eval = new Eval
eval[Connection](new File("config/test.scala"))
// if this repo is embedded in other repo (eg. birdcage), test.scala will be
// one level deeper than if running in a detached repo mode.
val configFile =
Some(new File("querulous/config/test.scala")) filter { _.exists } orElse {
Some(new File("config/test.scala")) filter { _.exists }
} getOrElse {
throw new FileNotFoundException("config/test.scala")
}
eval[Connection](configFile)
} catch {
case e =>
e.printStackTrace()
throw e
}

/**
* Wrap a test in this method to prevent it from running when on the CI machine.
* Some tests require a local mysqld, and will fail if executed on the CI machine.
*/
def skipIfCI(f: => Unit) {
if (System.getenv().containsKey("SBT_CI")) {
skip("skipping on CI machine")
} else {
f
}
}
}

object TestEvaluator {
Expand Down
Expand Up @@ -15,51 +15,53 @@ class QuerySpec extends ConfiguredSpecification {
val queryEvaluator = testEvaluatorFactory(config)

"Query" should {
doBefore {
queryEvaluator.execute("CREATE TABLE IF NOT EXISTS foo(bar INT, baz INT)")
queryEvaluator.execute("TRUNCATE foo")
queryEvaluator.execute("INSERT INTO foo VALUES (1,1), (3,3)")
}
skipIfCI {
doBefore {
queryEvaluator.execute("CREATE TABLE IF NOT EXISTS foo(bar INT, baz INT)")
queryEvaluator.execute("TRUNCATE foo")
queryEvaluator.execute("INSERT INTO foo VALUES (1,1), (3,3)")
}

"with too many arguments" >> {
queryEvaluator.select("SELECT 1 FROM DUAL WHERE 1 IN (?)", 1, 2, 3) { r => 1 } must throwA[TooManyQueryParametersException]
}
"with too many arguments" >> {
queryEvaluator.select("SELECT 1 FROM DUAL WHERE 1 IN (?)", 1, 2, 3) { r => 1 } must throwA[TooManyQueryParametersException]
}

"with too few arguments" >> {
queryEvaluator.select("SELECT 1 FROM DUAL WHERE 1 = ? OR 1 = ?", 1) { r => 1 } must throwA[TooFewQueryParametersException]
}
"with too few arguments" >> {
queryEvaluator.select("SELECT 1 FROM DUAL WHERE 1 = ? OR 1 = ?", 1) { r => 1 } must throwA[TooFewQueryParametersException]
}

"in batch mode" >> {
queryEvaluator.executeBatch("UPDATE foo SET bar = ? WHERE bar = ?") { withParams =>
withParams("2", "1")
withParams("3", "3")
} mustEqual 2
}
"in batch mode" >> {
queryEvaluator.executeBatch("UPDATE foo SET bar = ? WHERE bar = ?") { withParams =>
withParams("2", "1")
withParams("3", "3")
} mustEqual 2
}

"add annotations" >> {
val connection = testDatabaseFactory(config.hostnames.toList, config.database, config.username,
config.password, config.urlOptions, config.driverName).open()
"add annotations" >> {
val connection = testDatabaseFactory(config.hostnames.toList, config.database, config.username,
config.password, config.urlOptions, config.driverName).open()

try {
val query = testQueryFactory(connection, QueryClass.Select, "SELECT 1")
query.addAnnotation("key", "value")
query.addAnnotation("key2", "value2")
query.select(rv => rv.getInt(1) mustEqual 1)
} finally {
connection.close()
try {
val query = testQueryFactory(connection, QueryClass.Select, "SELECT 1")
query.addAnnotation("key", "value")
query.addAnnotation("key2", "value2")
query.select(rv => rv.getInt(1) mustEqual 1)
} finally {
connection.close()
}
}
}

"with just the right number of arguments" >> {
queryEvaluator.select("SELECT 1 FROM DUAL WHERE 1 IN (?)", List(1, 2, 3))(_.getInt(1)).toList mustEqual List(1)
}
"with just the right number of arguments" >> {
queryEvaluator.select("SELECT 1 FROM DUAL WHERE 1 IN (?)", List(1, 2, 3))(_.getInt(1)).toList mustEqual List(1)
}

"be backwards compatible" >> {
val noOpts = testEvaluatorFactory(config.hostnames.toList, null, config.username, config.password)
noOpts.select("SELECT 1 FROM DUAL WHERE 1 IN (?)", List(1, 2, 3))(_.getInt(1)).toList mustEqual List(1)
"be backwards compatible" >> {
val noOpts = testEvaluatorFactory(config.hostnames.toList, null, config.username, config.password)
noOpts.select("SELECT 1 FROM DUAL WHERE 1 IN (?)", List(1, 2, 3))(_.getInt(1)).toList mustEqual List(1)

val noDBNameOrOpts = testEvaluatorFactory(config.hostnames.toList, config.username, config.password)
noDBNameOrOpts.select("SELECT 1 FROM DUAL WHERE 1 IN (?)", List(1, 2, 3))(_.getInt(1)).toList mustEqual List(1)
val noDBNameOrOpts = testEvaluatorFactory(config.hostnames.toList, config.username, config.password)
noDBNameOrOpts.select("SELECT 1 FROM DUAL WHERE 1 IN (?)", List(1, 2, 3))(_.getInt(1)).toList mustEqual List(1)
}
}
}
}
Expand Up @@ -15,24 +15,26 @@ object ThrottledPoolingDatabaseSpec {
class ThrottledPoolingDatabaseSpec extends ConfiguredSpecification {
import ThrottledPoolingDatabaseSpec._

val queryEvaluator = testEvaluatorFactory(config)

"ThrottledJdbcPoolSpec" should {
"execute some queries" >> {
queryEvaluator.select("SELECT 1 FROM DUAL") { _.getInt(1) } mustEqual List(1)
queryEvaluator.select("SELECT 2 FROM DUAL") { _.getInt(1) } mustEqual List(2)
}
skipIfCI {
val queryEvaluator = testEvaluatorFactory(config)

"timeout when attempting to get a second connection" >> {
queryEvaluator.select("SELECT 1 FROM DUAL") { r =>
queryEvaluator.select("SELECT 2 FROM DUAL") { r2 => } must throwA[SqlDatabaseTimeoutException]
"execute some queries" >> {
queryEvaluator.select("SELECT 1 FROM DUAL") { _.getInt(1) } mustEqual List(1)
queryEvaluator.select("SELECT 2 FROM DUAL") { _.getInt(1) } mustEqual List(2)
}
}

"ejects idle connections" >> {
queryEvaluator.execute("set session wait_timeout = 1")
Thread.sleep(2.seconds.inMillis)
queryEvaluator.select("SELECT 1 FROM DUAL") { _.getInt(1) } mustEqual List(1)
"timeout when attempting to get a second connection" >> {
queryEvaluator.select("SELECT 1 FROM DUAL") { r =>
queryEvaluator.select("SELECT 2 FROM DUAL") { r2 => } must throwA[SqlDatabaseTimeoutException]
}
}

"ejects idle connections" >> {
queryEvaluator.execute("set session wait_timeout = 1")
Thread.sleep(2.seconds.inMillis)
queryEvaluator.select("SELECT 1 FROM DUAL") { _.getInt(1) } mustEqual List(1)
}
}
}
}
Expand Up @@ -18,31 +18,33 @@ class TimeoutSpec extends ConfiguredSpecification {
val timingOutQueryEvaluatorFactory = new StandardQueryEvaluatorFactory(testDatabaseFactory, timingOutQueryFactory)

"Timeouts" should {
doBefore {
testEvaluatorFactory(config.withoutDatabase).execute("CREATE DATABASE IF NOT EXISTS db_test")
}

"honor timeouts" in {
val queryEvaluator1 = testEvaluatorFactory(config)
val dbLock = getDbLock(queryEvaluator1, "padlock")
skipIfCI {
doBefore {
testEvaluatorFactory(config.withoutDatabase).execute("CREATE DATABASE IF NOT EXISTS db_test")
}

val thread = new Thread() {
override def run() {
try {
Thread.sleep(60.seconds.inMillis)
} catch { case _ => () }
dbLock.countDown()
"honor timeouts" in {
val queryEvaluator1 = testEvaluatorFactory(config)
val dbLock = getDbLock(queryEvaluator1, "padlock")

val thread = new Thread() {
override def run() {
try {
Thread.sleep(60.seconds.inMillis)
} catch { case _ => () }
dbLock.countDown()
}
}
thread.start()

val queryEvaluator2 = timingOutQueryEvaluatorFactory(config)
val start = Time.now
queryEvaluator2.select("SELECT GET_LOCK('padlock', 60) AS rv") { row => row.getInt("rv") } must throwA[SqlQueryTimeoutException]
val end = Time.now
(end - start).inMillis must beCloseTo(timeout.inMillis, 1.second.inMillis)
thread.interrupt()
thread.join()
}
thread.start()

val queryEvaluator2 = timingOutQueryEvaluatorFactory(config)
val start = Time.now
queryEvaluator2.select("SELECT GET_LOCK('padlock', 60) AS rv") { row => row.getInt("rv") } must throwA[SqlQueryTimeoutException]
val end = Time.now
(end - start).inMillis must beCloseTo(timeout.inMillis, 1.second.inMillis)
thread.interrupt()
thread.join()
}
}
}
Expand Up @@ -42,15 +42,19 @@ class DatabaseSpec extends ConfiguredSpecification with JMocker with ClassMocker
}

"SingleConnectionDatabaseFactory" should {
val factory = new SingleConnectionDatabaseFactory(defaultProps)
testFactory(factory)
skipIfCI {
val factory = new SingleConnectionDatabaseFactory(defaultProps)
testFactory(factory)
}
}

"ApachePoolingDatabaseFactory" should {
val factory = new ApachePoolingDatabaseFactory(
10, 10, 1.second, 10.millis, false, 0.seconds, defaultProps
)
skipIfCI {
val factory = new ApachePoolingDatabaseFactory(
10, 10, 1.second, 10.millis, false, 0.seconds, defaultProps
)

testFactory(factory)
testFactory(factory)
}
}
}

0 comments on commit b6cbe0c

Please sign in to comment.