Skip to content

Commit 3aedf15

Browse files
Merge pull request #327 from codacy/fetch-outdated-tool-patterns-only
feature: Use patterns from local storage and API as fallback CY-2772
2 parents 16d1060 + a725416 commit 3aedf15

File tree

2 files changed

+88
-23
lines changed

2 files changed

+88
-23
lines changed

toolRepository-remote/src/main/scala/com/codacy/toolRepository/remote/ToolRepositoryRemote.scala

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import com.codacy.analysis.core.model.{AnalyserError, ParameterSpec, PatternSpec
99
import com.codacy.analysis.core.tools.ToolRepository
1010
import com.codacy.plugins.api.languages.{Language, Languages}
1111
import com.codacy.toolRepository.remote.storage.{PatternSpecDataStorage, ToolSpecDataStorage}
12+
import org.log4s.{Logger, getLogger}
1213

1314
import scala.concurrent.duration._
1415
import scala.concurrent.{Await, ExecutionContext, Future}
@@ -18,6 +19,7 @@ class ToolRepositoryRemote(toolsClient: ToolsClient,
1819
patternStorage: String => PatternSpecDataStorage)(implicit val ec: ExecutionContext,
1920
implicit val mat: Materializer)
2021
extends ToolRepository {
22+
private val logger: Logger = getLogger
2123

2224
private val toolStorageFilename = "tools"
2325
private val toolStorageInstance = toolsStorage(toolStorageFilename)
@@ -61,7 +63,7 @@ class ToolRepositoryRemote(toolsClient: ToolsClient,
6163
}
6264
}
6365

64-
override def listPatterns(tool: ToolSpec): Either[AnalyserError, Seq[PatternSpec]] = {
66+
private def patternsFromApi(tool: ToolSpec): Either[AnalyserError, Seq[PatternSpec]] = {
6567
val source = PaginatedApiSourceFactory { cursor =>
6668
toolsClient.listPatterns(tool.uuid, cursor = cursor).value.map {
6769
case Right(ListPatternsResponse.OK(PatternListResponse(data, None | Some(PaginationInfo(None, _, _))))) =>
@@ -88,14 +90,33 @@ class ToolRepositoryRemote(toolsClient: ToolsClient,
8890
case e: Exception => Left(AnalyserError.FailedToListPatterns(tool.uuid, e.getMessage))
8991
}
9092

91-
val result = Await.result(patternsF, 1 minute)
92-
val patternSpecDataStorage = patternStorage(tool.uuid)
93-
result match {
94-
case Right(patterns) =>
95-
patternSpecDataStorage.save(patterns)
96-
Right(patterns)
93+
Await.result(patternsF, 1 minute)
94+
}
95+
96+
private def downloadPatternsFromApi(
97+
tool: ToolSpec,
98+
toolPatternsStorageInstance: PatternSpecDataStorage): Either[AnalyserError, Seq[PatternSpec]] = {
99+
patternsFromApi(tool) match {
100+
case Right(patternsFromApi) =>
101+
logger.info(s"Fetched patterns for ${tool.name} version ${tool.version}")
102+
toolPatternsStorageInstance.save(patternsFromApi)
103+
Right(patternsFromApi)
97104
case Left(err) =>
98-
patternSpecDataStorage.get().toRight(err)
105+
logger.error(s"Failed to fetch patterns for ${tool.name} from API: ${err.message}")
106+
Left(err)
107+
}
108+
}
109+
110+
override def listPatterns(tool: ToolSpec): Either[AnalyserError, Seq[PatternSpec]] = {
111+
val toolPatternsStorageFilename = s"${tool.uuid}-${tool.version}"
112+
val toolPatternsStorageInstance = patternStorage(toolPatternsStorageFilename)
113+
114+
toolPatternsStorageInstance.get() match {
115+
case Some(patternsFromStorage) =>
116+
logger.info(s"Using patterns from cache for ${tool.name} version ${tool.version}")
117+
Right(patternsFromStorage)
118+
case None =>
119+
downloadPatternsFromApi(tool, toolPatternsStorageInstance)
99120
}
100121
}
101122

toolRepository-remote/src/test/scala/com/codacy/toolRespository/remote/ToolRepositoryRemoteSpec.scala

Lines changed: 59 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -116,12 +116,20 @@ class ToolRepositoryRemoteSpec extends Specification with Mockito with EitherMat
116116
override def get(): Option[Seq[PatternSpec]] = Some(Seq(patternSpec(patternA.id)))
117117
}
118118

119+
def eitherListToolsResponse(
120+
listToolsResponse: ListToolsResponse): EitherT[Future, Either[Throwable, HttpResponse], ListToolsResponse] = {
121+
val responseEither: Either[Either[Throwable, HttpResponse], ListToolsResponse] = Right(listToolsResponse)
122+
EitherT(Future.successful(responseEither))
123+
}
124+
125+
def eitherListToolPatternsResponse(listToolPatternsResponse: ListPatternsResponse)
126+
: EitherT[Future, Either[Throwable, HttpResponse], ListPatternsResponse] = {
127+
val responseEither: Either[Either[Throwable, HttpResponse], ListPatternsResponse] =
128+
Right(listToolPatternsResponse)
129+
EitherT(Future.successful(responseEither))
130+
}
131+
119132
"list" should {
120-
def eitherListToolsResponse(
121-
listToolsResponse: ListToolsResponse): EitherT[Future, Either[Throwable, HttpResponse], ListToolsResponse] = {
122-
val responseEither: Either[Either[Throwable, HttpResponse], ListToolsResponse] = Right(listToolsResponse)
123-
EitherT(Future.successful(responseEither))
124-
}
125133

126134
"return the list of tools" in {
127135
val mockedClient = mock[ToolsClient]
@@ -203,17 +211,15 @@ class ToolRepositoryRemoteSpec extends Specification with Mockito with EitherMat
203211
}
204212

205213
"listPatterns" should {
206-
def eitherListToolPatternsResponse(listToolPatternsResponse: ListPatternsResponse)
207-
: EitherT[Future, Either[Throwable, HttpResponse], ListPatternsResponse] = {
208-
val responseEither: Either[Either[Throwable, HttpResponse], ListPatternsResponse] =
209-
Right(listToolPatternsResponse)
210-
EitherT(Future.successful(responseEither))
211-
}
212214

213-
"return the list of patterns" in {
215+
"return the list of patterns from API" in {
214216
val mockedClient = mock[ToolsClient]
215217
val toolRepository =
216-
new ToolRepositoryRemote(mockedClient, _ => mockToolsDataEmptyStorage, _ => mockPatternDataWithStorage)
218+
new ToolRepositoryRemote(mockedClient, _ => mockToolsDataEmptyStorage, _ => mockPatternDataEmptyStorage)
219+
220+
when(mockedClient.listTools(cursor = None)).thenReturn(
221+
eitherListToolsResponse(ListToolsResponse.OK(ToolListResponse(Vector(toolA), None))),
222+
eitherListToolsResponse(ListToolsResponse.OK(ToolListResponse(Vector(toolB), None))))
217223

218224
when(
219225
mockedClient.listPatterns(
@@ -232,13 +238,16 @@ class ToolRepositoryRemoteSpec extends Specification with Mockito with EitherMat
232238
patternsEither must beRight((p: Seq[PatternSpec]) => p.head.id must_== patternA.id)
233239
}
234240

235-
"return list with multiple patterns" in {
241+
"return list with multiple patterns from API" in {
236242
val mockedClient = mock[ToolsClient]
237243
val toolRepository =
238-
new ToolRepositoryRemote(mockedClient, _ => mockToolsDataEmptyStorage, _ => mockPatternDataWithStorage)
244+
new ToolRepositoryRemote(mockedClient, _ => mockToolsDataEmptyStorage, _ => mockPatternDataEmptyStorage)
239245

240246
val paginationInfo = PaginationInfo(Some("cursor"), Some(100), Some(1))
241247

248+
when(mockedClient.listTools(cursor = None))
249+
.thenReturn(eitherListToolsResponse(ListToolsResponse.OK(ToolListResponse(Vector(toolA), None))))
250+
242251
when(
243252
mockedClient.listPatterns(
244253
toolId = ArgumentMatchers.any[String],
@@ -263,6 +272,9 @@ class ToolRepositoryRemoteSpec extends Specification with Mockito with EitherMat
263272
val toolRepository =
264273
new ToolRepositoryRemote(mockedClient, _ => mockToolsDataWithStorage, _ => mockPatternDataWithStorage)
265274

275+
when(mockedClient.listTools(cursor = None))
276+
.thenReturn(eitherListToolsResponse(ListToolsResponse.OK(ToolListResponse(Vector(toolA), None))))
277+
266278
when(
267279
mockedClient.listPatterns(
268280
toolId = ArgumentMatchers.any[String],
@@ -278,11 +290,37 @@ class ToolRepositoryRemoteSpec extends Specification with Mockito with EitherMat
278290
patternsEither must beRight((p: Seq[PatternSpec]) => p.map(_.id) must contain(patternA.id))
279291
}
280292

293+
"return list of patterns first from storage" in {
294+
val mockedClient = mock[ToolsClient]
295+
val toolRepository =
296+
new ToolRepositoryRemote(mockedClient, _ => mockToolsDataWithStorage, _ => mockPatternDataWithStorage)
297+
298+
when(mockedClient.listTools(cursor = None))
299+
.thenReturn(eitherListToolsResponse(ListToolsResponse.OK(ToolListResponse(Vector(toolA, toolB), None))))
300+
301+
when(
302+
mockedClient.listPatterns(
303+
toolId = ArgumentMatchers.any[String],
304+
cursor = ArgumentMatchers.any[Option[String]],
305+
limit = ArgumentMatchers.any[Option[Int]],
306+
headers = ArgumentMatchers.any[List[HttpHeader]]))
307+
.thenReturn(eitherListToolPatternsResponse(ListPatternsResponse.BadRequest(BadRequest("error"))))
308+
309+
val patternsEither = toolRepository.listPatterns(toolSpec(toolB.uuid))
310+
311+
patternsEither must beRight
312+
patternsEither must beRight((p: Seq[PatternSpec]) => p must haveLength(1))
313+
patternsEither must beRight((p: Seq[PatternSpec]) => p.map(_.id) must contain(patternA.id))
314+
}
315+
281316
"throw an exception if API returns BadRequest" in {
282317
val mockedClient = mock[ToolsClient]
283318
val toolRepository =
284319
new ToolRepositoryRemote(mockedClient, _ => mockToolsDataEmptyStorage, _ => mockPatternDataEmptyStorage)
285320

321+
when(mockedClient.listTools(cursor = None))
322+
.thenReturn(eitherListToolsResponse(ListToolsResponse.OK(ToolListResponse(Vector(toolA), None))))
323+
286324
when(
287325
mockedClient.listPatterns(
288326
toolId = ArgumentMatchers.any[String],
@@ -300,6 +338,9 @@ class ToolRepositoryRemoteSpec extends Specification with Mockito with EitherMat
300338
val toolRepository =
301339
new ToolRepositoryRemote(mockedClient, _ => mockToolsDataEmptyStorage, _ => mockPatternDataEmptyStorage)
302340

341+
when(mockedClient.listTools(cursor = None))
342+
.thenReturn(eitherListToolsResponse(ListToolsResponse.OK(ToolListResponse(Vector(toolA), None))))
343+
303344
when(
304345
mockedClient.listPatterns(
305346
toolId = ArgumentMatchers.any[String],
@@ -317,6 +358,9 @@ class ToolRepositoryRemoteSpec extends Specification with Mockito with EitherMat
317358
val toolRepository =
318359
new ToolRepositoryRemote(mockedClient, _ => mockToolsDataEmptyStorage, _ => mockPatternDataEmptyStorage)
319360

361+
when(mockedClient.listTools(cursor = None))
362+
.thenReturn(eitherListToolsResponse(ListToolsResponse.OK(ToolListResponse(Vector(toolA), None))))
363+
320364
when(
321365
mockedClient.listPatterns(
322366
toolId = ArgumentMatchers.any[String],

0 commit comments

Comments
 (0)