Skip to content

Commit

Permalink
Fix integration tests
Browse files Browse the repository at this point in the history
  • Loading branch information
pkukielka committed Jul 29, 2024
1 parent 09e2ef5 commit 342dbd1
Show file tree
Hide file tree
Showing 6 changed files with 213 additions and 197 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
package com.sourcegraph.cody.edit

import com.sourcegraph.cody.edit.CodyInlineEditActionNotifier.Companion.TOPIC_DISPLAY_ACCEPT_GROUP
import com.sourcegraph.cody.edit.CodyInlineEditActionNotifier.Companion.TOPIC_DISPLAY_WORKING_GROUP
import com.sourcegraph.cody.edit.CodyInlineEditActionNotifier.Companion.TOPIC_PERFORM_ACCEPT
import com.sourcegraph.cody.edit.CodyInlineEditActionNotifier.Companion.TOPIC_PERFORM_UNDO
import com.sourcegraph.cody.edit.CodyInlineEditActionNotifier.Companion.TOPIC_TASK_FINISHED
import com.sourcegraph.cody.edit.actions.DocumentCodeAction
import com.sourcegraph.cody.edit.actions.lenses.EditAcceptAction
import com.sourcegraph.cody.edit.actions.lenses.EditCancelAction
import com.sourcegraph.cody.edit.actions.lenses.EditRetryAction
import com.sourcegraph.cody.edit.actions.lenses.EditUndoAction
import com.sourcegraph.cody.edit.widget.LensAction
Expand All @@ -17,27 +13,28 @@ import com.sourcegraph.cody.edit.widget.LensSpinner
import com.sourcegraph.cody.edit.widget.LensWidgetGroup
import com.sourcegraph.cody.util.CodyIntegrationTextFixture
import com.sourcegraph.cody.util.CustomJunitClassRunner
import org.junit.Ignore
import org.hamcrest.Matchers.startsWith
import org.junit.Assert.assertThat
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(CustomJunitClassRunner::class)
class DocumentCodeTest : CodyIntegrationTextFixture() {
@Ignore
@Test
fun testGetsWorkingGroupLens() {
runAndWaitForNotifications(DocumentCodeAction.ID, TOPIC_DISPLAY_WORKING_GROUP)
val codeLensGroup = runAndWaitForLenses(DocumentCodeAction.ID, EditCancelAction.ID)

val inlayModel = myFixture.editor.inlayModel
val blockElements = inlayModel.getBlockElementsInRange(0, myFixture.editor.document.textLength)
val lensesGroups = blockElements.mapNotNull { it.renderer as? LensWidgetGroup }

assertEquals("There should be exactly one lenses group", 1, lensesGroups.size)

assertTrue("codeLensGroup cannot be null", codeLensGroup != null)
// Lens group should match the expected structure.
val theWidgets = lensesGroups.first().widgets
val theWidgets = codeLensGroup!!.widgets

assertEquals("Lens group should have 8 widgets", 8, theWidgets.size)
assertEquals("Lens group should have 9 widgets", 9, theWidgets.size)
assertTrue("Zeroth lens group should be an icon", theWidgets[0] is LensIcon)
assertTrue(
"First lens group is space separator label", (theWidgets[1] as LensLabel).text == " ")
Expand All @@ -46,7 +43,7 @@ class DocumentCodeTest : CodyIntegrationTextFixture() {
"Third lens group is space separator label", (theWidgets[3] as LensLabel).text == " ")
assertTrue(
"Fourth lens group is a description label",
(theWidgets[4] as LensLabel).text == "Generating Code Edits")
(theWidgets[4] as LensAction).text == " Cody is working...")
assertTrue(
"Fifth lens group is separator label",
(theWidgets[5] as LensLabel).text == LensesService.SEPARATOR)
Expand All @@ -56,7 +53,7 @@ class DocumentCodeTest : CodyIntegrationTextFixture() {

@Test
fun testShowsAcceptLens() {
runAndWaitForNotifications(DocumentCodeAction.ID, TOPIC_DISPLAY_ACCEPT_GROUP)
runAndWaitForLenses(DocumentCodeAction.ID, EditAcceptAction.ID)
assertInlayIsShown()

// Lens group should match the expected structure.
Expand All @@ -73,11 +70,6 @@ class DocumentCodeTest : CodyIntegrationTextFixture() {
assertNotNull(
"Lens group should contain Accept action",
widgets.find { widget -> widget is LensAction && widget.actionId == EditAcceptAction.ID })
assertNotNull(
"Lens group should contain Show Diff action",
widgets.find { widget ->
widget is LensAction && widget.actionId == "cody.fixup.codelens.diff"
})
assertNotNull(
"Lens group should contain Show Undo action",
widgets.find { widget -> widget is LensAction && widget.actionId == EditUndoAction.ID })
Expand All @@ -92,21 +84,31 @@ class DocumentCodeTest : CodyIntegrationTextFixture() {
@Test
fun testAccept() {
assertNoInlayShown()
runAndWaitForNotifications(DocumentCodeAction.ID, TOPIC_DISPLAY_ACCEPT_GROUP)
val acceptLens = runAndWaitForLenses(DocumentCodeAction.ID, EditAcceptAction.ID)
assertTrue("Accept lens should be displayed", acceptLens != null)
assertInlayIsShown()
runAndWaitForNotifications(EditAcceptAction.ID, TOPIC_PERFORM_ACCEPT, TOPIC_TASK_FINISHED)

runLensAction(acceptLens!!, EditAcceptAction.ID)
assertNoInlayShown()
assertThat(
myFixture.editor.document.text,
startsWith(
"""/**
| * Imports the necessary Java standard library classes for the Foo class, including the ArrayList class.
| */"""
.trimMargin()))
}

@Test
fun testUndo() {
val originalDocument = myFixture.editor.document.text
runAndWaitForNotifications(DocumentCodeAction.ID, TOPIC_DISPLAY_ACCEPT_GROUP)
val undoLens = runAndWaitForLenses(DocumentCodeAction.ID, EditUndoAction.ID)
assertTrue("Undo lens should be displayed", undoLens != null)
assertNotSame(
"Expected document to be changed", originalDocument, myFixture.editor.document.text)
assertInlayIsShown()

runAndWaitForNotifications(EditUndoAction.ID, TOPIC_PERFORM_UNDO, TOPIC_TASK_FINISHED)
runLensAction(undoLens!!, EditUndoAction.ID)
assertEquals(
"Expected document changes to be reverted",
originalDocument,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,38 @@ import com.intellij.testFramework.EditorTestUtil
import com.intellij.testFramework.PlatformTestUtil
import com.intellij.testFramework.fixtures.BasePlatformTestCase
import com.intellij.testFramework.runInEdtAndWait
import com.intellij.util.messages.Topic
import com.sourcegraph.cody.agent.CodyAgentService
import com.sourcegraph.cody.agent.protocol_generated.ProtocolCodeLens
import com.sourcegraph.cody.config.CodyPersistentAccountsHost
import com.sourcegraph.cody.config.SourcegraphServerPath
import com.sourcegraph.cody.edit.CodyInlineEditActionNotifier
import com.sourcegraph.cody.edit.LensListener
import com.sourcegraph.cody.edit.LensesService
import com.sourcegraph.cody.edit.widget.LensAction
import com.sourcegraph.cody.edit.widget.LensWidgetGroup
import com.sourcegraph.config.ConfigUtil
import java.io.File
import java.nio.file.Paths
import java.util.concurrent.CompletableFuture
import java.util.concurrent.TimeUnit
import java.util.regex.Pattern

open class CodyIntegrationTextFixture : BasePlatformTestCase() {
open class CodyIntegrationTextFixture : BasePlatformTestCase(), LensListener {
private val logger = Logger.getInstance(CodyIntegrationTextFixture::class.java)
private val lensSubscribers =
mutableListOf<
Pair<(List<ProtocolCodeLens>) -> Boolean, CompletableFuture<LensWidgetGroup?>>>()

override fun setUp() {
super.setUp()
configureFixture()
checkInitialConditions()
myProject = project
LensesService.getInstance(project).addListener(this)
}

override fun tearDown() {
try {
LensesService.getInstance(project).removeListener(this)
CodyAgentService.getInstance(myFixture.project).apply {
try {
stopAgent(project)
Expand Down Expand Up @@ -200,39 +208,59 @@ open class CodyIntegrationTextFixture : BasePlatformTestCase() {
}
}

protected fun runAndWaitForNotifications(
actionId: String,
vararg topic: Topic<CodyInlineEditActionNotifier>
override fun onLensesUpdate(
uri: String,
taskId: String?,
lensWidgetGroup: LensWidgetGroup?,
codeLenses: List<ProtocolCodeLens>
) {
val futures = topic.associateWith { subscribeToTopic(it) }
triggerAction(actionId)
futures.forEach { (t, f) ->
try {
f.get()
} catch (e: Exception) {
assertTrue(
"Error while awaiting ${t.displayName} notification: ${e.localizedMessage}", false)
synchronized(lensSubscribers) {
lensSubscribers.removeAll { (checkFunc, future) ->
val hasLensAppeared = checkFunc(codeLenses)
if (hasLensAppeared) future.complete(lensWidgetGroup)
hasLensAppeared
}
}
}

// Returns a future that completes when the topic is published.
private fun subscribeToTopic(
topic: Topic<CodyInlineEditActionNotifier>,
): CompletableFuture<Void> {
val future = CompletableFuture<Void>().orTimeout(ASYNC_WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS)
project.messageBus
.connect()
.subscribe(
topic,
object : CodyInlineEditActionNotifier {
override fun afterAction() {
logger.warn("Notification sent for topic '${topic.displayName}'")
future.complete(null)
}
})
logger.warn("Subscribed to topic: $topic")
return future
fun runAndWaitForLenses(actionId: String, actionLensId: String): LensWidgetGroup? {
val future = CompletableFuture<LensWidgetGroup?>()
val check = { codeLens: List<ProtocolCodeLens> ->
codeLens.any { it.command?.command == actionLensId }
}
lensSubscribers.add(check to future)

triggerAction(actionId)

try {
return future.get(ASYNC_WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS)
} catch (e: Exception) {
assertTrue(
"Error while awaiting condition after for action $actionId: ${e.localizedMessage}", false)
throw e
}
}

fun runLensAction(lensWidgetGroup: LensWidgetGroup, actionId: String): LensWidgetGroup? {
val future = CompletableFuture<LensWidgetGroup?>()
val check = { codeLens: List<ProtocolCodeLens> -> codeLens.isEmpty() }
lensSubscribers.add(check to future)

runInEdtAndWait {
val action: LensAction? =
lensWidgetGroup.widgets.filterIsInstance<LensAction>().find { it.actionId == actionId }
PlatformTestUtil.dispatchAllEventsInIdeEventQueue()
assertTrue("Lens action $actionId should be available", action != null)
action?.triggerAction(myFixture.editor)
}

try {
return future.get(ASYNC_WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS)
} catch (e: Exception) {
assertTrue(
"Error while awaiting condition after for action $actionId: ${e.localizedMessage}", false)
throw e
}
}

protected fun hasJavadocComment(text: String): Boolean {
Expand All @@ -242,7 +270,7 @@ open class CodyIntegrationTextFixture : BasePlatformTestCase() {
}

companion object {
const val ASYNC_WAIT_TIMEOUT_SECONDS = 10L
const val ASYNC_WAIT_TIMEOUT_SECONDS = 15L
var myProject: Project? = null
}
}
Loading

0 comments on commit 342dbd1

Please sign in to comment.