Skip to content

Conversation

@sschuberth
Copy link
Member

There is no cycle in the originally defined

depCyc2 -> depFoo -> depCyc1

dependency chain. Doing so is actually not directly possible with the recursively defined PackageReference class.

Solve that by using a primitive DependencyHandler that just uses indexes to identify dependencies.

@sschuberth
Copy link
Member Author

sschuberth commented Mar 24, 2025

@oheger-bosch, fixing the test for cyclic dependencies now actually shows that we're running into a stack overflow.

From a first glance it seems that calling breakCycles() / removeCycles() happens too late, as the recursion already happens in addDependencyToGraph() called by DependencyGraphBuilder.addDependency() before DependencyGraphBuilder.build() is called.

Can you have a look as well?

@codecov
Copy link

codecov bot commented Mar 24, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 57.47%. Comparing base (a377370) to head (a592a93).

Additional details and impacted files
@@             Coverage Diff              @@
##               main   #10083      +/-   ##
============================================
- Coverage     57.47%   57.47%   -0.01%     
+ Complexity     1704     1703       -1     
============================================
  Files           346      346              
  Lines         12855    12855              
  Branches       1222     1222              
============================================
- Hits           7389     7388       -1     
  Misses         4992     4992              
- Partials        474      475       +1     
Flag Coverage Δ
funTest-external-tools 13.71% <ø> (ø)
funTest-no-external-tools 31.02% <ø> (ø)
test-ubuntu-24.04 42.42% <ø> (-0.04%) ⬇️
test-windows-2025 42.40% <ø> (-0.04%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@oheger-bosch
Copy link
Member

It is unclear to me what you want to achieve with this PR.

The code that adds dependencies to the graph uses a set to store the nodes it already has processed and to detect cycles in the graph. Obviously, your artificial dependency handler implementation tricks this out. Not sure how realistic this is.

@sschuberth
Copy link
Member Author

sschuberth commented Mar 25, 2025

It is unclear to me what you want to achieve with this PR.

I'm currently inspecting various "strange" real-world issues that we have when analyzing Gradle or Node projects (like #9763). As part of that I was inspecting various areas of the code again, and came across this test, which does not seem to be doing what it advertises.

But do you agree that the test in its current form actually does not check that cycles are properly handled?

Obviously, your artificial dependency handler implementation tricks this out. Not sure how realistic this is.

This handler is modeled after a real-world handler where the identifiers for packages are just strings, and in order to determine transitive dependencies you need to use this string in a map of packages where each string is mapped to its direct dependencies.

@sschuberth
Copy link
Member Author

But do you agree that the test in its current form actually does not check that cycles are properly handled?

@oheger-bosch, I'd appreciate some feedback here.

@oheger-bosch
Copy link
Member

But do you agree that the test in its current form actually does not check that cycles are properly handled?

@oheger-bosch, I'd appreciate some feedback here.

Well, the test handles at least a logic cyclic dependency between some packages; although this does not seem to be a cycle in the form that you encounter. Given that this code has been developed in a test-driven style, there must have been a stage in the implementation in which this test was failing.
Maybe rename it to make the difference clearer?

@sschuberth
Copy link
Member Author

Maybe rename it to make the difference clearer?

I'd appreciate any proposals for titles then, as to me it's totally unclear what this test is supposed to cover, that is not yet covered by other tests.

@oheger-bosch
Copy link
Member

Maybe rename it to make the difference clearer?

I'd appreciate any proposals for titles then, as to me it's totally unclear what this test is supposed to cover, that is not yet covered by other tests.

If you want to remove it, I won't object.

@sschuberth
Copy link
Member Author

If you want to remove it, I won't object.

Hmm. IMO we should either make the title match the test code, or make the test code match the title. The latter is what I've originally proposed here, to gain coverage for that case. Somehow this discussion is also going in cycles 😉

@oheger-bosch
Copy link
Member

Hmm. IMO we should either make the title match the test code, or make the test code match the title. The latter is what I've originally proposed here, to gain coverage for that case. Somehow this discussion is also going in cycles 😉

Sorry, this was not my intention.

To move this forward, it is probably necessary to figure out whether there is actually a problem with such cyclic dependencies you create in your modified test (and the stack overflow seems to indicate this). So, do you have any idea why the cycle detection does not work here? The insertIntoGraph function of DependencyGraphBuilder has this set of already processed nodes. So, why does it still run in an infinite loop?

@sschuberth sschuberth force-pushed the dep-graph-cycles branch 2 times, most recently from 77e0f38 to 2d18c93 Compare April 3, 2025 10:09
@sschuberth
Copy link
Member Author

So, do you have any idea why the cycle detection does not work here?

Please see my comment above: My assumption was that cycles are not detected / broken unless breakCycles() / removeCycles() is called, which happens too late.

Or are you saying that cycle detection and breaking of cycles happens at different stages?

The insertIntoGraph function of DependencyGraphBuilder has this set of already processed nodes. So, why does it still run in an infinite loop?

I'm not sure (how it's supposed to work exactly). The only place where the set of processed nodes is amended is here, but that code is never hit when running the test. I'd appreciate if you could try to debug the new test as well, as you are way more familiar with the code than I am.

There is no cycle in the originally defined

    depCyc2 -> depFoo -> depCyc1

dependency chain. Doing so is actually not directly possible with the
recursively defined `PackageReference` class.

Solve that by using a primitive `DependencyHandler` that just uses
indexes to identify dependencies.

However, as the functionality to break cycles is not actually
implemented yet in the dependency graph builder, disable this test
temporarily until it is implemented with an upcoming change.

Signed-off-by: Sebastian Schuberth <[email protected]>
@sschuberth sschuberth marked this pull request as ready for review December 10, 2025 12:37
@sschuberth sschuberth requested a review from a team as a code owner December 10, 2025 12:37
@sschuberth sschuberth enabled auto-merge (rebase) December 10, 2025 12:37
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.

4 participants