Skip to content

Conversation

@shawn-hurley
Copy link
Contributor

@shawn-hurley shawn-hurley commented Dec 2, 2025

Adding tests for other parts of the engine as well as verifying the long action of the code snipper is happening asynchronously

Fixes #1017

Summary by CodeRabbit

  • Refactor

    • Rule engine now returns violation-centric results, streamlines worker startup and processing, and standardizes tag/variable handling and templating to a single, more consistent type for reliable outputs.
  • Tests

    • Expanded coverage for tagging, deduplication, templating, incident limits, code-snippet latency, and end-to-end violation creation and filtering scenarios.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 2, 2025

Warning

Rate limit exceeded

@shawn-hurley has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 7 minutes and 40 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 400e280 and 95c89fd.

📒 Files selected for processing (2)
  • engine/engine.go (10 hunks)
  • engine/engine_test.go (7 hunks)

Walkthrough

Long-running work (e.g., code-snippet fetching and templating) was moved from the collector into worker goroutines; worker return payloads now carry a Violation pointer instead of ConditionResponse; several functions became ruleEngine methods; map types changed from map[string]interface{} to map[string]any and maps.Copy was introduced.

Changes

Cohort / File(s) Summary
Core Engine Implementation
engine/engine.go
Replaced ConditionResponse in worker/results with Violation *konveyor.Violation; response struct fields updated. processRuleWorker converted to a ruleEngine method and workers are started via r.processRuleWorker. Long-running actions (code-snippet fetching, templating/violation creation) moved into worker threads. Switched context/tag/incident maps to map[string]any and added maps.Copy. Helper signatures updated (e.g., createPerformString). Worker lifecycle/progress reporting adapted to Violation-centric flow.
Tests and Test Utilities
engine/engine_test.go
Tests updated to use any and map[string]any; added/updated helpers (testTemplateConditional, testCodeSnipper) and new/expanded tests (TestRunTaggingRules, enhanced TestCreateViolation) covering tagging, templating, deduplication, incident limits, code-snippet latency, and selector filtering.

Sequence Diagram(s)

sequenceDiagram
    participant Worker as Worker (r.processRuleWorker)
    participant Engine as ruleEngine (evaluate/create)
    participant Snipper as Code Snippet Fetcher
    participant Collector as Collector/Aggregator

    Note over Worker,Collector: Long-running tasks moved into workers
    Worker->>Engine: receive ruleMessage / evaluate condition
    alt condition matches
        Engine->>Snipper: fetch code snippet (long-running)
        activate Snipper
        Snipper-->>Engine: snippet data
        deactivate Snipper
        Engine->>Engine: create Violation (templating, incidents)
        Engine-->>Worker: response with Violation
    else no match
        Engine-->>Worker: response without Violation
    end
    Worker->>Collector: send response (includes Violation or empty)
    Collector->>Collector: aggregate results (no long-running tasks)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Inspect worker startup and context/goroutine lifecycle changes in processRuleWorker.
  • Verify code-snippet fetching and templating now run in workers (no fan-in blocking).
  • Check all map type changes (map[string]interface{}map[string]any) and correct use of maps.Copy.
  • Review createViolation, incident deduplication, label handling, and rule/insight classification.
  • Run and validate new/updated tests for flakiness (async/snippet delays).

Poem

🐰 I hopped into code with nimble feet,

Moved slow snips so collectors keep the beat,
Violations sprout where workers play,
Tags in any now cheer the day,
A carrot of tests — concise and sweet. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title references moving time-taking actions of creating violations, which directly aligns with the PR's core objective of performing long-running code snippet operations asynchronously in worker threads instead of the fan-in thread.
Linked Issues check ✅ Passed The PR successfully addresses issue #1017 by refactoring the response structure to hold Violation pointers, converting processRuleWorker to a receiver method that can perform violations creation in worker context, and moving long-running operations (code snippets) out of the collector/fan-in thread.
Out of Scope Changes check ✅ Passed The PR includes type modernization changes (map[string]interface{} to map[string]any) that support the core refactoring but are not strictly necessary for moving violations creation; however, these are minor and support Go 1.18+ conventions without deviating from the main objective.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
engine/engine_test.go (2)

