Merge pull request #3074 from eed3si9n/fport/3015

[fport] ScriptedPlugin: Add support for paginated tests
This commit is contained in:
eugene yokota 2017-04-04 18:08:47 -07:00 committed by GitHub
commit e2a1f02be9
3 changed files with 53 additions and 8 deletions

View File

@ -0,0 +1,12 @@
### Improvements
- ScriptedPlugin: Add the ability to paginate scripted tests.
It is now possible to run a subset of scripted tests in a directory at once,
for example:
```
scripted source-dependencies/*1of3
```
Will create three pages and run page 1. This is especially useful when running
scripted tests on a CI, to benefit from the available parallelism.
[3013]: https://github.com/sbt/sbt/pull/3013
[@smarter]: https://github.com/smarter

View File

@ -37,6 +37,8 @@ object Scripted {
import DefaultParsers._
// Paging, 1-index based.
case class ScriptedTestPage(page: Int, total: Int)
// FIXME: Duplicated with ScriptedPlugin.scriptedParser, this can be
// avoided once we upgrade build.properties to 0.13.14
def scriptedParser(scriptedBase: File): Parser[Seq[String]] =
{
val scriptedFiles: NameFilter = ("test": NameFilter) | "pending"

View File

@ -62,20 +62,51 @@ object ScriptedPlugin extends AutoPlugin {
m.getClass.getMethod("run", classOf[File], classOf[Boolean], classOf[Array[String]], classOf[File], classOf[Array[String]])
}
private def scriptedParser(scriptedBase: File): Parser[Seq[String]] =
import DefaultParsers._
case class ScriptedTestPage(page: Int, total: Int)
private[sbt] def scriptedParser(scriptedBase: File): Parser[Seq[String]] =
{
import DefaultParsers._
val pairs = (scriptedBase * AllPassFilter * AllPassFilter * "test").get map { (f: File) =>
val scriptedFiles: NameFilter = ("test": NameFilter) | "pending"
val pairs = (scriptedBase * AllPassFilter * AllPassFilter * scriptedFiles).get map { (f: File) =>
val p = f.getParentFile
(p.getParentFile.getName, p.getName)
}
val pairMap = pairs.groupBy(_._1).mapValues(_.map(_._2).toSet)
val pairMap = pairs.groupBy(_._1).mapValues(_.map(_._2).toSet);
val id = charClass(c => !c.isWhitespace && c != '/').+.string
val groupP = token(id.examples(pairMap.keySet)) <~ token('/')
def nameP(group: String) = token("*".id | id.examples(pairMap(group)))
val testID = for (group <- groupP; name <- nameP(group)) yield (group, name)
(token(Space) ~> matched(testID)).*
val groupP = token(id.examples(pairMap.keySet.toSet)) <~ token('/')
// A parser for page definitions
val pageP: Parser[ScriptedTestPage] = ("*" ~ NatBasic ~ "of" ~ NatBasic) map {
case _ ~ page ~ _ ~ total => ScriptedTestPage(page, total)
}
// Grabs the filenames from a given test group in the current page definition.
def pagedFilenames(group: String, page: ScriptedTestPage): Seq[String] = {
val files = pairMap(group).toSeq.sortBy(_.toLowerCase)
val pageSize = files.size / page.total
// The last page may loose some values, so we explicitly keep them
val dropped = files.drop(pageSize * (page.page - 1))
if (page.page == page.total) dropped
else dropped.take(pageSize)
}
def nameP(group: String) = {
token("*".id | id.examples(pairMap(group)))
}
val PagedIds: Parser[Seq[String]] =
for {
group <- groupP
page <- pageP
files = pagedFilenames(group, page)
// TODO - Fail the parser if we don't have enough files for the given page size
//if !files.isEmpty
} yield files map (f => group + '/' + f)
val testID = (for (group <- groupP; name <- nameP(group)) yield (group, name))
val testIdAsGroup = matched(testID) map (test => Seq(test))
//(token(Space) ~> matched(testID)).*
(token(Space) ~> (PagedIds | testIdAsGroup)).* map (_.flatten)
}
def scriptedTask: Initialize[InputTask[Unit]] = Def.inputTask {