From 4fe0de64dc5041450cae8ac2d49b702f5163975b Mon Sep 17 00:00:00 2001 From: Rohit Rai Date: Fri, 23 Oct 2015 00:44:23 -0700 Subject: [PATCH 01/14] Local tar support --- build.sbt | 13 +++++++++---- .../hochgi/sbt/cassandra/CassandraPlugin.scala | 10 +++++++--- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/build.sbt b/build.sbt index 60cf904..a976e07 100644 --- a/build.sbt +++ b/build.sbt @@ -1,12 +1,12 @@ sbtPlugin := true -organization := "com.github.hochgi" +organization := "com.tuplejump.com.github.hochgi" name := "sbt-cassandra-plugin" description := "SBT plugin to allow launching Cassandra during tests, and test your application against it" -version := "0.6.1" +version := "0.6.2" scalaVersion := "2.10.4" @@ -40,8 +40,8 @@ licenses := Seq("The MIT License (MIT)" -> url("http://opensource.org/licenses/M pomExtra := ( - https://github.com/hochgi/sbt-cassandra-plugin.git - scm:git@github.com:hochgi/sbt-cassandra-plugin.git + https://github.com/tuplejump/sbt-cassandra-plugin.git + scm:git@github.com:tuplejump/sbt-cassandra-plugin.git @@ -49,5 +49,10 @@ pomExtra := ( Gilad Hoch http://hochgi.blogspot.com + + milliondreams + Rohit Rai + http://www.twitter.com/milliondreams + ) diff --git a/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraPlugin.scala b/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraPlugin.scala index be7210c..7208e30 100644 --- a/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraPlugin.scala +++ b/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraPlugin.scala @@ -16,6 +16,7 @@ object CassandraPlugin extends Plugin { private[this] val defaultConfigDir = "NO_DIR_SUPPLIED" private[this] val defaultCliInit = "NO_CLI_COMMANDS_SUPPLIED" private[this] val defaultCqlInit = "NO_CQL_COMMANDS_SUPPLIED" + //private[this] val defaultTarBall = "GET_FROM_MAVEN" val cassandraVersion = SettingKey[String]("cassandra-version") val cassandraConfigDir = SettingKey[String]("cassandra-config-dir") @@ -33,6 +34,7 @@ object CassandraPlugin extends Plugin { val cleanCassandraAfterStop = SettingKey[Boolean]("stop-cassandra-after-tests") val cassandraPid = TaskKey[String]("cassandra-pid") val stopCassandra = TaskKey[Unit]("stop-cassandra") + val cassandraTgz = SettingKey[String]("cassandra-tgz") val cassandraSettings = Seq( cassandraHost := "localhost", @@ -68,13 +70,15 @@ object CassandraPlugin extends Plugin { else oldPort } }, + cassandraTgz := "", classpathTypes ~= (_ + "tar.gz"), libraryDependencies += { "org.apache.cassandra" % "apache-cassandra" % cassandraVersion.value artifacts(Artifact("apache-cassandra", "tar.gz", "tar.gz","bin")) intransitive() }, - deployCassandra <<= (cassandraVersion, target, dependencyClasspath in Runtime, streams) map { - case (ver, targetDir, classpath, streams) => { - val cassandraTarGz = Attributed.data(classpath).find(_.getName == s"apache-cassandra-$ver-bin.tar.gz").get + deployCassandra <<= (cassandraVersion, target, dependencyClasspath in Runtime, streams, cassandraTgz) map { + case (ver, targetDir, classpath, streams, ctgz) => { + val cassandraTarGz:File = if(ctgz.nonEmpty) file(ctgz) else Attributed.data(classpath).find(_.getName == s"apache-cassandra-$ver-bin.tar.gz").get + if (cassandraTarGz == null) sys.error("could not load: cassandra tar.gz file.") streams.log.info(s"cassandraTarGz: ${cassandraTarGz.getAbsolutePath}") Process(Seq("tar","-xzf",cassandraTarGz.getAbsolutePath),targetDir).! From da107788f30beb506f739c7ef41ca2d44b1ad135 Mon Sep 17 00:00:00 2001 From: Rohit Rai Date: Wed, 28 Oct 2015 21:54:15 -0700 Subject: [PATCH 02/14] removing cli initialization --- .../sbt/cassandra/CassandraPlugin.scala | 40 +++++++++---------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraPlugin.scala b/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraPlugin.scala index 7208e30..7a14c3d 100644 --- a/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraPlugin.scala +++ b/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraPlugin.scala @@ -14,7 +14,6 @@ object CassandraPlugin extends Plugin { //defaults: private[this] val defaultConfigDir = "NO_DIR_SUPPLIED" - private[this] val defaultCliInit = "NO_CLI_COMMANDS_SUPPLIED" private[this] val defaultCqlInit = "NO_CQL_COMMANDS_SUPPLIED" //private[this] val defaultTarBall = "GET_FROM_MAVEN" @@ -35,7 +34,8 @@ object CassandraPlugin extends Plugin { val cassandraPid = TaskKey[String]("cassandra-pid") val stopCassandra = TaskKey[Unit]("stop-cassandra") val cassandraTgz = SettingKey[String]("cassandra-tgz") - + val addLibJars = SettingKey[Seq[File]]("additional-lib-jars") + val cassandraSettings = Seq( cassandraHost := "localhost", cassandraPort := "9160", @@ -57,7 +57,6 @@ object CassandraPlugin extends Plugin { } }, cassandraConfigDir := defaultConfigDir, - cassandraCliInit := defaultCliInit, cassandraCqlInit := defaultCqlInit, stopCassandraAfterTests := true, cleanCassandraAfterStop := true, @@ -98,10 +97,13 @@ object CassandraPlugin extends Plugin { cassHome } }, - startCassandra <<= (target, deployCassandra, cassandraConfigDir,cassandraCliInit,cassandraCqlInit,cassandraHost,cassandraPort,cassandraCqlPort, cassandraStartDeadline, configMappings, streams) map { - case (targetDir, cassHome, confDirAsString, cli, cql, host, port, cqlPort, startDeadline, confMappings, streams) => { + startCassandra <<= (target, deployCassandra, cassandraConfigDir, + cassandraCqlInit, cassandraHost, cassandraPort, cassandraCqlPort, cassandraStartDeadline, + configMappings, streams) map { + + case (targetDir, cassHome, confDirAsString, cql, host, port, cqlPort, startDeadline, confMappings, outStreams) => { val pidFile = targetDir / "cass.pid" - val jarClasspath = sbt.IO.listFiles(cassHome / "lib").collect{case f: File if f.getName.endsWith(".jar") => f.getAbsolutePath}.mkString(":") + val jarClasspath = (sbt.IO.listFiles(cassHome / "lib")).collect{case f: File if f.getName.endsWith(".jar") => f.getAbsolutePath}.mkString(":") val conf: String = { if(confDirAsString == defaultConfigDir) { val configDir = cassHome / "conf" @@ -111,15 +113,15 @@ object CassandraPlugin extends Plugin { val classpath = conf + ":" + jarClasspath val bin = cassHome / "bin" / "cassandra" val args = Seq(bin.getAbsolutePath, "-p", pidFile.getAbsolutePath) - overrideConfigs(conf, confMappings, streams.log) + overrideConfigs(conf, confMappings, outStreams.log) if (!isCassandraRunning(port)) { Process(args, cassHome, "CASSANDRA_CONF" -> conf, "CASSANDRA_HOME" -> cassHome.getAbsolutePath).run - streams.log.info("going to wait for cassandra:") - waitForCassandra(port, startDeadline, (s: String) => streams.log.info(s)) - streams.log.info("going to initialize cassandra:") - initCassandra(cli, cql, classpath, cassHome, host, port, cqlPort) + outStreams.log.info("going to wait for cassandra:") + waitForCassandra(port, startDeadline, (s: String) => outStreams.log.info(s)) + outStreams.log.info("going to initialize cassandra:") + initCassandra(cql, classpath, cassHome, host, port, cqlPort) } else { - streams.log.warn("cassandra already running") + outStreams.log.warn("cassandra already running") } val pid = Try(sbt.IO.read(pidFile).filterNot(_.isWhitespace)).getOrElse("NO PID") cassandraPid := pid @@ -210,16 +212,10 @@ object CassandraPlugin extends Plugin { } } - def initCassandra(cli: String, cql: String, classpath: String, cassHome: File, host: String, port: String, cqlPort: String): Unit = { - if(cli != defaultCliInit && cql != defaultCqlInit) { - sys.error("use cli initiation commands, or cql initiation commands, but not both!") - } else if(cli != defaultCliInit) { - val bin = cassHome / "bin" / "cassandra-cli" - val args = Seq(bin.getAbsolutePath, "-f", cli,"-h",host,"-p",port) - Process(args,cassHome).! - } else if(cql != defaultCqlInit) { - val bin = cassHome / "bin" / "cqlsh" - val cqlPath = new File(cql).getAbsolutePath + def initCassandra(cql: String, classpath: String, cassHome: File, host: String, port: String, cqlPort: String): Unit = { + if(cql != defaultCqlInit) { + val bin = cassHome / "bin" / "cqlsh" + val cqlPath = new File(cql).getAbsolutePath val args = Seq(bin.getAbsolutePath, "-f", cqlPath,host,cqlPort) Process(args,cassHome).! } From 334299e8623e6b9c691edb19cc97cf414fab34cb Mon Sep 17 00:00:00 2001 From: Rohit Rai Date: Wed, 28 Oct 2015 23:05:42 -0700 Subject: [PATCH 03/14] removing port, address, etc, they should now be passed in config mappings or the conf file. Adding additional classpath support --- .../sbt/cassandra/CassandraPlugin.scala | 47 ++++++++++--------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraPlugin.scala b/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraPlugin.scala index 7a14c3d..0c57876 100644 --- a/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraPlugin.scala +++ b/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraPlugin.scala @@ -10,6 +10,9 @@ import org.yaml.snakeyaml.Yaml import java.io._ import scala.util.Try +import java.util.{Map => JMap} +import scala.collection.JavaConversions._ + object CassandraPlugin extends Plugin { //defaults: @@ -19,11 +22,7 @@ object CassandraPlugin extends Plugin { val cassandraVersion = SettingKey[String]("cassandra-version") val cassandraConfigDir = SettingKey[String]("cassandra-config-dir") - val cassandraCliInit = SettingKey[String]("cassandra-cli-init") val cassandraCqlInit = SettingKey[String]("cassandra-cql-init") - val cassandraHost = SettingKey[String]("cassandra-host") - val cassandraPort = SettingKey[String]("cassandra-port") - val cassandraCqlPort = SettingKey[String]("cassandra-cql-port") val cassandraHome = TaskKey[File]("cassandra-home") val cassandraStartDeadline = TaskKey[Int]("cassandra-start-deadline") val configMappings = SettingKey[Seq[(String,java.lang.Object)]]("cassandra-conf", "used to override values in conf/cassandra.yaml. values are appropriate java objects") @@ -37,16 +36,13 @@ object CassandraPlugin extends Plugin { val addLibJars = SettingKey[Seq[File]]("additional-lib-jars") val cassandraSettings = Seq( - cassandraHost := "localhost", - cassandraPort := "9160", configMappings := Seq(), - configMappings <++= (cassandraPort,target){ - case (port, targetDir) => { + configMappings <++= (target){ + case (targetDir) => { val data = targetDir / "data" def d(s: String): String = (data / s).getAbsolutePath Seq( - "rpc_port" -> port, - "data_file_directories" -> { + "data_file_directories" -> { val l = new java.util.LinkedList[String]() l.add(d("data")) l @@ -63,12 +59,7 @@ object CassandraPlugin extends Plugin { cassandraStartDeadline := 20, cassandraHome <<= (cassandraVersion, target) map {case (ver,targetDir) => targetDir / s"apache-cassandra-${ver}"}, cassandraVersion := "2.1.2", - cassandraCqlPort <<= (cassandraPort, cassandraVersion){ - case (oldPort, ver) => { - if(Version(ver) > Version("2.1.0")) "9042" - else oldPort - } - }, + cassandraTgz := "", classpathTypes ~= (_ + "tar.gz"), libraryDependencies += { @@ -97,19 +88,29 @@ object CassandraPlugin extends Plugin { cassHome } }, - startCassandra <<= (target, deployCassandra, cassandraConfigDir, - cassandraCqlInit, cassandraHost, cassandraPort, cassandraCqlPort, cassandraStartDeadline, - configMappings, streams) map { + startCassandra <<= (target, deployCassandra, cassandraConfigDir, addLibJars, + cassandraCqlInit, cassandraStartDeadline, configMappings, streams) map { - case (targetDir, cassHome, confDirAsString, cql, host, port, cqlPort, startDeadline, confMappings, outStreams) => { + case (targetDir, cassHome, confDirAsString, addLibs, cql, startDeadline, confMappings, outStreams) => { val pidFile = targetDir / "cass.pid" - val jarClasspath = (sbt.IO.listFiles(cassHome / "lib")).collect{case f: File if f.getName.endsWith(".jar") => f.getAbsolutePath}.mkString(":") + val jarClasspath = (sbt.IO.listFiles(cassHome / "lib").collect{case f: File if f.getName.endsWith(".jar") => f.getAbsolutePath} ++ addLibs).mkString(":") val conf: String = { if(confDirAsString == defaultConfigDir) { val configDir = cassHome / "conf" configDir.getAbsolutePath } else confDirAsString } + + val yamlFile = new FileInputStream(new File(s"$conf/cassandra.yaml")) + + val yaml = new Yaml() + val cprops = yaml.load(yamlFile).asInstanceOf[JMap[String, Object]] ++ confMappings.toMap + + val host = cprops.get("listen_address").asInstanceOf[String] + val port = cprops.get("rpc_port").asInstanceOf[String] + val cqlPort = cprops.get("native_transport_port").asInstanceOf[String] + + val classpath = conf + ":" + jarClasspath val bin = cassHome / "bin" / "cassandra" val args = Seq(bin.getAbsolutePath, "-p", pidFile.getAbsolutePath) @@ -119,7 +120,7 @@ object CassandraPlugin extends Plugin { outStreams.log.info("going to wait for cassandra:") waitForCassandra(port, startDeadline, (s: String) => outStreams.log.info(s)) outStreams.log.info("going to initialize cassandra:") - initCassandra(cql, classpath, cassHome, host, port, cqlPort) + initCassandra(cql, classpath, cassHome, host, cqlPort) } else { outStreams.log.warn("cassandra already running") } @@ -212,7 +213,7 @@ object CassandraPlugin extends Plugin { } } - def initCassandra(cql: String, classpath: String, cassHome: File, host: String, port: String, cqlPort: String): Unit = { + def initCassandra(cql: String, classpath: String, cassHome: File, host: String, cqlPort: String): Unit = { if(cql != defaultCqlInit) { val bin = cassHome / "bin" / "cqlsh" val cqlPath = new File(cql).getAbsolutePath From b46889772b0155b02d0df495a7eabe1afd395d86 Mon Sep 17 00:00:00 2001 From: Rohit Rai Date: Wed, 28 Oct 2015 23:06:09 -0700 Subject: [PATCH 04/14] bumping the version number --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index a976e07..23b0db2 100644 --- a/build.sbt +++ b/build.sbt @@ -6,7 +6,7 @@ name := "sbt-cassandra-plugin" description := "SBT plugin to allow launching Cassandra during tests, and test your application against it" -version := "0.6.2" +version := "0.6.3" scalaVersion := "2.10.4" From dcd10bba741ead6d8363003421c8e3123a743aeb Mon Sep 17 00:00:00 2001 From: Shiti Date: Thu, 31 Mar 2016 18:21:05 +0530 Subject: [PATCH 05/14] auto-plugin and removed dependency on Cassandra --- build.sbt | 11 +- project/plugins.sbt | 2 +- .../sbt/cassandra/CassandraITPlugin.scala | 236 +++++++++++++++++ .../sbt/cassandra/CassandraPlugin.scala | 249 ------------------ 4 files changed, 244 insertions(+), 254 deletions(-) create mode 100644 src/main/scala/com/github/hochgi/sbt/cassandra/CassandraITPlugin.scala delete mode 100644 src/main/scala/com/github/hochgi/sbt/cassandra/CassandraPlugin.scala diff --git a/build.sbt b/build.sbt index 23b0db2..791e8d2 100644 --- a/build.sbt +++ b/build.sbt @@ -4,9 +4,9 @@ organization := "com.tuplejump.com.github.hochgi" name := "sbt-cassandra-plugin" -description := "SBT plugin to allow launching Cassandra during tests, and test your application against it" +description := "SBT plugin to launch and use Cassandra during integration tests" -version := "0.6.3" +version := "0.9.0" scalaVersion := "2.10.4" @@ -18,8 +18,6 @@ libraryDependencies ++= Seq("org.apache.thrift" % "libthrift" % "0.9.2" exclude( scalacOptions ++= Seq("-deprecation", "-feature", "-unchecked", "-language:postfixOps") -net.virtualvoid.sbt.graph.Plugin.graphSettings - publishTo := { val nexus = "https://oss.sonatype.org/" if (isSnapshot.value) Some("snapshots" at nexus + "content/repositories/snapshots") @@ -54,5 +52,10 @@ pomExtra := ( Rohit Rai http://www.twitter.com/milliondreams + + Shiti + Shiti Saxena + https://twitter.com/eraoferrors + ) diff --git a/project/plugins.sbt b/project/plugins.sbt index b5869f0..501c6fd 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,3 +1,3 @@ -addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.5") +//addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.5") addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0") diff --git a/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraITPlugin.scala b/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraITPlugin.scala new file mode 100644 index 0000000..cd2944a --- /dev/null +++ b/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraITPlugin.scala @@ -0,0 +1,236 @@ +package com.github.hochgi.sbt.cassandra + +import java.io.{FileInputStream, FileOutputStream} +import java.util.{Properties, Map => JMap} + +import sbt._ +import Keys._ +import org.yaml.snakeyaml.Yaml + +import scala.concurrent.{Await, Promise} +import scala.util.Try +import scala.collection.JavaConverters._ +import scala.concurrent.duration._ + +object CassandraITPlugin extends AutoPlugin { + + object autoImport { + lazy val cassandraVersion = SettingKey[String]("cassandra-version", + "Required. Version of Cassandra to be used for testing.") + lazy val cassandraConfigDir = SettingKey[String]("cassandra-config-dir") + + lazy val configMappings = SettingKey[Seq[(String, java.lang.Object)]]("cassandra-conf", + "Optional. used to override values in conf/cassandra.yaml. values are appropriate java objects") + lazy val cassandraCqlInit = SettingKey[String]("cassandra-cql-init", + "Optional. cql script to be executed before starting tests. Useful for loading test data.") + + lazy val cassandraTgz = SettingKey[String]("cassandra-tgz", + "Optional. Path to Cassandra binary tar file") + + lazy val cassandraStartDeadline = SettingKey[Int]("cassandra-start-deadline") + lazy val stopCassandraAfterTests = SettingKey[Boolean]("stop-cassandra-after-tests", + "Optional. Defaults to true") + lazy val cleanCassandraAfterStop = SettingKey[Boolean]("clean-cassandra-after-stop", + "Optional. Defaults to true") + + lazy val cassandraJavaArgs = SettingKey[Seq[String]]("cassandra-java-args", + "Optional. Java arguments to be passed to Cassandra") + + } + + private val PIDFileName = "cass.pid" + + def deployCassandra(tarFile: String, + casVersion: String, + targetDir: File, + logger: Logger): File = { + val source = s"http://archive.apache.org/dist/cassandra/$casVersion/apache-cassandra-$casVersion-bin.tar.gz" + val cassandraTarGz: File = if (tarFile.trim.nonEmpty) { + file(tarFile) + } else { + val file: File = new File(targetDir, s"apache-cassandra-$casVersion-bin.tar.gz") + IO.download(url(source), file) + file + } + if (cassandraTarGz == null) sys.error("could not load: cassandra tar.gz file.") + logger.info(s"cassandraTarGz: ${cassandraTarGz.getAbsolutePath}") + Process(Seq("tar", "-xzf", cassandraTarGz.getAbsolutePath), targetDir).! + val cassHome = targetDir / s"apache-cassandra-$casVersion" + //old cassandra versions used log4j, newer versions use logback and are configurable through env vars + val oldLogging = cassHome / "conf" / "log4j-server.properties" + if (oldLogging.exists) { + val in: FileInputStream = new FileInputStream(oldLogging) + val props: Properties = new Properties + props.load(in) + in.close() + val out: FileOutputStream = new FileOutputStream(oldLogging) + props.setProperty("log4j.appender.R.File", (targetDir / "data" / "logs").getAbsolutePath) + props.store(out, null) + out.close() + } + cassHome + } + + def initCassandra(cql: String, + cassHome: File, + host: String, + cqlPort: Int): Unit = { + if (cql.nonEmpty) { + val bin = cassHome / "bin" / "cqlsh" + val cqlPath = new File(cql).getAbsolutePath + val args = Seq(bin.getAbsolutePath, "-f", cqlPath, host, cqlPort.toString) + Process(args, cassHome).! + } + } + + def isCassandraRunning(rpcAddress: String, + rpcPort: Int): Boolean = { + import org.apache.thrift.transport.{TFramedTransport, TSocket} + val tr = new TFramedTransport(new TSocket(rpcAddress, rpcPort)) + Try { + tr.open() + }.isSuccess + } + + def waitForCassandra(rpcAddress: String, + rpcPort: Int, + deadline: Int, + infoPrintFunc: String => Unit): Unit = { + import org.apache.thrift.transport.{TFramedTransport, TSocket, TTransport, TTransportException} + + import scala.concurrent.duration._ + + var retry = true + val deadlineTime = deadline.seconds.fromNow + while (retry && deadlineTime.hasTimeLeft) { + val tr: TTransport = new TFramedTransport(new TSocket(rpcAddress, rpcPort)) + try { + tr.open() + retry = false + } catch { + case e: TTransportException => { + infoPrintFunc(s"waiting for cassandra to boot on port $rpcPort") + Thread.sleep(500) + } + } + if (tr.isOpen) { + tr.close() + } + } + } + + def updateCassandraConfig(confDir: String, + confMappings: Seq[(String, java.lang.Object)], + logger: Logger): JMap[String, Object] = { + val filePath: String = s"$confDir/cassandra.yaml" + val yamlFile = new FileInputStream(new File(filePath)) + val yaml = new Yaml + val cassandraYamlMap = (yaml.load(yamlFile).asInstanceOf[JMap[String, Object]].asScala ++ confMappings.toMap).asJava + + val ymlContent = yaml.dump(cassandraYamlMap) + logger.debug(ymlContent) + sbt.IO.write(file(filePath), ymlContent, java.nio.charset.StandardCharsets.UTF_8, false) + + cassandraYamlMap + } + + def startCassandra(cassHome: File, + host: String, + port: Int, + targetDir: File, + conf: String, + logger: Logger, + javaArgs: Seq[String], + startDeadline: Int): Unit = { + + val pidFile = targetDir / PIDFileName + + if (!isCassandraRunning(host, port)) { + val bin = cassHome / "bin" / "cassandra" + val args = Seq(bin.getAbsolutePath, "-p", pidFile.getAbsolutePath) + Process(args, cassHome, "CASSANDRA_CONF" -> conf, + "CASSANDRA_HOME" -> cassHome.getAbsolutePath, "JVM_OPTS" -> javaArgs.mkString(" ")).run + logger.info("going to wait for cassandra:") + waitForCassandra(host, port, startDeadline, (s: String) => logger.info(s)) + } else { + logger.warn("cassandra already running") + } + + } + + def stopCassandra(clean: Boolean, + dataDir: File, + pid: String) = { + if (pid.nonEmpty) { + s"kill $pid" ! + //give cassandra a chance to exit gracefully + var counter = 40 + val never = Promise().future + while ((s"jps" !!).split("\n").contains(s"$pid CassandraDaemon") && counter > 0) { + try { + Await.ready(never, 250 millis) + } catch { + case _: Throwable => counter = counter - 1 + } + } + if (counter == 0) { + //waited too long... + s"kill -9 $pid" ! + } + if (clean) { + sbt.IO.delete(dataDir) + } + } + } + + import autoImport._ + + lazy val cassandraITDefaultSettings: Seq[Def.Setting[_]] = Seq( + cassandraConfigDir := "", + cassandraCqlInit := "", + cassandraTgz := "", + stopCassandraAfterTests := true, + cleanCassandraAfterStop := true, + cassandraStartDeadline := 20, + configMappings := Nil, + cassandraJavaArgs := Nil + ) + + override def projectSettings: Seq[_root_.sbt.Def.Setting[_]] = super.projectSettings ++ + cassandraITDefaultSettings ++ Seq( + fork in IntegrationTest := true, + parallelExecution in IntegrationTest := false, + testOptions in IntegrationTest += Tests.Setup { () => + val targetDir = target.value + val logger = streams.value.log + + val cassHome = deployCassandra(cassandraTgz.value, cassandraVersion.value, targetDir, logger) + + val confDir: String = { + if (cassandraConfigDir.value.trim.isEmpty) { + (cassHome / "conf").getAbsolutePath + } else cassandraConfigDir.value.trim + } + + val updatedConfig = updateCassandraConfig(confDir, configMappings.value, logger) + val host = updatedConfig.get("listen_address").asInstanceOf[String] + val port = updatedConfig.get("rpc_port").asInstanceOf[Int] + val cqlPort = updatedConfig.get("native_transport_port").asInstanceOf[Int] + + startCassandra(cassHome, host, port, targetDir, confDir, + logger, cassandraJavaArgs.value, cassandraStartDeadline.value) + + logger.info("going to initialize cassandra:") + initCassandra(cassandraCqlInit.value.trim, cassHome, host, cqlPort) + }, + + testOptions in IntegrationTest += Tests.Cleanup { () => + if (stopCassandraAfterTests.value) { + val targetDir = target.value + val pidFile = targetDir / PIDFileName + val pid = Try(sbt.IO.read(pidFile).filterNot(_.isWhitespace)).getOrElse("") + stopCassandra(cleanCassandraAfterStop.value, targetDir / "data", pid) + } + } + ) +} diff --git a/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraPlugin.scala b/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraPlugin.scala deleted file mode 100644 index 0c57876..0000000 --- a/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraPlugin.scala +++ /dev/null @@ -1,249 +0,0 @@ -package com.github.hochgi.sbt.cassandra - -import java.util.Properties -import semverfi._ -import sbt._ -import Keys._ -import scala.concurrent._ ,duration._ -import ExecutionContext.Implicits.global -import org.yaml.snakeyaml.Yaml -import java.io._ -import scala.util.Try - -import java.util.{Map => JMap} -import scala.collection.JavaConversions._ - -object CassandraPlugin extends Plugin { - - //defaults: - private[this] val defaultConfigDir = "NO_DIR_SUPPLIED" - private[this] val defaultCqlInit = "NO_CQL_COMMANDS_SUPPLIED" - //private[this] val defaultTarBall = "GET_FROM_MAVEN" - - val cassandraVersion = SettingKey[String]("cassandra-version") - val cassandraConfigDir = SettingKey[String]("cassandra-config-dir") - val cassandraCqlInit = SettingKey[String]("cassandra-cql-init") - val cassandraHome = TaskKey[File]("cassandra-home") - val cassandraStartDeadline = TaskKey[Int]("cassandra-start-deadline") - val configMappings = SettingKey[Seq[(String,java.lang.Object)]]("cassandra-conf", "used to override values in conf/cassandra.yaml. values are appropriate java objects") - val deployCassandra = TaskKey[File]("deploy-cassandra") - val startCassandra = TaskKey[String]("start-cassandra") - val stopCassandraAfterTests = SettingKey[Boolean]("stop-cassandra-after-tests") - val cleanCassandraAfterStop = SettingKey[Boolean]("stop-cassandra-after-tests") - val cassandraPid = TaskKey[String]("cassandra-pid") - val stopCassandra = TaskKey[Unit]("stop-cassandra") - val cassandraTgz = SettingKey[String]("cassandra-tgz") - val addLibJars = SettingKey[Seq[File]]("additional-lib-jars") - - val cassandraSettings = Seq( - configMappings := Seq(), - configMappings <++= (target){ - case (targetDir) => { - val data = targetDir / "data" - def d(s: String): String = (data / s).getAbsolutePath - Seq( - "data_file_directories" -> { - val l = new java.util.LinkedList[String]() - l.add(d("data")) - l - }, - "commitlog_directory" -> d("commitlog"), - "saved_caches_directory" -> d("saved_caches") - ) - } - }, - cassandraConfigDir := defaultConfigDir, - cassandraCqlInit := defaultCqlInit, - stopCassandraAfterTests := true, - cleanCassandraAfterStop := true, - cassandraStartDeadline := 20, - cassandraHome <<= (cassandraVersion, target) map {case (ver,targetDir) => targetDir / s"apache-cassandra-${ver}"}, - cassandraVersion := "2.1.2", - - cassandraTgz := "", - classpathTypes ~= (_ + "tar.gz"), - libraryDependencies += { - "org.apache.cassandra" % "apache-cassandra" % cassandraVersion.value artifacts(Artifact("apache-cassandra", "tar.gz", "tar.gz","bin")) intransitive() - }, - deployCassandra <<= (cassandraVersion, target, dependencyClasspath in Runtime, streams, cassandraTgz) map { - case (ver, targetDir, classpath, streams, ctgz) => { - val cassandraTarGz:File = if(ctgz.nonEmpty) file(ctgz) else Attributed.data(classpath).find(_.getName == s"apache-cassandra-$ver-bin.tar.gz").get - - if (cassandraTarGz == null) sys.error("could not load: cassandra tar.gz file.") - streams.log.info(s"cassandraTarGz: ${cassandraTarGz.getAbsolutePath}") - Process(Seq("tar","-xzf",cassandraTarGz.getAbsolutePath),targetDir).! - val cassHome = targetDir / s"apache-cassandra-${ver}" - //old cassandra versions used log4j, newer versions use logback and are configurable through env vars - val oldLogging = cassHome / "conf" / "log4j-server.properties" - if(oldLogging.exists) { - val in: FileInputStream = new FileInputStream(oldLogging) - val props: Properties = new Properties - props.load(in) - in.close - val out: FileOutputStream = new FileOutputStream(oldLogging) - props.setProperty("log4j.appender.R.File", (targetDir / "data" / "logs").getAbsolutePath) - props.store(out, null) - out.close - } - cassHome - } - }, - startCassandra <<= (target, deployCassandra, cassandraConfigDir, addLibJars, - cassandraCqlInit, cassandraStartDeadline, configMappings, streams) map { - - case (targetDir, cassHome, confDirAsString, addLibs, cql, startDeadline, confMappings, outStreams) => { - val pidFile = targetDir / "cass.pid" - val jarClasspath = (sbt.IO.listFiles(cassHome / "lib").collect{case f: File if f.getName.endsWith(".jar") => f.getAbsolutePath} ++ addLibs).mkString(":") - val conf: String = { - if(confDirAsString == defaultConfigDir) { - val configDir = cassHome / "conf" - configDir.getAbsolutePath - } else confDirAsString - } - - val yamlFile = new FileInputStream(new File(s"$conf/cassandra.yaml")) - - val yaml = new Yaml() - val cprops = yaml.load(yamlFile).asInstanceOf[JMap[String, Object]] ++ confMappings.toMap - - val host = cprops.get("listen_address").asInstanceOf[String] - val port = cprops.get("rpc_port").asInstanceOf[String] - val cqlPort = cprops.get("native_transport_port").asInstanceOf[String] - - - val classpath = conf + ":" + jarClasspath - val bin = cassHome / "bin" / "cassandra" - val args = Seq(bin.getAbsolutePath, "-p", pidFile.getAbsolutePath) - overrideConfigs(conf, confMappings, outStreams.log) - if (!isCassandraRunning(port)) { - Process(args, cassHome, "CASSANDRA_CONF" -> conf, "CASSANDRA_HOME" -> cassHome.getAbsolutePath).run - outStreams.log.info("going to wait for cassandra:") - waitForCassandra(port, startDeadline, (s: String) => outStreams.log.info(s)) - outStreams.log.info("going to initialize cassandra:") - initCassandra(cql, classpath, cassHome, host, cqlPort) - } else { - outStreams.log.warn("cassandra already running") - } - val pid = Try(sbt.IO.read(pidFile).filterNot(_.isWhitespace)).getOrElse("NO PID") - cassandraPid := pid - pid - } - }, - //if compilation of test classes fails, cassandra should not be invoked. (moreover, Test.Cleanup won't execute to stop it...) - startCassandra <<= (startCassandra).dependsOn(compile in Test), - cassandraPid <<= (target) map { - t => { - val cassPid = t / "cass.pid" - if(cassPid.exists) sbt.IO.read(cassPid).filterNot(_.isWhitespace) - else "NO PID" // did you run start-cassandra task? - } - }, - stopCassandra <<= (cassandraPid, cleanCassandraAfterStop, target) map { - case (pid,clean,targetDir) => stopCassandraMethod(clean, targetDir/ "data", pid) - }, - //make sure to Stop cassandra when tests are done. - testOptions in Test <+= (cassandraPid, stopCassandraAfterTests, cleanCassandraAfterStop, target) map { - case (pid, stop, clean, targetDir) => Tests.Cleanup(() => { - if(stop) stopCassandraMethod(clean, targetDir / "data", pid) - }) - } - ) - - def stopCassandraMethod(clean: Boolean, dataDir: File, pid: String) = if(pid != "NO PID") { - s"kill $pid" ! - //give cassandra a chance to exit gracefully - var counter = 40 - val never = Promise().future - while((s"jps" !!).split("\n").exists(_ == s"$pid CassandraDaemon") && counter > 0) { - try{ - Await.ready(never, 250 millis) - } catch { - case _ : Throwable => counter = counter - 1 - } - } - if(counter == 0) { - //waited to long... - s"kill -9 $pid" ! - } - if(clean) sbt.IO.delete(dataDir) - } - - def waitCassandraShutdown(pid: String) = { - var counter = 40 - val never = Promise[Boolean].future - while((s"jps" !!).split("\n").exists(_ == s"$pid CassandraDaemon") && counter > 0) { - try{ - Await.ready(never, 250 millis) - } catch { - case _ : Throwable => counter = counter - 1 - } - } - } - - def isCassandraRunning(port: String): Boolean = { - import org.apache.thrift.transport.{TTransport, TFramedTransport, TSocket, TTransportException} - val rpcAddress = "localhost" - val rpcPort = port.toInt - val tr = new TFramedTransport(new TSocket(rpcAddress, rpcPort)) - Try { tr.open }.isSuccess - } - - def waitForCassandra(port: String, deadline: Int, infoPrintFunc: String => Unit): Unit = { - import org.apache.thrift.transport.{TTransport, TFramedTransport, TSocket, TTransportException} - import scala.concurrent.duration._ - - val rpcAddress = "localhost" - val rpcPort = port.toInt - var retry = true - val deadlineTime = deadline.seconds.fromNow - while (retry && deadlineTime.hasTimeLeft) { - val tr: TTransport = new TFramedTransport(new TSocket(rpcAddress, rpcPort)) - try { - tr.open - retry = false - } catch { - case e: TTransportException => { - infoPrintFunc(s"waiting for cassandra to boot on port $rpcPort") - Thread.sleep(500) - } - } - if (tr.isOpen) { - tr.close - } - } - } - - def initCassandra(cql: String, classpath: String, cassHome: File, host: String, cqlPort: String): Unit = { - if(cql != defaultCqlInit) { - val bin = cassHome / "bin" / "cqlsh" - val cqlPath = new File(cql).getAbsolutePath - val args = Seq(bin.getAbsolutePath, "-f", cqlPath,host,cqlPort) - Process(args,cassHome).! - } - } - - def overrideConfigs(confDir: String, confMappings: Seq[(String,java.lang.Object)], logger: Logger): Unit = { - val cassandraYamlPath = s"$confDir/cassandra.yaml" - val yaml = new Yaml - val cassandraYamlMap = yaml.load(new FileInputStream(new File(cassandraYamlPath))) - .asInstanceOf[java.util.LinkedHashMap[String, java.lang.Object]] - confMappings.foreach{ - case (prop,value) => { - logger.info(s"setting configuration [$prop] with [$value]") - cassandraYamlMap.put(prop, value) - } - } - - val it = cassandraYamlMap.entrySet().iterator() - val m = new java.util.LinkedHashMap[String, java.lang.Object]() - while(it.hasNext) { - val cur = it.next() - if(cur.getValue != null) { - m.put(cur.getKey, cur.getValue) - } - } - val ymlContent = yaml.dump(m) - logger.debug(ymlContent) - sbt.IO.write(file(cassandraYamlPath), ymlContent, java.nio.charset.StandardCharsets.UTF_8, false) - } -} From 282312507659b37519009072cc5636717e3b31e8 Mon Sep 17 00:00:00 2001 From: Shiti Date: Sat, 2 Apr 2016 10:17:17 +0530 Subject: [PATCH 06/14] updated README and version --- README.md | 59 +++++++++++++++++++++++---------------------- build.sbt | 4 +-- project/plugins.sbt | 2 -- 3 files changed, 32 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index eb52ce2..158bdce 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,27 @@ -sbt-cassandra-plugin -==================== +sbt-cassandra +============== -This is a work in progress project. The goal is to allow launching [Cassandra](http://cassandra.apache.org) during tests, and test your application against it (much like the [plugin for maven](http://mojo.codehaus.org/cassandra-maven-plugin)). -at this pre-mature phase, only the very basic functionality works (and only on linux/unix). API is not final, and might (probably will) change down the road. -However, the plugin is already usable as is. +An auto-plugin that launches [Cassandra](http://cassandra.apache.org) during integration tests. ## Installation ## Add the following to your `project/plugins.sbt` file: -```scala -resolvers += "Sonatype OSS Releases" at "https://oss.sonatype.org/content/repositories/releases" -addSbtPlugin("com.github.hochgi" % "sbt-cassandra-plugin" % "0.6.1") +```scala +addSbtPlugin("com.tuplejump.com.github.hochgi" % "sbt-cassandra" % "1.0.0") ``` ## Usage ## ### Basic: ### -```scala -import com.github.hochgi.sbt.cassandra._ +In `build.sbt`, enable the plugin for desired project and specify the version of cassandra against which tests are to be run, -CassandraPlugin.cassandraSettings - -test in Test <<= (test in Test).dependsOn(startCassandra) -``` -### Advanced: ## -To choose a specific version of cassandra (default is 2.1.2), you can use: ```scala -cassandraVersion := "2.1.2" +lazy val root = (project in file(".")) + .enablePlugins(CassandraITPlugin) + .settings(cassandraVersion := "3.4") ``` + +### Additional Settings: ## + cassandra now shuts down by default when tests are done. to disable this behavior, set: ```scala stopCassandraAfterTests := false @@ -39,23 +34,19 @@ to use special configuration files suited for your use case, use: ```scala cassandraConfigDir := "/path/to/your/conf/dir" ``` -to intialize cassandra with your custom cassandra-cli commands, use: -```scala -cassandraCliInit := "/path/to/cassandra-cli/commands/file" -``` to intialize cassandra with your custom cql commands, use: ```scala cassandraCqlInit := "/path/to/cassandra-cql/commands/file" ``` -to change cassandra rpc port (note: even if you change the port on the configuration, this is the port number that will be used), use: -```scala -cassandraPort := "PORT_NUMBER" -``` timeout for waiting on cassandra to start (default is 20 seconds) can be configured with property (in seconds): ```scala cassandraStartDeadline := 10 ``` -also, you may override any other configuration, e.g: +the plugin downloads cassandra tar from [Apache Cassandra Archives](http://archive.apache.org/dist/cassandra/). A custom version can be used by configuring, the path to the tar file, +```scala +cassandraTgz := "resources/custom-cassandra.tgz" +``` +to override cassandra configuration, e.g: ```scala configMappings += "auto_snapshot" -> true configMappings ++= Seq( @@ -69,6 +60,16 @@ configMappings ++= Seq( } ) ``` -##### IMPORTANT NOTES ##### -* don't use both CQL & CLI. choose only one... -* the `configMappings` key takes a sequence of `(String,java.lang.Object)`, and should be compatible with actual value represented by the key in the yaml file. +Note: the `configMappings` key takes a sequence of `(String,java.lang.Object)`, and should be compatible with actual value represented by the key in the yaml file. + +The `configMappings` setting should be used to change host, port and cqlPort. The keys for them are: + +* host - `listen_address` +* port - `rpc_port` +* cqlPort - `native_transport_port` + +to pass java args to cassandra, +```scala +cassandraJavaArgs := Seq("-Xmx1G") +``` + diff --git a/build.sbt b/build.sbt index 791e8d2..6495e95 100644 --- a/build.sbt +++ b/build.sbt @@ -2,11 +2,11 @@ sbtPlugin := true organization := "com.tuplejump.com.github.hochgi" -name := "sbt-cassandra-plugin" +name := "sbt-cassandra" description := "SBT plugin to launch and use Cassandra during integration tests" -version := "0.9.0" +version := "1.0.0" scalaVersion := "2.10.4" diff --git a/project/plugins.sbt b/project/plugins.sbt index 501c6fd..4ce4d9e 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,3 +1 @@ -//addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.5") - addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0") From f8f98f7179e40b3c11eebdfd9751ee6a8e9cdbc1 Mon Sep 17 00:00:00 2001 From: Shiti Date: Mon, 11 Apr 2016 11:02:54 +0530 Subject: [PATCH 07/14] throwing error when both cassandra version and path are not specified --- .../github/hochgi/sbt/cassandra/CassandraITPlugin.scala | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraITPlugin.scala b/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraITPlugin.scala index cd2944a..dedd857 100644 --- a/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraITPlugin.scala +++ b/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraITPlugin.scala @@ -44,14 +44,17 @@ object CassandraITPlugin extends AutoPlugin { casVersion: String, targetDir: File, logger: Logger): File = { - val source = s"http://archive.apache.org/dist/cassandra/$casVersion/apache-cassandra-$casVersion-bin.tar.gz" val cassandraTarGz: File = if (tarFile.trim.nonEmpty) { file(tarFile) - } else { + } else if (casVersion.trim.nonEmpty) { val file: File = new File(targetDir, s"apache-cassandra-$casVersion-bin.tar.gz") + val source = s"http://archive.apache.org/dist/cassandra/$casVersion/apache-cassandra-$casVersion-bin.tar.gz" IO.download(url(source), file) file + } else { + sys.error("Specify Cassandra version or path to Cassandra tar.gz file") } + if (cassandraTarGz == null) sys.error("could not load: cassandra tar.gz file.") logger.info(s"cassandraTarGz: ${cassandraTarGz.getAbsolutePath}") Process(Seq("tar", "-xzf", cassandraTarGz.getAbsolutePath), targetDir).! From 9ff5ab9d04b53fabd3cc33d26f9b22dc8633f686 Mon Sep 17 00:00:00 2001 From: Shiti Date: Mon, 11 Apr 2016 11:04:22 +0530 Subject: [PATCH 08/14] preparing for release 1.0.1 --- README.md | 2 +- build.sbt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 158bdce..d5961be 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ An auto-plugin that launches [Cassandra](http://cassandra.apache.org) during int Add the following to your `project/plugins.sbt` file: ```scala -addSbtPlugin("com.tuplejump.com.github.hochgi" % "sbt-cassandra" % "1.0.0") +addSbtPlugin("com.tuplejump.com.github.hochgi" % "sbt-cassandra" % "1.0.1") ``` ## Usage ## diff --git a/build.sbt b/build.sbt index 6495e95..cda1fcb 100644 --- a/build.sbt +++ b/build.sbt @@ -6,7 +6,7 @@ name := "sbt-cassandra" description := "SBT plugin to launch and use Cassandra during integration tests" -version := "1.0.0" +version := "1.0.1" scalaVersion := "2.10.4" From 88ba91167287af6164fb09b4a8e911c7e72c3fba Mon Sep 17 00:00:00 2001 From: Shiti Date: Mon, 11 Apr 2016 11:23:42 +0530 Subject: [PATCH 09/14] default empty value for cassandraVersion --- .../com/github/hochgi/sbt/cassandra/CassandraITPlugin.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraITPlugin.scala b/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraITPlugin.scala index dedd857..f77759e 100644 --- a/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraITPlugin.scala +++ b/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraITPlugin.scala @@ -189,6 +189,7 @@ object CassandraITPlugin extends AutoPlugin { import autoImport._ lazy val cassandraITDefaultSettings: Seq[Def.Setting[_]] = Seq( + cassandraVersion:="", cassandraConfigDir := "", cassandraCqlInit := "", cassandraTgz := "", From 01aa75fa2f452b080fa86fd749a83c157470fac6 Mon Sep 17 00:00:00 2001 From: Shiti Date: Mon, 11 Apr 2016 11:47:11 +0530 Subject: [PATCH 10/14] updating version for release --- README.md | 2 +- build.sbt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d5961be..8ccfabb 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ An auto-plugin that launches [Cassandra](http://cassandra.apache.org) during int Add the following to your `project/plugins.sbt` file: ```scala -addSbtPlugin("com.tuplejump.com.github.hochgi" % "sbt-cassandra" % "1.0.1") +addSbtPlugin("com.tuplejump.com.github.hochgi" % "sbt-cassandra" % "1.0.2") ``` ## Usage ## diff --git a/build.sbt b/build.sbt index cda1fcb..215a96c 100644 --- a/build.sbt +++ b/build.sbt @@ -6,7 +6,7 @@ name := "sbt-cassandra" description := "SBT plugin to launch and use Cassandra during integration tests" -version := "1.0.1" +version := "1.0.2" scalaVersion := "2.10.4" From b443832701e85cf9710128bb12456343f3eaa73f Mon Sep 17 00:00:00 2001 From: Shiti Date: Mon, 18 Apr 2016 10:52:25 +0530 Subject: [PATCH 11/14] removed reference to cassandraVersion in deploy once its downloaded --- build.sbt | 2 +- .../hochgi/sbt/cassandra/CassandraITPlugin.scala | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/build.sbt b/build.sbt index 215a96c..8e4602b 100644 --- a/build.sbt +++ b/build.sbt @@ -6,7 +6,7 @@ name := "sbt-cassandra" description := "SBT plugin to launch and use Cassandra during integration tests" -version := "1.0.2" +version := "1.0.3" scalaVersion := "2.10.4" diff --git a/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraITPlugin.scala b/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraITPlugin.scala index f77759e..e722ad9 100644 --- a/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraITPlugin.scala +++ b/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraITPlugin.scala @@ -44,9 +44,9 @@ object CassandraITPlugin extends AutoPlugin { casVersion: String, targetDir: File, logger: Logger): File = { - val cassandraTarGz: File = if (tarFile.trim.nonEmpty) { + val cassandraTarGz: File = if (tarFile.nonEmpty) { file(tarFile) - } else if (casVersion.trim.nonEmpty) { + } else if (casVersion.nonEmpty) { val file: File = new File(targetDir, s"apache-cassandra-$casVersion-bin.tar.gz") val source = s"http://archive.apache.org/dist/cassandra/$casVersion/apache-cassandra-$casVersion-bin.tar.gz" IO.download(url(source), file) @@ -57,8 +57,11 @@ object CassandraITPlugin extends AutoPlugin { if (cassandraTarGz == null) sys.error("could not load: cassandra tar.gz file.") logger.info(s"cassandraTarGz: ${cassandraTarGz.getAbsolutePath}") + val fileName: String = cassandraTarGz.getName + val extensionIndex = fileName.indexOf(".tar.gz") + val dirName = fileName.substring(0, extensionIndex) Process(Seq("tar", "-xzf", cassandraTarGz.getAbsolutePath), targetDir).! - val cassHome = targetDir / s"apache-cassandra-$casVersion" + val cassHome = targetDir / dirName //old cassandra versions used log4j, newer versions use logback and are configurable through env vars val oldLogging = cassHome / "conf" / "log4j-server.properties" if (oldLogging.exists) { @@ -189,7 +192,7 @@ object CassandraITPlugin extends AutoPlugin { import autoImport._ lazy val cassandraITDefaultSettings: Seq[Def.Setting[_]] = Seq( - cassandraVersion:="", + cassandraVersion := "", cassandraConfigDir := "", cassandraCqlInit := "", cassandraTgz := "", @@ -208,7 +211,8 @@ object CassandraITPlugin extends AutoPlugin { val targetDir = target.value val logger = streams.value.log - val cassHome = deployCassandra(cassandraTgz.value, cassandraVersion.value, targetDir, logger) + val cassHome = deployCassandra(cassandraTgz.value.trim, + cassandraVersion.value.trim, targetDir, logger) val confDir: String = { if (cassandraConfigDir.value.trim.isEmpty) { From 69973b227eaaa3f8dcb4abc3ead69f932c0f986c Mon Sep 17 00:00:00 2001 From: Shiti Date: Wed, 20 Apr 2016 14:00:19 +0530 Subject: [PATCH 12/14] fixed bug with deploying Cassandra. Added a demo project to make testing easier --- README.md | 5 ++++- build.sbt | 2 +- demo/build.sbt | 12 ++++++++++++ demo/project/build.properties | 1 + demo/project/plugins.sbt | 3 +++ demo/src/it/scala/com/tuplejump/DummySpec.scala | 5 +++++ .../hochgi/sbt/cassandra/CassandraITPlugin.scala | 7 +++---- 7 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 demo/build.sbt create mode 100644 demo/project/build.properties create mode 100644 demo/project/plugins.sbt create mode 100644 demo/src/it/scala/com/tuplejump/DummySpec.scala diff --git a/README.md b/README.md index 8ccfabb..67da3a3 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,13 @@ sbt-cassandra ============== An auto-plugin that launches [Cassandra](http://cassandra.apache.org) during integration tests. +Note: The plugin does not work on WindowsOS ## Installation ## Add the following to your `project/plugins.sbt` file: ```scala -addSbtPlugin("com.tuplejump.com.github.hochgi" % "sbt-cassandra" % "1.0.2") +addSbtPlugin("com.tuplejump.com.github.hochgi" % "sbt-cassandra" % "1.0.4") ``` ## Usage ## @@ -17,6 +18,8 @@ In `build.sbt`, enable the plugin for desired project and specify the version of ```scala lazy val root = (project in file(".")) .enablePlugins(CassandraITPlugin) + .configs(IntegrationTest) + .settings(Defaults.itSettings: _*) .settings(cassandraVersion := "3.4") ``` diff --git a/build.sbt b/build.sbt index 8e4602b..f742a69 100644 --- a/build.sbt +++ b/build.sbt @@ -6,7 +6,7 @@ name := "sbt-cassandra" description := "SBT plugin to launch and use Cassandra during integration tests" -version := "1.0.3" +version := "1.0.4" scalaVersion := "2.10.4" diff --git a/demo/build.sbt b/demo/build.sbt new file mode 100644 index 0000000..ba04737 --- /dev/null +++ b/demo/build.sbt @@ -0,0 +1,12 @@ +name := "demo" + +version := "1.0.0" + +scalaVersion := "2.11.8" + +lazy val root = (project in file(".")) + .enablePlugins(CassandraITPlugin) + .configs(IntegrationTest) + .settings(Defaults.itSettings: _*) + .settings(cassandraVersion := "3.4") + diff --git a/demo/project/build.properties b/demo/project/build.properties new file mode 100644 index 0000000..d638b4f --- /dev/null +++ b/demo/project/build.properties @@ -0,0 +1 @@ +sbt.version = 0.13.8 \ No newline at end of file diff --git a/demo/project/plugins.sbt b/demo/project/plugins.sbt new file mode 100644 index 0000000..0e556fa --- /dev/null +++ b/demo/project/plugins.sbt @@ -0,0 +1,3 @@ +logLevel := Level.Warn + +addSbtPlugin("com.tuplejump.com.github.hochgi" % "sbt-cassandra" % "1.0.4") diff --git a/demo/src/it/scala/com/tuplejump/DummySpec.scala b/demo/src/it/scala/com/tuplejump/DummySpec.scala new file mode 100644 index 0000000..946bbc8 --- /dev/null +++ b/demo/src/it/scala/com/tuplejump/DummySpec.scala @@ -0,0 +1,5 @@ +package com.tuplejump + +class DummySpec{ + +} diff --git a/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraITPlugin.scala b/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraITPlugin.scala index e722ad9..356a9f5 100644 --- a/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraITPlugin.scala +++ b/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraITPlugin.scala @@ -57,10 +57,9 @@ object CassandraITPlugin extends AutoPlugin { if (cassandraTarGz == null) sys.error("could not load: cassandra tar.gz file.") logger.info(s"cassandraTarGz: ${cassandraTarGz.getAbsolutePath}") - val fileName: String = cassandraTarGz.getName - val extensionIndex = fileName.indexOf(".tar.gz") - val dirName = fileName.substring(0, extensionIndex) - Process(Seq("tar", "-xzf", cassandraTarGz.getAbsolutePath), targetDir).! + val dirName = "cassandraForIT" + Process(Seq("mkdir", "-p", dirName), targetDir).! + Process(Seq("tar", "-xzf", cassandraTarGz.getAbsolutePath, "-C", dirName,"--strip-components=1"), targetDir).! val cassHome = targetDir / dirName //old cassandra versions used log4j, newer versions use logback and are configurable through env vars val oldLogging = cassHome / "conf" / "log4j-server.properties" From 5d2df522eea078a375bcbd332c5210fae86f56ea Mon Sep 17 00:00:00 2001 From: velotelo Date: Tue, 15 Nov 2016 16:30:16 +0200 Subject: [PATCH 13/14] Add forceCassandraDownload option. --- README.md | 10 +++++++--- build.sbt | 2 +- .../hochgi/sbt/cassandra/CassandraITPlugin.scala | 16 +++++++++++----- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 8737ae2..ae8473e 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ addSbtPlugin("com.github.hochgi" % "sbt-cassandra" % "1.0.4") ## Usage ## ### Basic: ### -In `build.sbt`, enable the plugin for desired project and specify the version of cassandra against which tests are to be run, +In `build.sbt`, enable the plugin for desired project and specify the version of cassandra against which tests are to be run, ```scala lazy val root = (project in file(".")) @@ -49,6 +49,10 @@ the plugin downloads cassandra tar from [Apache Cassandra Archives](http://archi ```scala cassandraTgz := "resources/custom-cassandra.tgz" ``` +to prevent downloading cassandra tar file if the file already exists +```scala +forceCassandraDowload := false +``` to override cassandra configuration, e.g: ```scala configMappings += "auto_snapshot" -> true @@ -70,9 +74,9 @@ The `configMappings` setting should be used to change host, port and cqlPort. Th * host - `listen_address` * port - `rpc_port` * cqlPort - `native_transport_port` - + to pass java args to cassandra, ```scala cassandraJavaArgs := Seq("-Xmx1G") ``` - + diff --git a/build.sbt b/build.sbt index 7b905bc..090f128 100644 --- a/build.sbt +++ b/build.sbt @@ -6,7 +6,7 @@ name := "sbt-cassandra" description := "SBT plugin to launch and use Cassandra during integration tests" -version := "1.0.4" +version := "1.1.0" scalaVersion := "2.10.6" diff --git a/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraITPlugin.scala b/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraITPlugin.scala index 356a9f5..d8452ee 100644 --- a/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraITPlugin.scala +++ b/src/main/scala/com/github/hochgi/sbt/cassandra/CassandraITPlugin.scala @@ -36,6 +36,8 @@ object CassandraITPlugin extends AutoPlugin { lazy val cassandraJavaArgs = SettingKey[Seq[String]]("cassandra-java-args", "Optional. Java arguments to be passed to Cassandra") + lazy val forceCassandraDownload = SettingKey[Boolean]("force-cassandra-download", + "Optional. Defaults to true") } private val PIDFileName = "cass.pid" @@ -43,13 +45,16 @@ object CassandraITPlugin extends AutoPlugin { def deployCassandra(tarFile: String, casVersion: String, targetDir: File, - logger: Logger): File = { + logger: Logger, + forceCassandraDownload: Boolean): File = { val cassandraTarGz: File = if (tarFile.nonEmpty) { file(tarFile) } else if (casVersion.nonEmpty) { val file: File = new File(targetDir, s"apache-cassandra-$casVersion-bin.tar.gz") - val source = s"http://archive.apache.org/dist/cassandra/$casVersion/apache-cassandra-$casVersion-bin.tar.gz" - IO.download(url(source), file) + if (!file.exists || forceCassandraDownload) { + val source = s"http://archive.apache.org/dist/cassandra/$casVersion/apache-cassandra-$casVersion-bin.tar.gz" + IO.download(url(source), file) + } file } else { sys.error("Specify Cassandra version or path to Cassandra tar.gz file") @@ -199,7 +204,8 @@ object CassandraITPlugin extends AutoPlugin { cleanCassandraAfterStop := true, cassandraStartDeadline := 20, configMappings := Nil, - cassandraJavaArgs := Nil + cassandraJavaArgs := Nil, + forceCassandraDownload := true ) override def projectSettings: Seq[_root_.sbt.Def.Setting[_]] = super.projectSettings ++ @@ -211,7 +217,7 @@ object CassandraITPlugin extends AutoPlugin { val logger = streams.value.log val cassHome = deployCassandra(cassandraTgz.value.trim, - cassandraVersion.value.trim, targetDir, logger) + cassandraVersion.value.trim, targetDir, logger, forceCassandraDownload.value) val confDir: String = { if (cassandraConfigDir.value.trim.isEmpty) { From 294af7478143efe947f704bbd7977c2f4e186ea4 Mon Sep 17 00:00:00 2001 From: velotelo Date: Wed, 16 Nov 2016 08:16:52 +0200 Subject: [PATCH 14/14] Add more description --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d58ace9..5163d8a 100644 --- a/README.md +++ b/README.md @@ -49,9 +49,9 @@ the plugin downloads cassandra tar from [Apache Cassandra Archives](http://archi ```scala cassandraTgz := "resources/custom-cassandra.tgz" ``` -to prevent downloading cassandra tar file if the file already exists +to prevent downloading cassandra tar file if the file already exists. Parameter is ignored if custom file is specified in `cassandraTgz` ```scala -forceCassandraDowload := false +forceCassandraDownload := false ``` to override cassandra configuration, e.g: ```scala