1
1
import sbt ._
2
2
import Keys ._
3
+ import com .typesafe .config .ConfigFactory
3
4
4
5
// I need to make these imported by default
5
6
import Project .inConfig
@@ -136,7 +137,8 @@ object MimaBuild {
136
137
settings(myAssemblySettings:_* )
137
138
settings(
138
139
// add task functional-tests that depends on all functional tests
139
- functionalTests := runAllTests.value,
140
+ functionalTests := allTests(functionalTests in _).value,
141
+ test in IntegrationTest := allTests(test in IntegrationTest in _).value,
140
142
mainClass in assembly := Some (" com.typesafe.tools.mima.cli.Main" )
141
143
)
142
144
)
@@ -163,20 +165,28 @@ object MimaBuild {
163
165
// select all testN directories.
164
166
val bases = (file(" reporter" ) / " functional-tests" / " src" / " test" ) *
165
167
(DirectoryFilter && new SimpleFileFilter (_.list.contains(" problems.txt" )))
168
+ val integrationTestBases = (file(" reporter" ) / " functional-tests" / " src" / " it" ) *
169
+ (DirectoryFilter && new SimpleFileFilter (_.list.contains(" test.conf" )))
166
170
167
171
// make the Project for each discovered directory
168
172
lazy val tests = bases.get map testProject
173
+ lazy val integrationTests = integrationTestBases.get map integrationTestProject
169
174
170
175
// defines a Project for the given base directory (for example, functional-tests/test1)
171
176
// Its name is the directory name (test1) and it has compile+package tasks for sources in v1/ and v2/
172
177
def testProject (base : File ) = project(" test-" + base.name, base, settings = testProjectSettings).configs(v1Config, v2Config)
178
+ def integrationTestProject (base : File ) = project(" it-" + base.name, base, settings = integrationTestProjectSettings)
173
179
174
180
lazy val testProjectSettings =
175
181
commonSettings ++ // normal project defaults; can be trimmed later- test and run aren't needed, for example.
176
182
Seq (scalaVersion := (testScalaVersion in Global ).value) ++
177
183
inConfig(v1Config)(perConfig) ++ // add compile/package for the v1 sources
178
184
inConfig(v2Config)(perConfig) :+ // add compile/package for the v2 sources
179
185
(functionalTests := runTest.value) // add the functional-tests task
186
+ lazy val integrationTestProjectSettings =
187
+ commonSettings ++
188
+ Seq (scalaVersion := (testScalaVersion in Global ).value) ++
189
+ (test in IntegrationTest := runIntegrationTest.value)
180
190
181
191
// this is the key for the task that runs the reporter's functional tests
182
192
lazy val functionalTests = TaskKey [Unit ](" test-functional" )
@@ -200,44 +210,84 @@ object MimaBuild {
200
210
lazy val shortSourceDir = scalaSource := baseDirectory.value / configuration.value.name
201
211
202
212
lazy val runTest = Def .task {
203
- val cp = (fullClasspath in (reporterFunctionalTests, Compile )).value // the test classpath from the functionalTest project for the test
204
213
val proj = thisProjectRef.value // gives us the ProjectRef this task is defined in
205
- val si = (scalaInstance in core).value // get a reference to the already loaded Scala classes so we get the advantage of a warm jvm
206
- val v1 = (packageBin in v1Config).value // package the v1 sources and get the configuration used
207
- val v2 = (packageBin in v2Config).value // same for v2
208
- val scalaV = scalaVersion.value
209
- val streams = Keys .streams.value
214
+ runCollectProblemsTest(
215
+ (fullClasspath in (reporterFunctionalTests, Compile )).value, // the test classpath from the functionalTest project for the test
216
+ (scalaInstance in core).value, // get a reference to the already loaded Scala classes so we get the advantage of a warm jvm
217
+ streams.value,
218
+ proj.project,
219
+ (packageBin in v1Config).value, // package the v1 sources and get the configuration used
220
+ (packageBin in v2Config).value, // same for v2
221
+ baseDirectory.value,
222
+ scalaVersion.value,
223
+ null )
224
+ }
225
+
226
+ lazy val runIntegrationTest = Def .task {
227
+ val proj = thisProjectRef.value // gives us the ProjectRef this task is defined in
228
+ val confFile = baseDirectory.value / " test.conf"
229
+ val conf = ConfigFactory .parseFile(confFile).resolve()
230
+ val moduleBase = conf.getString(" groupId" ) % conf.getString(" artifactId" )
231
+ val jar1 = getArtifact(moduleBase % conf.getString(" v1" ), ivySbt.value, streams.value)
232
+ val jar2 = getArtifact(moduleBase % conf.getString(" v2" ), ivySbt.value, streams.value)
233
+ streams.value.log.info(s " Comparing $jar1 -> $jar2" )
234
+ runCollectProblemsTest(
235
+ (fullClasspath in (reporterFunctionalTests, Compile )).value, // the test classpath from the functionalTest project for the test
236
+ (scalaInstance in core).value, // get a reference to the already loaded Scala classes so we get the advantage of a warm jvm
237
+ streams.value,
238
+ proj.project,
239
+ jar1,
240
+ jar2,
241
+ baseDirectory.value,
242
+ scalaVersion.value,
243
+ confFile.getAbsolutePath)
244
+ }
245
+
246
+ def runCollectProblemsTest (cp : Keys .Classpath , si : ScalaInstance , streams : Keys .TaskStreams , testName : String , v1 : File , v2 : File , projectPath : File , scalaV : String , filterPath : String ): Unit = {
210
247
val urls = Attributed .data(cp).map(_.toURI.toURL).toArray
211
248
val loader = new java.net.URLClassLoader (urls, si.loader)
212
249
213
250
val testClass = loader.loadClass(" com.typesafe.tools.mima.lib.CollectProblemsTest" )
214
251
val testRunner = testClass.newInstance().asInstanceOf [{
215
- def runTest (testClasspath : Array [String ], testName : String , oldJarPath : String , newJarPath : String , oraclePath : String ): Unit
252
+ def runTest (testClasspath : Array [String ], testName : String , oldJarPath : String , newJarPath : String , oraclePath : String , filterPath : String ): Unit
216
253
}]
217
254
218
255
// Add the scala-library to the MiMa classpath used to run this test
219
256
val testClasspath = Attributed .data(cp).filter(_.getName endsWith " scala-library.jar" ).map(_.getAbsolutePath).toArray
220
257
221
- val projectPath = proj.build.getPath + " reporter" + " /" + " functional-tests" + " /" + " src" + " /" + " test" + " /" + proj.project.stripPrefix(" test-" )
222
-
223
- val oraclePath = {
224
- val p = projectPath + " /problems.txt"
225
- val p212 = projectPath + " /problems-2.12.txt"
226
- if (! (scalaV.startsWith(" 2.10." ) || scalaV.startsWith(" 2.11." )) && new java.io.File (p212).exists) p212
258
+ val oracleFile = {
259
+ val p = projectPath / " problems.txt"
260
+ val p212 = projectPath / " problems-2.12.txt"
261
+ if (! (scalaV.startsWith(" 2.10." ) || scalaV.startsWith(" 2.11." )) && p212.exists) p212
227
262
else p
228
263
}
229
264
230
265
try {
231
266
import scala .language .reflectiveCalls
232
- testRunner.runTest(testClasspath, proj.project , v1.getAbsolutePath, v2.getAbsolutePath, oraclePath )
233
- streams.log.info(" Test '" + proj.project + " ' succeeded." )
267
+ testRunner.runTest(testClasspath, testName , v1.getAbsolutePath, v2.getAbsolutePath, oracleFile.getAbsolutePath, filterPath )
268
+ streams.log.info(" Test '" + testName + " ' succeeded." )
234
269
} catch {
235
270
case e : Exception => sys.error(e.toString)
236
271
}
237
- ()
238
272
}
239
273
240
- lazy val runAllTests = Def .taskDyn {
274
+ def getArtifact (m : ModuleID , ivy : IvySbt , s : TaskStreams ): File = {
275
+ val moduleSettings = InlineConfiguration (
276
+ " dummy" % " test" % " version" ,
277
+ ModuleInfo (" dummy-test-project-for-resolving" ),
278
+ dependencies = Seq (m))
279
+ val module = new ivy.Module (moduleSettings)
280
+ val report = Deprecated .Inner .ivyUpdate(ivy)(module, s)
281
+ val optFile = (for {
282
+ config <- report.configurations
283
+ module <- config.modules
284
+ (artifact, file) <- module.artifacts
285
+ if artifact.name == m.name
286
+ } yield file).headOption
287
+ optFile getOrElse sys.error(" Could not resolve artifact: " + m)
288
+ }
289
+
290
+ def allTests (f : ProjectRef => TaskKey [Unit ]) = Def .taskDyn {
241
291
val s = state.value // this is how we access all defined projects from a task
242
292
val proj = thisProjectRef.value // gives us the ProjectRef this task is defined in
243
293
val _ = (test in Test ).value // requires unit tests to run first
@@ -247,7 +297,7 @@ object MimaBuild {
247
297
val allProjects = structure.units(proj.build).defined.values filter (_.id != proj.project)
248
298
249
299
// get the fun-tests task in each project
250
- val allTests = allProjects.toSeq flatMap { p => functionalTests in ProjectRef (proj.build, p.id) get structure.data }
300
+ val allTests = allProjects.toSeq flatMap { p => f( ProjectRef (proj.build, p.id) ) get structure.data }
251
301
252
302
// depend on all fun-tests
253
303
Def .task {
@@ -260,5 +310,23 @@ object MimaBuild {
260
310
}
261
311
262
312
object DefineTestProjectsPlugin extends AutoPlugin {
263
- override def extraProjects = MimaBuild .tests
313
+ override def extraProjects = MimaBuild .tests ++ MimaBuild .integrationTests
314
+ }
315
+
316
+ // use the SI-7934 workaround to silence a deprecation warning on an sbt API
317
+ // we have no choice but to call. on the lack of any suitable alternative,
318
+ // see https://gitter.im/sbt/sbt-dev?at=5616e2681b0e279854bd74a4 :
319
+ // "it's my intention to eventually come up with a public API" says Eugene Y
320
+ object Deprecated {
321
+ @ deprecated(" " , " " ) class Inner {
322
+ def ivyUpdate (ivy : IvySbt )(module : ivy.Module , s : TaskStreams ) =
323
+ IvyActions .update(
324
+ module,
325
+ new UpdateConfiguration (
326
+ retrieve = None ,
327
+ missingOk = false ,
328
+ logging = UpdateLogging .DownloadOnly ),
329
+ s.log)
330
+ }
331
+ object Inner extends Inner
264
332
}
0 commit comments