Skip to content

High overhead in FileSource due to repeated canonical path resolution during test discovery #4630

@lslonina

Description

@lslonina

🤔 Problem Description
I'm experiencing high overhead during test discovery in projects using Cucumber-JVM with the JUnit Platform Engine. Specifically, the issue stems from repeated calls to File.getCanonicalFile() inside FileSource.

In our setup:

  • 200+ feature files
  • 6000+ containers
  • 20,000+ test cases

Runtime: Windows 11 + FSlogix (actually that could be the main culprit for slow FS access), Java: 21

Discovery takes 60–70 seconds, primarily spent in canonical path resolution via:

FeatureOrigin.java#L90

FileSource.java#L73

✨ Proposed Solution
I like to propose a minor enhancement to JUnit's FileSource:

Add a static factory method:

	/**
	 * Create a new {@code FileSource} from an existing instance but with a different
	 * {@link FilePosition}. This avoids redundant canonical path resolution.
	 *
	 * @param source the existing {@code FileSource}; must not be {@code null}
	 * @param filePosition the new {@code FilePosition}; may be {@code null}
	 * @return a new {@code FileSource} with same file and updated position
	 */
	public static FileSource withPosition(FileSource source, @Nullable FilePosition filePosition) {
		Preconditions.notNull(source, "source must not be null");
		return direct(source.file, filePosition); // new FileSource without canonicalPath call
	}

This would reuse an already-canonical File from an existing FileSource, avoiding the repeated and expensive getCanonicalFile() call.

🛠️ Workarounds We've Tried

  • We implemented a custom CachingFileSource variant to avoid repeated canonicalization. Since FileSource has private constructors, this required duplicating its entire implementation. With caching in place, discovery time dropped from ~60s to ~5s.
  • We also experimented with parallelizing feature parsing in Cucumber, which reduced overall time to ~20s, but did not address the core overhead from canonical path resolution.

🔄 Alternatives Considered
While this could be implemented on the Cucumber side, it currently requires duplicating the entire FileSource logic, unless JUnit provides extension points or additional factory methods.

Cucumber-jvm Issue for the same

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions