Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
c4aa8cb
Added Manifest Fetcher
LokeshDogga13 Feb 18, 2025
d1ca7d1
Addressing code review comments
LokeshDogga13 Feb 18, 2025
600f91a
Added unit test cases
LokeshDogga13 Feb 18, 2025
cad10ef
Fixing lint issues
LokeshDogga13 Feb 18, 2025
2607eec
Merge branch 'feature/q-lsp' into lodogga/initialChanges
LokeshDogga13 Feb 19, 2025
b0e9648
Addressing code review comments
LokeshDogga13 Feb 19, 2025
973b710
Addressing code review comments
LokeshDogga13 Feb 19, 2025
2641472
Merge branch 'feature/q-lsp' into lodogga/initialChanges
LokeshDogga13 Feb 19, 2025
fef3b06
Fixing lint issues
LokeshDogga13 Feb 19, 2025
539cb7e
Merge remote-tracking branch 'origin/lodogga/initialChanges' into lod…
LokeshDogga13 Feb 19, 2025
563ca08
Addressing code review comments
LokeshDogga13 Feb 19, 2025
8f44478
Fixing detektMain lint issues
LokeshDogga13 Feb 19, 2025
30f8dc6
Added unit test cases
LokeshDogga13 Feb 21, 2025
eef3e59
Merge branch 'feature/q-lsp' into lodogga/initialChanges
LokeshDogga13 Feb 21, 2025
bc25fb9
Updating code according to spec.
LokeshDogga13 Feb 24, 2025
7ac76b0
detekt
LokeshDogga13 Feb 24, 2025
a28dca7
Merge branch 'feature/q-lsp' into lodogga/initialChanges
LokeshDogga13 Feb 24, 2025
20e7451
Fixing typo
LokeshDogga13 Feb 24, 2025
a970509
Artifact changes
LokeshDogga13 Feb 25, 2025
44f5c7b
Fixing validation function
LokeshDogga13 Feb 26, 2025
60c4b1c
Merge branch 'feature/q-lsp' into lodogga/initialChanges
LokeshDogga13 Feb 26, 2025
65f6f68
Addressing code review comments
LokeshDogga13 Feb 26, 2025
224289d
Merge branch 'feature/q-lsp' into lodogga/initialChanges
LokeshDogga13 Feb 26, 2025
3e1bc1e
Fixing Detekt
LokeshDogga13 Feb 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.services.amazonq.lsp.artifacts

import com.intellij.openapi.util.SystemInfo
import com.intellij.openapi.util.text.StringUtil
import com.intellij.util.io.DigestUtil
import com.intellij.util.system.CpuArch
import java.nio.file.Path
import java.nio.file.Paths

fun getToolkitsCommonCacheRoot(): Path = when {

Check warning on line 13 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/LspUtils.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/LspUtils.kt#L13

Added line #L13 was not covered by tests
SystemInfo.isWindows -> {
Paths.get(System.getenv("LOCALAPPDATA"))

Check warning on line 15 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/LspUtils.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/LspUtils.kt#L15

Added line #L15 was not covered by tests
}
SystemInfo.isMac -> {
Paths.get(System.getProperty("user.home"), "Library", "Caches")

Check warning on line 18 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/LspUtils.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/LspUtils.kt#L18

Added line #L18 was not covered by tests
}
else -> {
Paths.get(System.getProperty("user.home"), ".cache")

Check warning on line 21 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/LspUtils.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/LspUtils.kt#L20-L21

Added lines #L20 - L21 were not covered by tests
}
}

Check warning on line 23 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/LspUtils.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/LspUtils.kt#L23

Added line #L23 was not covered by tests

fun getCurrentOS(): String = when {

Check warning on line 25 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/LspUtils.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unused symbol

Function "getCurrentOS" is never used

Check warning on line 25 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/LspUtils.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/LspUtils.kt#L25

Added line #L25 was not covered by tests
SystemInfo.isWindows -> "windows"
SystemInfo.isMac -> "darwin"
else -> "linux"
}

Check warning on line 29 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/LspUtils.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/LspUtils.kt#L28-L29

Added lines #L28 - L29 were not covered by tests

