Skip to content

Commit

Permalink
Merge pull request #2 from reibitto/improve-balancing
Browse files Browse the repository at this point in the history
Add more tests and fix JUnit time conversion
  • Loading branch information
reibitto authored Mar 20, 2024
2 parents 279f7d6 + 83d0b25 commit 73666db
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 5 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/scala.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
strategy:
fail-fast: false
matrix:
scala: [2.12.18]
scala: [2.12.19]
java: [adopt@1.11, adopt@1.8]
runs-on: ubuntu-latest
steps:
Expand Down
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ inThisBuild(
lazy val root = (project in file(".")).settings(
name := "sbt-test-shards",
organization := "com.github.reibitto",
scalaVersion := "2.12.18",
scalaVersion := "2.12.19",
sbtPlugin := true,
libraryDependencies ++= Seq(
"org.scalameta" %% "munit" % "0.7.29" % Test,
Expand Down
2 changes: 1 addition & 1 deletion project/build.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
sbt.version=1.9.7
sbt.version=1.9.9
2 changes: 1 addition & 1 deletion src/main/scala/sbttestshards/ShardingAlgorithm.scala
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ object ShardingAlgorithm {
): Balance =
ShardingAlgorithm.Balance(
JUnitReportParser.parseDirectoriesRecursively(reportDirectories).testReports.map { r =>
SpecInfo(r.name, Some(Duration.ofMillis(r.timeTaken.toLong)))
SpecInfo(r.name, Some(Duration.ofMillis((r.timeTaken * 1000).toLong)))
},
shardsInfo,
fallbackShardingAlgorithm
Expand Down
65 changes: 64 additions & 1 deletion src/test/scala/sbttestshards/ShardingAlgorithmSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class ShardingAlgorithmSpec extends ScalaCheckSuite {
implicit val specInfoArbitrary: Arbitrary[SpecInfo] = Arbitrary {
for {
specName <- Gen.resize(30, Gen.alphaStr)
timeTaken <- Gen.choose(0L, 9 * 60 * 1000)
timeTaken <- Gen.choose(0L, 5 * 60 * 1000)
} yield SpecInfo(specName, Some(Duration.ofMillis(timeTaken)))
}

Expand Down Expand Up @@ -50,4 +50,67 @@ class ShardingAlgorithmSpec extends ScalaCheckSuite {
}
}

property("only choose shard if initialDuration indicates node started early") {
forAll { (tests: List[SpecInfo]) =>
val initialDurations = Map(0 -> Duration.ofMinutes(-1000))
val algo = ShardingAlgorithm.Balance(tests, ShardingInfo(3, initialDurations))

val bucketMap = algo.distributeEvenly.toSeq.groupBy(_._2).map { case (k, v) =>
k -> v.map(_._1.timeTaken).reduceOption(_.plus(_)).getOrElse(Duration.ZERO)
}

if (tests.isEmpty)
bucketMap.isEmpty
else
bucketMap.keys.toSeq == Seq(0)
}
}

property("not choose shard if initialDuration exceeds the available time") {
forAll { (tests: List[SpecInfo]) =>
val initialDurations = Map(0 -> Duration.ofMinutes(1000))
val algo = ShardingAlgorithm.Balance(tests, ShardingInfo(3, initialDurations))

val bucketMap = algo.distributeEvenly.toSeq.groupBy(_._2).map { case (k, v) =>
k -> v.map(_._1.timeTaken).reduceOption(_.plus(_)).getOrElse(Duration.ZERO)
}

!bucketMap.contains(0)
}
}

test("take initialDurations into account when distributing specs") {
val initialDurations = Map(0 -> Duration.ofSeconds(10))
val tests = List(
SpecInfo("spec1", timeTaken = Some(Duration.ofSeconds(1))),
SpecInfo("spec2", timeTaken = Some(Duration.ofSeconds(2))),
SpecInfo("spec3", timeTaken = Some(Duration.ofSeconds(3))),
SpecInfo("spec4", timeTaken = Some(Duration.ofSeconds(4))),
SpecInfo("spec5", timeTaken = Some(Duration.ofSeconds(5))),
SpecInfo("spec6", timeTaken = Some(Duration.ofSeconds(6))),
SpecInfo("spec7", timeTaken = Some(Duration.ofSeconds(7))),
SpecInfo("spec8", timeTaken = Some(Duration.ofSeconds(8))),
SpecInfo("spec9", timeTaken = Some(Duration.ofSeconds(9)))
)

val algo = ShardingAlgorithm.Balance(tests, ShardingInfo(3, initialDurations))

val bucketMap = algo.distributeEvenly.toSeq.groupBy(_._2).map { case (k, v) =>
k -> v.map(_._1.timeTaken).reduceOption(_.plus(_)).getOrElse(Duration.ZERO)
}

val bucketMapWithInitialDurations = bucketMap.map { case (k, v) =>
k -> initialDurations.getOrElse(k, Duration.ZERO).plus(v)
}

assertEquals(
bucketMapWithInitialDurations,
Map(
0 -> Duration.ofSeconds(19),
1 -> Duration.ofSeconds(18),
2 -> Duration.ofSeconds(18)
)
)
}

}

0 comments on commit 73666db

Please sign in to comment.