500-505: Consider making sleep duration configurable or shorter for faster tests.

A 10-second sleep per code snippet is quite long for unit tests. While it serves to demonstrate parallelism, consider using a shorter duration (e.g., 100-500ms) that still proves the point without significantly extending CI time.

 func (t *testCodeSnipper) GetCodeSnip(uri.URI, Location) (string, error) {
-	time.Sleep(10 * time.Second)
+	time.Sleep(500 * time.Millisecond)
 	return "test code snip", nil
 }

Then adjust the timeout assertion accordingly:

-if time.Since(start) >= 11*time.Second {
+if time.Since(start) >= 2*time.Second {

1729-1771: Test creates files in /tmp - consider using t.TempDir().

Using a hardcoded /tmp path could cause issues in parallel test runs or on systems with different temp directory conventions.

-testFile := "/tmp/test_custom_var.java"
+testFile := filepath.Join(t.TempDir(), "test_custom_var.java")

Note: This would require adding "path/filepath" to imports. The benefit is that t.TempDir() automatically cleans up after the test and provides isolation.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3d1bb23 and 6e42d49.

📒 Files selected for processing (2)
  • engine/engine.go (10 hunks)
  • engine/engine_test.go (7 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: test
  • GitHub Check: benchmark (macos-latest, mac)
  • GitHub Check: test (ubuntu-latest, linux, amd64)
  • GitHub Check: test (windows-latest, windows, amd64)
  • GitHub Check: test (macos-latest, darwin, amd64)
  • GitHub Check: test (macos-latest, darwin, arm64)
  • GitHub Check: test (ubuntu-latest, linux, arm64)
  • GitHub Check: benchmark (ubuntu-latest, linux)
  • GitHub Check: benchmark (windows-latest, windows)
🔇 Additional comments (6)
engine/engine.go (4)

174-210: Core objective achieved: violation creation moved to worker thread.

The refactoring correctly moves createViolation (which includes the potentially slow getCodeLocation call) from the collector goroutine into the worker goroutine. This ensures code snippet fetching happens in parallel across workers rather than sequentially in the fan-in thread.


307-319: Response handling logic correctly updated for new Violation-centric flow.

The check len(response.Violation.Incidents) > 0 properly handles the case where a rule matched but all incidents were filtered out (e.g., by scope or incident selector), treating it as unmatched.


474-476: Good use of maps.Copy for safe variable copying.

Using maps.Copy prevents mutation of the original incident.Variables map when adding lineNumber, which could cause subtle bugs if the same incident is processed multiple times or in different contexts.


152-156: Verify Go version requirement in go.mod.

for i := range workers is a Go 1.22+ feature. Confirm the project's minimum Go version supports this syntax, or refactor to traditional index loop for i := 0; i < len(workers); i++ for compatibility with earlier Go versions.

engine/engine_test.go (2)

1186-1437: Comprehensive test coverage for tagging rules.

Good test coverage for the runTaggingRules function including:

  • Basic tag creation
  • Tags with effort creating violations vs insights
  • Template tags with variable substitution
  • Unmatched rules
  • Error handling
  • Tag deduplication
  • UsesHasTags sorting behavior

1439-1905: Comprehensive test coverage for violation creation.

Thorough test suite covering:

  • Basic violation creation
  • Incident limiting
  • Code snip limiting
  • Message template rendering with variables
  • Duplicate incident filtering
  • Label deduplication
  • Custom variables with named capture groups
  • Custom variables with default values
  • Incident selector filtering

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
engine/engine_test.go (1)

694-849: Test does not validate parallel code snippet fetching.

This test case has the same issue previously identified: all AndCondition blocks evaluate to false (AND of false && true), so no rules match, createViolation is never called, and testCodeSnipper.GetCodeSnip is never invoked. The test passes quickly not due to parallelism, but because the slow operation is never executed.

To fix, change the first condition in each AndCondition to return true:

 When: AndCondition{
   Conditions: []ConditionEntry{
     {
-      ProviderSpecificConfig: createTestConditional(false, nil, false),
+      ProviderSpecificConfig: createTestConditional(true, nil, false),
     },
     {
       ProviderSpecificConfig: createTestConditional(true, nil, false),
     },
   },
 },
🧹 Nitpick comments (2)
engine/engine_test.go (1)

1218-1227: Unsafe type assertions may panic instead of failing gracefully.

Direct type assertions like resultContext.Tags["Java"].(bool) will panic if the key doesn't exist or the value is nil, causing the test to crash rather than report a proper failure.

Use the comma-ok idiom for safer assertions:

 checkFunc: func(t *testing.T, resultContext ConditionContext, rs *konveyor.RuleSet) {
-    if !resultContext.Tags["Java"].(bool) {
+    val, ok := resultContext.Tags["Java"]
+    if !ok || val != true {
         t.Error("Expected 'Java' tag in context")
     }
-    if !resultContext.Tags["Migration"].(bool) {
+    val, ok = resultContext.Tags["Migration"]
+    if !ok || val != true {
         t.Error("Expected 'Migration' tag in context")
     }

This pattern should be applied to similar assertions at lines 1276-1278 as well.

engine/engine.go (1)

189-203: Consider guarding createViolation when processRule returns an error.

If processRule returns an error, the worker still checks conditionResponse.Matched and may call createViolation. While the collector correctly prioritizes error handling, this could waste time on the long-running violation creation when it will ultimately be discarded.

 conditionResponse, err := processRule(ctx, m.rule, m.conditionContext, newLogger)
 logger.V(5).Info("finished rule", "found", len(conditionResponse.Incidents), "matched", conditionResponse.Matched, "error", err, "rule", m.rule.RuleID)
 response := response{
     Err:         err,
     Rule:        m.rule,
     RuleSetName: m.ruleSetName,
 }
-if conditionResponse.Matched {
+if err == nil && conditionResponse.Matched {
     violation, err := r.createViolation(ctx, conditionResponse, m.rule, m.scope)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6e42d49 and 9b33729.

📒 Files selected for processing (2)
  • engine/engine.go (10 hunks)
  • engine/engine_test.go (7 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
engine/engine_test.go (2)
engine/conditions.go (5)
  • ConditionResponse (19-25)
  • IncidentContext (51-58)
  • Location (60-63)
  • Position (65-83)
  • CodeSnip (89-91)
engine/engine.go (3)
  • WithIncidentLimit (99-103)
  • WithCodeSnipLimit (111-115)
  • WithIncidentSelector (117-121)
engine/engine.go (2)
output/v1/konveyor/violations.go (1)
  • Violation (79-101)
engine/conditions.go (1)
  • Rule (101-107)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: test
  • GitHub Check: test (ubuntu-latest, linux, amd64)
  • GitHub Check: test (windows-latest, windows, amd64)
  • GitHub Check: test (macos-latest, darwin, arm64)
  • GitHub Check: test (macos-latest, darwin, amd64)
  • GitHub Check: test (ubuntu-latest, linux, arm64)
  • GitHub Check: benchmark (windows-latest, windows)
  • GitHub Check: benchmark (macos-latest, mac)
  • GitHub Check: benchmark (ubuntu-latest, linux)
🔇 Additional comments (10)
engine/engine_test.go (4)

52-84: Type updates to any look good.

The switch from interface{} to any is consistent with modern Go style and aligns with the changes in engine.go.


91-111: Good test helper for template variable testing.

The testTemplateConditional provides deterministic test data for validating template tag substitution with variables.


498-503: Test mock correctly simulates slow code snippet fetching.

The 10-second delay is intentional for validating that snippet fetching happens in parallel across workers rather than sequentially in the collector thread.


1437-1781: Comprehensive test coverage for createViolation.

The test structure using setupFunc/checkFunc with cleanup is well-designed. Good coverage of:

  • Basic violation creation
  • Incident and code snip limits
  • Message template variable substitution
  • Duplicate incident filtering
  • Label deduplication
  • Incident selector filtering
engine/engine.go (6)

59-64: Response struct redesign supports the PR objective.

The Violation-centric response allows workers to create violations (including code snippets) before sending results back through the channel, moving the long-running work out of the collector thread as intended.


250-253: Type consistency with map[string]any.

The change aligns with the broader switch to any throughout the codebase.


307-319: Violation-based response handling is correct.

The check len(response.Violation.Incidents) > 0 properly distinguishes matched rules from unmatched ones, and the effort-based categorization (Violations vs Insights) is preserved.


474-479: Defensive copy prevents mutation of original incident variables.

Using maps.Copy to create a working copy before adding lineNumber is good practice, ensuring the original incident.Variables remains unmodified.


689-693: Consistent pattern for variable map handling.

Same defensive copy pattern as used in runTaggingRules, maintaining consistency.


152-156: Verify Go version supports range-over-integer.

The for i := range workers syntax is a Go 1.22+ feature. Ensure the project's go.mod specifies Go 1.22 or later.

log.Error(err, "unable to create violation from response")
} else if len(response.Violation.Incidents) > 0 {
atomic.AddInt32(&matchedRules, 1)
rs, ok := mapRuleSets[response.RuleSetName]
Copy link
Contributor

Choose a reason for hiding this comment

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

what if its unmatched?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Konveyor.Violation doesn't have a matched/unmatched, which is used by the worker to determine if we need to create a violation.

I have an idea on how to make it more clear, pushing up a fix.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated to make the violation a pointer, which will be nil if unmatched or has no incidents.

Let me know if that works for you?

Copy link
Contributor

Choose a reason for hiding this comment

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

@shawn-hurley this is looking better. But still not following where exactly is "Unmatched" part of output is populated

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is this what you are asking about? https://github.com/konveyor/analyzer-lsp/pull/1020/files#diff-2e6c4934f63ff9b712c2c346b33036af4724adf70b0801fff9b74f71b37fcd89R330

The core of the logic is the same, if there is an Err handle the error, if it is matched and the incidents > 0 (or violation.Incidents > 0 after creation) then mark it as matched if not then the else block will add it as unmatched.

Copy link
Contributor

Choose a reason for hiding this comment

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

ahhh there's still another else block handling the unmatched part. Okay makes sense. Sorry I only looked at the diff and thought you removed the unmatched part.

@shawn-hurley shawn-hurley force-pushed the issue/issue-1017 branch 3 times, most recently from 674c659 to 9ead53d Compare December 2, 2025 18:00
Adding test's for other parts of the engine as well as verifing the long
action of code snipper is happening asyncrounsly

Signed-off-by: Shawn Hurley <[email protected]>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
engine/engine.go (1)

135-159: Fix worker spawn loop: range over an int does not compile

CreateRuleEngine currently uses for i := range workers { ... } where workers is an int. This does not compile and prevents the engine from starting.

Use a standard counted loop instead:

-	for i := range workers {
-		logger := log.WithValues("worker", i)
-		wg.Add(1)
-		go r.processRuleWorker(ctx, ruleProcessor, logger, wg)
-	}
+	for i := 0; i < workers; i++ {
+		logger := log.WithValues("worker", i)
+		wg.Add(1)
+		go r.processRuleWorker(ctx, ruleProcessor, logger, wg)
+	}
♻️ Duplicate comments (1)
engine/engine_test.go (1)

498-503: Snipper parallelism test still doesn’t exercise GetCodeSnip and timing assumption is off

This new TestRuleEngine case is intended to verify that code-snippet fetching happens in parallel across workers, but there are two problems:

  1. testCodeSnipper.GetCodeSnip is never called

    • createTestConditional(true, nil, false) produces incidents without CodeLocation.
    • createViolation only calls getCodeLocation (and thus the snipper) when m.CodeLocation != nil.
    • As a result, getCodeLocation returns early and testCodeSnipper’s time.Sleep(10 * time.Second) is never hit.
    • The test passes quickly regardless of whether snippet fetching is parallel or still in the collector goroutine.
  2. Worker count vs. rule count makes the 11s threshold unrealistic if snips were fetched

    • This test case defines 11 rules that all use testCodeSnipper, but CreateRuleEngine is called with workers = 10.
    • If GetCodeSnip really slept for 10s per rule and ran only in workers, the total time would be ~20s (10 rules in parallel + 1 sequential), so the time.Since(start) >= 11*time.Second check would be violated even in a correct implementation.

To actually test parallel snipper execution and keep the timing assertion meaningful, I suggest:

  • Introduce a conditional that returns incidents with a non-nil CodeLocation so getCodeLocation will invoke rule.Snipper.GetCodeSnip.
  • Either:
    • Reduce the number of snip-enabled rules to match the worker count (10 rules with 10 workers and a 10s sleep, keeping the < 11s threshold), or
    • Increase the worker count to be at least the number of rules, or
    • Relax the timing assertion to something like < 2 * sleepDuration and document the reasoning.

For example, one direction would be:

- ruleEngine := CreateRuleEngine(context.Background(), 10, log)
+ ruleEngine := CreateRuleEngine(context.Background(), 11, log)

and change createTestConditional (or add a new helper) so the returned IncidentContext sets a realistic CodeLocation.

Also applies to: 694-759, 762-776

🧹 Nitpick comments (2)
engine/engine.go (1)

59-64: Worker now owns violation creation – behavior looks consistent with collector logic

The refactor to have processRuleWorker call processRule and then createViolation, and to send back a response with Violation *konveyor.Violation instead of a ConditionResponse, is internally consistent:

  • Collector now branches purely on Err vs Violation != nil vs neither, keeping fan-in work lightweight.
  • Matched rules with incidents produce a violation in the worker; rules with no incidents or unmatched conditions are correctly treated as unmatched by the collector.
  • Tagging rules still use runTaggingRules with the same Matched && len(Incidents) > 0 semantics, so overall behavior is preserved while moving code-snippet work to workers.

One small cleanliness nit: inside the worker loop you mutate ctx via ctx = prop.Extract(ctx, m.carrier), which means later iterations build spans off the previously extracted context rather than the original worker context. It would be slightly clearer to keep the loop-local context separate:

-			ctx = prop.Extract(ctx, m.carrier)
-			conditionResponse, err := processRule(ctx, m.rule, m.conditionContext, newLogger)
+			ruleCtx := prop.Extract(ctx, m.carrier)
+			conditionResponse, err := processRule(ruleCtx, m.rule, m.conditionContext, newLogger)

This avoids any accidental cross-contamination between rule evaluations.

Also applies to: 174-205

engine/engine_test.go (1)

1347-1691: TestCreateViolation aligns closely with createViolation logic

The new TestCreateViolation cases validate key aspects of createViolation:

  • Basic violation creation and propagation of description and incident messages.
  • Incident limiting (WithIncidentLimit) and basic code-snippet limiting (WithCodeSnipLimit).
  • Message templating with both rule variables and lineNumber.
  • Duplicate incident suppression, label deduplication, and incident-selector filtering.

One small note: the “code snip limit” test asserts that at most one incident has a non-empty CodeSnip, but because the test file path is synthetic, getCodeLocation will likely fail and produce empty snippets for all incidents. The test still correctly validates “no more than one snippet” via the limit counter, but does not prove that one snippet is actually produced. If you want stronger coverage of the positive path, consider wiring a fake provider/snipper that always returns a non-empty snippet for a given FileURI.

Otherwise, the tests look consistent with the implementation.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9b33729 and 400e280.

📒 Files selected for processing (2)
  • engine/engine.go (10 hunks)
  • engine/engine_test.go (7 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
engine/engine.go (2)
output/v1/konveyor/violations.go (1)
  • Violation (79-101)
engine/conditions.go (1)
  • Rule (101-107)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: test
  • GitHub Check: test (ubuntu-latest, linux, amd64)
  • GitHub Check: test (ubuntu-latest, linux, arm64)
  • GitHub Check: test (windows-latest, windows, amd64)
  • GitHub Check: test (macos-latest, darwin, amd64)
  • GitHub Check: test (macos-latest, darwin, arm64)
  • GitHub Check: benchmark (macos-latest, mac)
  • GitHub Check: benchmark (ubuntu-latest, linux)
  • GitHub Check: benchmark (windows-latest, windows)
🔇 Additional comments (6)
engine/engine.go (3)

251-265: ConditionContext.Tags type change and tag templating look correct

The move to Tags: make(map[string]any) in ConditionContext, plus using maps.Copy when building the tag templating variables in runTaggingRules, is consistent and matches the new tests:

  • Tags continue to be stored as booleans (context.Tags[tag] = true), which the tests type-assert back to bool.
  • Template-based tags (Framework={{name}}) are rendered via createPerformString and then parsed by parseTagsFromPerformString as expected.

No issues spotted with the updated tagging flow.

Also applies to: 441-539


597-742: createViolation refactor is aligned with new behavior and tests

The updated createViolation implementation looks sound and matches the new test coverage:

  • Incident limiting (WithIncidentLimit) and code-snippet limiting (WithCodeSnipLimit) are enforced per file via incidentLimit and fileCodeSnipCount.
  • Scope and incidentSelector filtering are applied before deduplication; duplicates are prevented via a stable incidentString key.
  • Message templates now use a map[string]any variables map with maps.Copy, and lineNumber is injected so templates like {{lineNumber}} work as tested.
  • Labels are deduplicated once at the end via deduplicateLabels.

Given getCodeLocation now only runs inside workers (via this function), this also correctly moves snipper work out of the collector goroutine.


744-795: getCodeLocation and createPerformString helpers are consistent with refactor

getCodeLocation now sits purely behind createViolation, and createPerformString wraps mustache.Render with a map[string]any context. That matches the new tests around templated messages and tags and ensures all templating logic goes through a single helper.

No functional issues spotted here.

Also applies to: 797-799

engine/engine_test.go (3)

49-63: TemplateContext type updates to any are consistent

Switching testChainableConditionalAs.AsValue / FromValue to any and using map[string]any for TemplateContext matches the production types and keeps the chainable-condition tests aligned with engine changes. The existing equality checks via reflect.DeepEqual remain valid.

Also applies to: 69-89


91-112: testTemplateConditional correctly drives template-based tagging

testTemplateConditional returns a matched ConditionResponse with:

  • A concrete LineNumber
  • Variables including "name": "Spring"

This is exactly what runTaggingRules needs to exercise templated tags (Framework={{name}}) and the new map[string]any variable handling. The implementation looks correct.


1094-1345: TestRunTaggingRules thoroughly exercises tagging behavior

The new TestRunTaggingRules table tests cover:

  • Basic tag creation and propagation into ConditionContext.Tags and RuleSet.Tags.
  • Effort-bearing tag rules becoming violations instead of insights.
  • Template-based tags via testTemplateConditional and createPerformString.
  • Unmatched tagging rules populating RuleSet.Unmatched.
  • Error paths writing into RuleSet.Errors.
  • Cross-rule tag deduplication and UsesHasTags ordering.

These align well with the updated runTaggingRules implementation in engine.go. The tests look correct and valuable for guarding future changes.

@shawn-hurley shawn-hurley enabled auto-merge (squash) December 2, 2025 18:32
log.Error(err, "unable to create violation from response")
} else if len(response.Violation.Incidents) > 0 {
atomic.AddInt32(&matchedRules, 1)
rs, ok := mapRuleSets[response.RuleSetName]
Copy link
Contributor

Choose a reason for hiding this comment

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

ahhh there's still another else block handling the unmatched part. Okay makes sense. Sorry I only looked at the diff and thought you removed the unmatched part.

@shawn-hurley shawn-hurley merged commit 64dd03a into konveyor:main Dec 3, 2025
20 of 21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[bug] Engine code does long running tasks in Fan-In thread

2 participants