fun getCurrentArchitecture() = when {

Check warning on line 31 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/LspUtils.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unused symbol

Function "getCurrentArchitecture" is never used

Check warning on line 31 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/LspUtils.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/LspUtils.kt#L31

Added line #L31 was not covered by tests
CpuArch.CURRENT == CpuArch.X86_64 -> "x64"
else -> "arm64"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should also handle unknown case

}

Check warning on line 34 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/LspUtils.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/LspUtils.kt#L33-L34

Added lines #L33 - L34 were not covered by tests

fun generateMD5Hash(filePath: Path): String {
val messageDigest = DigestUtil.md5()
DigestUtil.updateContentHash(messageDigest, filePath)
return StringUtil.toHexString(messageDigest.digest())

Check warning on line 39 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/LspUtils.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/LspUtils.kt#L37-L39

Added lines #L37 - L39 were not covered by tests
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.services.amazonq.lsp.artifacts

import org.assertj.core.util.VisibleForTesting
import software.aws.toolkits.core.utils.deleteIfExists
import software.aws.toolkits.core.utils.error
import software.aws.toolkits.core.utils.exists
import software.aws.toolkits.core.utils.getLogger
import software.aws.toolkits.core.utils.info
import software.aws.toolkits.core.utils.readText
import software.aws.toolkits.jetbrains.core.getETagFromUrl
import software.aws.toolkits.jetbrains.core.getTextFromUrl
import software.aws.toolkits.jetbrains.core.saveFileFromUrl
import software.aws.toolkits.jetbrains.services.amazonq.project.manifest.ManifestManager
import java.nio.file.Path

class ManifestFetcher {

Check warning on line 19 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt#L19

Added line #L19 was not covered by tests
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we replace the existing implementation with this?


private val lspManifestUrl = "https://aws-toolkit-language-servers.amazonaws.com/codewhisperer/0/manifest.jso"
private val manifestManager = ManifestManager()
private val lspManifestFilePath: Path = getToolkitsCommonCacheRoot().resolve("aws").resolve("toolkits").resolve("language-servers")
.resolve("jetbrains-lsp-manifest.json")

Check warning on line 24 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt#L21-L24

Added lines #L21 - L24 were not covered by tests

companion object {
private val logger = getLogger<ManifestFetcher>()

Check warning on line 27 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt#L27

Added line #L27 was not covered by tests
}

/**
* Method which will be used to fetch latest manifest.
* */
fun fetch(): ManifestManager.Manifest? {
val localManifest = fetchManifestFromLocal()

Check warning on line 34 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt#L34

Added line #L34 was not covered by tests
if (localManifest != null) {
return localManifest

Check warning on line 36 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt#L36

Added line #L36 was not covered by tests
}
return fetchManifestFromRemote()

Check warning on line 38 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt#L38

Added line #L38 was not covered by tests
}

@VisibleForTesting
internal fun fetchManifestFromRemote(): ManifestManager.Manifest? {
val manifest: ManifestManager.Manifest?
try {
val manifestString = getTextFromUrl(lspManifestUrl)

Check warning on line 45 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt#L43-L45

Added lines #L43 - L45 were not covered by tests
manifest = manifestManager.readManifestFile(manifestString) ?: return null
} catch (e: Exception) {
logger.error(e) { "error fetching lsp manifest from remote URL ${e.message}" }
return null

Check warning on line 49 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt#L47-L49

Added lines #L47 - L49 were not covered by tests
}
if (manifest.isManifestDeprecated == true) {
logger.info { "Manifest is deprecated" }
return null

Check warning on line 53 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt#L52-L53

Added lines #L52 - L53 were not covered by tests
}
updateManifestCache()
logger.info { "Using manifest found from remote URL" }
return manifest

Check warning on line 57 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt#L55-L57

Added lines #L55 - L57 were not covered by tests
}

private fun updateManifestCache() {
try {
saveFileFromUrl(lspManifestUrl, lspManifestFilePath)
} catch (e: Exception) {
logger.error(e) { "error occurred while saving lsp manifest to local cache ${e.message}" }

Check warning on line 64 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt#L61-L64

Added lines #L61 - L64 were not covered by tests
}
}

Check warning on line 66 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt#L66

Added line #L66 was not covered by tests

@VisibleForTesting
internal fun fetchManifestFromLocal(): ManifestManager.Manifest? {
val localETag = getManifestETagFromLocal()
val remoteETag = getManifestETagFromUrl()

Check warning on line 71 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt#L70-L71

Added lines #L70 - L71 were not covered by tests
// If local and remote have same ETag, we can re-use the manifest file from local to fetch artifacts.
// If remote manifest is null or system is offline, re-use localManifest
if ((localETag != null && remoteETag != null && localETag == remoteETag) or (localETag != null && remoteETag == null)) {
try {
val manifestContent = lspManifestFilePath.readText()
val manifest = manifestManager.readManifestFile(manifestContent)

Check warning on line 77 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt#L75-L77

Added lines #L75 - L77 were not covered by tests
if (manifest != null) return manifest
lspManifestFilePath.deleteIfExists() // delete manifest if it fails to de-serialize
} catch (e: Exception) {
logger.error(e) { "error reading lsp manifest file from local ${e.message}" }
return null

Check warning on line 82 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt#L79-L82

Added lines #L79 - L82 were not covered by tests
}
}
return null

Check warning on line 85 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt#L85

Added line #L85 was not covered by tests
}

private fun getManifestETagFromLocal(): String? {
if (lspManifestFilePath.exists()) {
return generateMD5Hash(lspManifestFilePath)

Check warning on line 90 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt#L90

Added line #L90 was not covered by tests
}
return null

Check warning on line 92 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt#L92

Added line #L92 was not covered by tests
}

private fun getManifestETagFromUrl(): String? {
try {
val actualETag = getETagFromUrl(lspManifestUrl)
return actualETag.trim('"')
} catch (e: Exception) {
logger.error(e) { "error fetching ETag of lsp manifest from url." }

Check warning on line 100 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt#L96-L100

Added lines #L96 - L100 were not covered by tests
}
return null

Check warning on line 102 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt#L102

Added line #L102 was not covered by tests
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

package software.aws.toolkits.jetbrains.services.amazonq.project.manifest

import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import com.intellij.openapi.util.SystemInfo
Expand All @@ -18,10 +18,9 @@
val currentVersion = "0.1.32"
val currentOs = getOs()
private val arch = CpuArch.CURRENT
private val mapper = jacksonObjectMapper()
private val mapper = jacksonObjectMapper().apply { configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) }

Check warning on line 21 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/project/manifest/ManifestManager.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/project/manifest/ManifestManager.kt#L21

Added line #L21 was not covered by tests

data class TargetContent(
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonProperty("filename")
val filename: String? = null,
@JsonProperty("url")
Expand All @@ -33,16 +32,15 @@
)

data class VersionTarget(
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonProperty("platform")
val platform: String? = null,
@JsonProperty("arch")
val arch: String? = null,
@JsonProperty("contents")
val contents: List<TargetContent>? = emptyList(),
)

data class Version(
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonProperty("serverVersion")
val serverVersion: String? = null,
@JsonProperty("isDelisted")
Expand All @@ -52,7 +50,6 @@
)

data class Manifest(
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonProperty("manifestSchemaVersion")
val manifestSchemaVersion: String? = null,
@JsonProperty("artifactId")
Expand All @@ -67,7 +64,7 @@

fun getManifest(): Manifest? = fetchFromRemoteAndSave()

private fun readManifestFile(content: String): Manifest? {
fun readManifestFile(content: String): Manifest? {
try {
return mapper.readValue<Manifest>(content)
} catch (e: Exception) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.services.amazonq.lsp.artifacts

import io.mockk.every
import io.mockk.mockkStatic
import org.assertj.core.api.Assertions.assertThat
import org.jetbrains.annotations.TestOnly
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.mockito.kotlin.atLeastOnce
import org.mockito.kotlin.never
import org.mockito.kotlin.reset
import org.mockito.kotlin.spy
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
import software.aws.toolkits.jetbrains.core.getTextFromUrl
import software.aws.toolkits.jetbrains.services.amazonq.project.manifest.ManifestManager

@TestOnly
class ManifestFetcherTest {

private lateinit var manifestFetcher: ManifestFetcher
private lateinit var manifest: ManifestManager.Manifest
private lateinit var manifestManager: ManifestManager

@BeforeEach
fun setup() {
manifestFetcher = spy(ManifestFetcher())
manifestManager = spy(ManifestManager())
manifest = ManifestManager.Manifest()
}

@Test
fun `should return null when both local and remote manifests are null`() {
whenever(manifestFetcher.fetchManifestFromLocal()).thenReturn(null)
whenever(manifestFetcher.fetchManifestFromRemote()).thenReturn(null)

assertThat(manifestFetcher.fetch()).isNull()
}

@Test
fun `should return valid result from local should not execute remote method`() {
reset(manifestFetcher)
whenever(manifestFetcher.fetchManifestFromLocal()).thenReturn(manifest)

assertThat(manifestFetcher.fetch()).isNotNull().isEqualTo(manifest)
verify(manifestFetcher, atLeastOnce()).fetchManifestFromLocal()
verify(manifestFetcher, never()).fetchManifestFromRemote()
}

@Test
fun `should return valid result from remote`() {
whenever(manifestFetcher.fetchManifestFromLocal()).thenReturn(null)
whenever(manifestFetcher.fetchManifestFromRemote()).thenReturn(manifest)

assertThat(manifestFetcher.fetch()).isNotNull().isEqualTo(manifest)
verify(manifestFetcher, atLeastOnce()).fetchManifestFromLocal()
verify(manifestFetcher, atLeastOnce()).fetchManifestFromRemote()
}

@Test
fun `fetchManifestFromRemote should return null due to invalid manifestString`() {
mockkStatic("software.aws.toolkits.jetbrains.core.HttpUtilsKt")
every { getTextFromUrl(any()) } returns "ManifestContent"

whenever(manifestManager.readManifestFile("")).thenReturn(null)

assertThat(manifestFetcher.fetchManifestFromRemote()).isNull()
}

@Test
fun `fetchManifestFromRemote should return manifest and update manifest`() {
val validManifest = ManifestManager.Manifest(manifestSchemaVersion = "1.0")
mockkStatic("software.aws.toolkits.jetbrains.core.HttpUtilsKt")

every { getTextFromUrl(any()) } returns "{ \"manifestSchemaVersion\": \"1.0\" }"

val result = manifestFetcher.fetchManifestFromRemote()
assertThat(result).isNotNull().isEqualTo(validManifest)
}

@Test
fun `fetchManifestFromRemote should return null if manifest is deprecated`() {
mockkStatic("software.aws.toolkits.jetbrains.core.HttpUtilsKt")
every { getTextFromUrl(any()) } returns "ManifestContent"

val deprecatedManifest = ManifestManager.Manifest(isManifestDeprecated = true)

whenever(manifestManager.readManifestFile("")).thenReturn(deprecatedManifest)

assertThat(manifestFetcher.fetchManifestFromRemote()).isNull()
}

@Test
fun `fetchManifestFromLocal should return null`() {
assertThat(manifestFetcher.fetchManifestFromLocal()).isNull()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
package software.aws.toolkits.jetbrains.core

import com.intellij.openapi.application.PathManager
import com.intellij.util.io.HttpRequests
import com.intellij.util.io.createDirectories
import software.aws.toolkits.core.utils.DefaultRemoteResourceResolver
import software.aws.toolkits.core.utils.UrlFetcher
Expand Down Expand Up @@ -41,11 +40,7 @@
}

override fun getETag(url: String): String =
HttpRequests.head(url)
.userAgent("AWS Toolkit for JetBrains")
.connect { request ->
request.connection.headerFields["ETag"]?.firstOrNull().orEmpty()
}
getETagFromUrl(url)

Check warning on line 43 in plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/DefaultRemoteResourceResolverProvider.kt

View check run for this annotation

Codecov / codecov/patch

plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/DefaultRemoteResourceResolverProvider.kt#L43

Added line #L43 was not covered by tests
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,10 @@
request.write(jsonString)
request.readString(indicator)
}

fun getETagFromUrl(url: String): String =
HttpRequests.head(url)
.userAgent(AwsClientManager.getUserAgent())
.connect { request ->

Check warning on line 31 in plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/HttpUtils.kt

View check run for this annotation

Codecov / codecov/patch

plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/HttpUtils.kt#L29-L31

Added lines #L29 - L31 were not covered by tests
request.connection.headerFields["ETag"]?.firstOrNull().orEmpty()
}

Check warning on line 33 in plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/HttpUtils.kt

View check run for this annotation

Codecov / codecov/patch

plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/HttpUtils.kt#L33

Added line #L33 was not covered by tests
Loading