From 4bd78c3ed96083666639fafc97ebfdcd4bf66673 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0est=C3=A1k=20V=C3=ADt?= Date: Wed, 4 Jan 2017 17:07:38 +0100 Subject: [PATCH] Fixed bug in filtering by team. If a team has assigned a project with all subprojects and the project has more than one subproject, only one subproject used to be shown when filtering by team. This is a trivial fix (two/three lines changed), but other additions are in tests. --- .../DependencyCheckReportsParser.scala | 8 +- app/controllers/ProjectsWithReports.scala | 2 +- build.sbt | 4 +- test/ProjectFilterSpec.scala | 26 ++++ test/ResultsTest.scala | 24 ++++ test/factories/ReportsFactory.scala | 116 ++++++++++++++++++ 6 files changed, 173 insertions(+), 7 deletions(-) create mode 100644 test/ProjectFilterSpec.scala create mode 100644 test/ResultsTest.scala create mode 100644 test/factories/ReportsFactory.scala diff --git a/app/controllers/DependencyCheckReportsParser.scala b/app/controllers/DependencyCheckReportsParser.scala index 546e8f3..ca6d8bd 100644 --- a/app/controllers/DependencyCheckReportsParser.scala +++ b/app/controllers/DependencyCheckReportsParser.scala @@ -20,7 +20,7 @@ sealed trait Filter{ def descriptionHtml: Html def descriptionText: String } -private final case class ProjectFilter(project: ReportInfo) extends Filter{ +final case class ProjectFilter(project: ReportInfo) extends Filter{ override def filters: Boolean = true override def descriptionHtml: Html = views.html.filters.project(project) override def descriptionText: String = s"project ${friendlyProjectNameString(project)}" @@ -43,7 +43,7 @@ private final case class ProjectFilter(project: ReportInfo) extends Filter{ } override def selector = Some(s"project:${project.fullId}") } -private final case class TeamFilter(team: Team) extends Filter{ +final case class TeamFilter(team: Team) extends Filter{ override def filters: Boolean = true private def splitSuccessesAndFailures[T, U](set: Set[Either[T, U]]) = { @@ -64,10 +64,10 @@ private final case class TeamFilter(team: Team) extends Filter{ val ProjectName = """^(.*): (.*)$""".r val failedProjectsFriendlyNames = r.failedProjects.failedProjectsSet.map(_.projectName) Logger.error("failedProjectsFriendlyNames: "+failedProjectsFriendlyNames) - val rootProjectReports = reportInfoByFriendlyProjectNameMap.map{ + val rootProjectReports = reportInfoByFriendlyProjectNameMap.toSeq.map{ case (ProjectName(rootProject, _subproject), v) => (rootProject, v) case value @ (rootProject, v) => value - }.groupBy(_._1).mapValues(_.values).withDefault(name => + }.groupBy(_._1).mapValues(_.map(_._2)).withDefault(name => if(failedProjectsFriendlyNames contains name) Seq() else sys.error("Unknown project: "+name) ) diff --git a/app/controllers/ProjectsWithReports.scala b/app/controllers/ProjectsWithReports.scala index f59f2d4..37b8e81 100644 --- a/app/controllers/ProjectsWithReports.scala +++ b/app/controllers/ProjectsWithReports.scala @@ -59,7 +59,7 @@ class ProjectsWithReports (val projects: Projects, val reports: Set[String]) { private def parseUnfriendlyName(unfriendlyName: String, missingProject: String => String): ReportInfo = { val (baseName, theRest) = unfriendlyName.span(_ != '/') - val removeLeadingMess = RestMessBeginRegexp.replaceAllIn(_: String, "") + val removeLeadingMess = RestMessBeginRegexp.replaceAllIn(_: String, "").dropWhile(_=='/') val removeTrailingMess = RestMessEndRegexp.replaceAllIn(_: String, "") val removeMess = removeLeadingMess andThen removeTrailingMess val subProjectOption = Some(removeMess(theRest)).filter(_ != "") diff --git a/build.sbt b/build.sbt index ca02054..57bf711 100644 --- a/build.sbt +++ b/build.sbt @@ -14,8 +14,8 @@ libraryDependencies ++= Seq( //jdbc, cache, ws, - filters - //specs2 % Test + filters, + specs2 % Test ) //resolvers += "scalaz-bintray" at https?"http://dl.bintray.com/scalaz/releases" diff --git a/test/ProjectFilterSpec.scala b/test/ProjectFilterSpec.scala new file mode 100644 index 0000000..33876f4 --- /dev/null +++ b/test/ProjectFilterSpec.scala @@ -0,0 +1,26 @@ +import controllers.ProjectFilter +import org.specs2.mutable.Specification + +//noinspection ScalaUnnecessaryParentheses +class ProjectFilterSpec extends Specification { + import factories.ReportsFactory._ + + private val f1 = ProjectFilter(res.projectsReportInfo.reportIdToReportInfo("a")) // with subprojects + // TODO: filter root + // TODO: filter subproject + + private val s1 = f1.subReports(res).get + + "It should have all dependencies for project a and its subprojects" >> { + "like a" >> {s1.groupedDependenciesByPlainLibraryIdentifier.keySet should contain(buildFakeIdentifier("a").toLibraryIdentifierOption.get)} + "like a/subX" >> {s1.groupedDependenciesByPlainLibraryIdentifier.keySet should contain(buildFakeIdentifier("a/subX").toLibraryIdentifierOption.get)} + "like a/subY" >> {s1.groupedDependenciesByPlainLibraryIdentifier.keySet should contain(buildFakeIdentifier("a/subY").toLibraryIdentifierOption.get)} + } + + "It should now have other dependencies" >> { + "like b" >> {s1.groupedDependenciesByPlainLibraryIdentifier.keySet should not contain(buildFakeIdentifier("b").toLibraryIdentifierOption.get)} + "like b/subX" >> {s1.groupedDependenciesByPlainLibraryIdentifier.keySet should not contain(buildFakeIdentifier("b/subX").toLibraryIdentifierOption.get)} + "like b/subY" >> {s1.groupedDependenciesByPlainLibraryIdentifier.keySet should not contain(buildFakeIdentifier("b/subY").toLibraryIdentifierOption.get)} + } + +} diff --git a/test/ResultsTest.scala b/test/ResultsTest.scala new file mode 100644 index 0000000..c620d7d --- /dev/null +++ b/test/ResultsTest.scala @@ -0,0 +1,24 @@ +import org.specs2.mutable.Specification + +//noinspection ScalaUnnecessaryParentheses +class ResultsTest extends Specification { + import factories.ReportsFactory._ + + "The resultset should" >> { + "have dependencies related to project a" >> { + "like a" >> {res.groupedDependenciesByPlainLibraryIdentifier.keySet should contain(buildFakeIdentifier("a").toLibraryIdentifierOption.get)} + "libe a/subX" >> {res.groupedDependenciesByPlainLibraryIdentifier.keySet should contain(buildFakeIdentifier("a/subX").toLibraryIdentifierOption.get)} + "like a/subY" >> {res.groupedDependenciesByPlainLibraryIdentifier.keySet should contain(buildFakeIdentifier("a/subY").toLibraryIdentifierOption.get)} + } + "have dependencies related to project m" >> { + "like m" >> {res.groupedDependenciesByPlainLibraryIdentifier.keySet should contain(buildFakeIdentifier("m").toLibraryIdentifierOption.get)} + "libe m/subX" >> {res.groupedDependenciesByPlainLibraryIdentifier.keySet should contain(buildFakeIdentifier("m/subX").toLibraryIdentifierOption.get)} + "like m/subY" >> {res.groupedDependenciesByPlainLibraryIdentifier.keySet should contain(buildFakeIdentifier("m/subY").toLibraryIdentifierOption.get)} + } + "have groupedDependencies" >> { + res.groupedDependencies shouldNotEqual null + } + + } + +} diff --git a/test/factories/ReportsFactory.scala b/test/factories/ReportsFactory.scala new file mode 100644 index 0000000..cfc526d --- /dev/null +++ b/test/factories/ReportsFactory.scala @@ -0,0 +1,116 @@ +package factories + +import com.github.nscala_time.time.Imports.DateTime +import com.ysoft.odc._ +import controllers.DependencyCheckReportsParser.Result +import controllers.{Projects, ProjectsWithReports, ReportInfo, TeamId} +import org.apache.commons.codec.digest.DigestUtils + +//noinspection TypeAnnotation +object ReportsFactory{ + + def buildFlatReport(projectId: String): (String, () => (ReportInfo, Analysis)) = { + val thuck = () => { // needs laziness in order to prevent dependency cycle + val reportInfo = projectsReportInfo.parseUnfriendlyName(projectId) + reportInfo -> Analysis( + scanInfo = SerializableXml(""), + name = projectId, + reportDate = DateTime.lastDay, + dependencies = Seq( + buildDependency(projectId) + ) + ) + } + projectId -> thuck + } + + def buildDependency(projectId: String) = { + val fakeFileContent = projectId + Dependency( + fileName = s"dep-for-$projectId", + filePath = s"dep-for-$projectId", + md5 = DigestUtils.md5Hex(fakeFileContent), + sha1 = DigestUtils.sha1Hex(fakeFileContent), + description = s"Some fake dependency for project $projectId", + evidenceCollected = Set(), + identifiers = Seq(buildFakeIdentifier(projectId)), + suppressedIdentifiers = Seq(), + license = "something", + vulnerabilities = Seq(), + suppressedVulnerabilities = Seq(), + relatedDependencies = SerializableXml("") + ) + } + + def buildFakeIdentifier(projectId: String) = { + Identifier(s"fake:dep-for-$projectId:1.0-SNAPSHOT", Confidence.High, "", "maven") + } + + val pm = Map( + "a"->"project a", + "b"->"project b", + "c"->"project c", + "d"->"project d", + "e"->"project e", + "f"->"project f", + "g"->"project g", + "h"->"project h", + "i"->"project i", + "j"->"project j", + "k"->"project k", + "l"->"project l", + "m"->"project m", + "n"->"project n", + "o"->"project o" + ) + + val projectToTeams = Map( + "project a: *" -> Set("TEAM A"), + "project b: subX" -> Set("TEAM A"), + "project b: subY" -> Set("TEAM B"), + "project b" -> Set("TEAM A"), + "project c: *" -> Set("TEAM A"), + "project d: *" -> Set("TEAM A"), + "project e: *" -> Set("TEAM A"), + "project f: *" -> Set("TEAM A"), + "project g: *" -> Set("TEAM A"), + "project h: *" -> Set("TEAM B"), + "project i: *" -> Set("TEAM B"), + "project j: *" -> Set("TEAM B"), + "project k: *" -> Set("TEAM B"), + "project l: *" -> Set("TEAM B"), + "project m: *" -> Set("TEAM B"), + "project n: *" -> Set("TEAM B"), + "project o: *" -> Set("TEAM B") + ) + + val teamLeaders = Map(TeamId("TEAM A") -> "John Smith", TeamId("TEAM B") -> "Jane") + + val projects = new Projects( + projectMap = pm, + teamLeaders = teamLeaders, + projectToTeams = projectToTeams.mapValues(_.map(TeamId)) + ) + + val bareFlatReportsFactories = pm.keySet.flatMap{ projectId => + Seq( + buildFlatReport(projectId), + buildFlatReport(projectId+"/subX"), + buildFlatReport(projectId+"/subY") + ) + } + + val projectsReportInfo = new ProjectsWithReports(projects, bareFlatReportsFactories.map(_._1)) + + val bareFlatReports = bareFlatReportsFactories.map(_._2()).toMap // Prevents forward reference issues + + val res = Result( + bareFlatReports = bareFlatReports, + bareFailedAnalysises = Map(), + projectsReportInfo = projectsReportInfo, + failedReportDownloads = Map() + ) + + val team1 = projects.teamById("TEAM A") + +}