Skip to content

🧪 Add comprehensive unit tests for transfer-pvc command - #355

Open
RanWurmbrand wants to merge 3 commits into
migtools:mainfrom
RanWurmbrand:transfer-pvc-unit-tests
Open

🧪 Add comprehensive unit tests for transfer-pvc command#355
RanWurmbrand wants to merge 3 commits into
migtools:mainfrom
RanWurmbrand:transfer-pvc-unit-tests

Conversation

@RanWurmbrand

@RanWurmbrand RanWurmbrand commented May 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds 41 unit tests for the transfer-pvc command, covering validation, flag parsing, PVC construction, rsync options, cluster helpers, and resource cleanup. All tests use fake Kubernetes clients with no external dependencies.

What's covered

Flag types and parsing

  • mappedNameVarString(), Set(), Type() for source:destination mapping
  • quantityVarString(), Set(), Type() for storage quantity parsing
  • endpointTypeSet(), Type() for nginx-ingress and route validation
  • parseSourceDestinationMapping — valid mappings, edge cases, empty input

Validation

  • TransferPVCCommand.Validate — nil contexts, same-cluster detection, cascading PVC and endpoint validation errors, success path
  • EndpointFlags.Validate — nginx requires subdomain, route does not, empty type defaults to nginx
  • PvcFlags.Validate — empty source/destination name and namespace checks

PVC building

  • buildDestinationPVC — copies labels, access modes, and storage requests from source; overrides storage requests and storage class from flags; clears VolumeMode and VolumeName so destination binds to a new PV

Rsync transfer options

  • verify — adds --checksum when enabled, strips --checksum and -c when disabled while preserving other flags
  • restrictedContainers — disables privilege options and adds --omit-dir-times when true; enables them when false
  • verbose — sets Info array and appends --progress flag

Route and node helpers

  • getRouteHostName — returns nil for short prefixes, truncates to 62 chars and appends ingress domain for long prefixes, errors when Ingress config is missing
  • getNodeNameForPVC — finds running pod with matching PVC volume, returns empty when no pods match, skips non-running pods

Namespace ID parsing

  • getIDsForNamespace — extracts UID/GID from security annotations, returns nil fields when annotations are missing, errors on nonexistent namespace

Resource cleanup

  • deleteResourcesIteratively — deletes by label, scoped to namespace, handles multiple resource types, no error when empty
  • garbageCollect — cleans up source cluster resources (Pods, ConfigMaps, Secrets) and destination endpoint resources (Ingress for nginx, Route for route)

Resource name validation

  • getValidatedResourceName — returns original name under 63 chars, returns crane- prefixed MD5 hash for long names

Test plan

  • go test -v ./cmd/transfer-pvc/... — all 41 tests pass

Summary by CodeRabbit

  • Tests
    • Significantly expanded test suite for transfer-pvc with comprehensive unit tests covering command/flag validation, destination PVC construction behavior, rsync option configuration, route host naming, PVC node selection, iterative resource cleanup, garbage collection across clusters, and resource name validation rules.

@coderabbitai

coderabbitai Bot commented May 6, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1111e282-4c50-4213-aa53-644aaa1c4c16

📥 Commits

Reviewing files that changed from the base of the PR and between c752cb2 and 9a03be4.

📒 Files selected for processing (1)
  • cmd/transfer-pvc/transfer-pvc_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • cmd/transfer-pvc/transfer-pvc_test.go

📝 Walkthrough

Walkthrough

The PR expands cmd/transfer-pvc/transfer-pvc_test.go with unit tests for command and flag validation, PVC construction, rsync options, route and node resolution, resource cleanup, garbage collection, and resource naming.

Changes

Transfer-PVC test coverage

Layer / File(s) Summary
Validation and PVC behavior
cmd/transfer-pvc/transfer-pvc_test.go
Tests command and flag validation, custom variable parsing and representation, and destination PVC field mapping with storage and storage-class overrides.
Transfer options and resource resolution
cmd/transfer-pvc/transfer-pvc_test.go
Tests checksum, restricted-container, and verbose rsync options, route hostname generation, and node selection from running PVC-consuming pods.
Cleanup and resource naming
cmd/transfer-pvc/transfer-pvc_test.go
Tests namespace- and label-filtered deletion, source and destination garbage collection, and short or long validated resource names.

Estimated code review effort: 3 (Moderate) | ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 78.05% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ 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 clearly summarizes the main change: adding comprehensive unit tests for the transfer-pvc command.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@github-actions

github-actions Bot commented May 6, 2026

Copy link
Copy Markdown

Test Coverage Report

Total: 45.3%

Per-package coverage

  • github.com/konveyor/crane — 0.0%
  • github.com/konveyor/crane/cmd/apply — 33.3%
  • github.com/konveyor/crane/cmd/convert — 0.0%
  • github.com/konveyor/crane/cmd/export — 93.1%
  • github.com/konveyor/crane/cmd/plugin-manager — 0.0%
  • github.com/konveyor/crane/cmd/plugin-manager/add — 0.0%
  • github.com/konveyor/crane/cmd/plugin-manager/list — 0.0%
  • github.com/konveyor/crane/cmd/plugin-manager/remove — 0.0%
  • github.com/konveyor/crane/cmd/runfn — 0.0%
  • github.com/konveyor/crane/cmd/skopeo-sync-gen — 0.0%
  • github.com/konveyor/crane/cmd/transfer-pvc — 49.2%
  • github.com/konveyor/crane/cmd/transform — 0.0%
  • github.com/konveyor/crane/cmd/transform/listplugins — 0.0%
  • github.com/konveyor/crane/cmd/transform/optionals — 0.0%
  • github.com/konveyor/crane/cmd/tunnel-api — 0.0%
  • github.com/konveyor/crane/cmd/validate — 35.3%
  • github.com/konveyor/crane/cmd/version — 0.0%
  • github.com/konveyor/crane/internal/apply — 26.1%
  • github.com/konveyor/crane/internal/file — 68.6%
  • github.com/konveyor/crane/internal/flags — 0.0%
  • github.com/konveyor/crane/internal/plugin — 32.9%
  • github.com/konveyor/crane/internal/transform — 78.1%
  • github.com/konveyor/crane/internal/validate — 55.1%
Full function-level details
github.com/konveyor/crane/cmd/apply/apply.go:36:			Complete				100.0%
github.com/konveyor/crane/cmd/apply/apply.go:40:			Validate				100.0%
github.com/konveyor/crane/cmd/apply/apply.go:50:			Run					0.0%
github.com/konveyor/crane/cmd/apply/apply.go:54:			NewApplyCommand				0.0%
github.com/konveyor/crane/cmd/apply/apply.go:86:			addFlagsForOptions			0.0%
github.com/konveyor/crane/cmd/apply/apply.go:97:			run					0.0%
github.com/konveyor/crane/cmd/convert/convert.go:30:			NewConvertOptions			0.0%
github.com/konveyor/crane/cmd/convert/convert.go:63:			addFlagsForConvertOptions		0.0%
github.com/konveyor/crane/cmd/convert/convert.go:74:			Complete				0.0%
github.com/konveyor/crane/cmd/convert/convert.go:83:			Run					0.0%
github.com/konveyor/crane/cmd/convert/convert.go:87:			run					0.0%
github.com/konveyor/crane/cmd/convert/convert.go:112:			getClientFromContext			0.0%
github.com/konveyor/crane/cmd/convert/convert.go:134:			getRestConfigFromContext		0.0%
github.com/konveyor/crane/cmd/export/cluster.go:29:			NewClusterScopeHandler			100.0%
github.com/konveyor/crane/cmd/export/cluster.go:35:			isClusterScopedResource			100.0%
github.com/konveyor/crane/cmd/export/cluster.go:44:			filterRbacResources			100.0%
github.com/konveyor/crane/cmd/export/cluster.go:102:			NewClusterScopedRbacHandler		100.0%
github.com/konveyor/crane/cmd/export/cluster.go:113:			exportedSANamespaces			100.0%
github.com/konveyor/crane/cmd/export/cluster.go:126:			groupMatchesExportedSANamespaces	100.0%
github.com/konveyor/crane/cmd/export/cluster.go:143:			parseServiceAccountUserSubject		100.0%
github.com/konveyor/crane/cmd/export/cluster.go:154:			prepareForFiltering			100.0%
github.com/konveyor/crane/cmd/export/cluster.go:187:			filteredResourcesOfKind			100.0%
github.com/konveyor/crane/cmd/export/cluster.go:213:			accept					100.0%
github.com/konveyor/crane/cmd/export/cluster.go:223:			acceptClusterRoleBinding		100.0%
github.com/konveyor/crane/cmd/export/cluster.go:260:			acceptClusterRole			100.0%
github.com/konveyor/crane/cmd/export/cluster.go:284:			acceptSecurityContextConstraints	100.0%
github.com/konveyor/crane/cmd/export/cluster.go:336:			anyServiceAccountInNamespace		100.0%
github.com/konveyor/crane/cmd/export/crd.go:17:				normalizeGroupSet			85.7%
github.com/konveyor/crane/cmd/export/crd.go:29:				shouldSkipCRDGroup			100.0%
github.com/konveyor/crane/cmd/export/crd.go:50:				crdFailureAPIResourceName		100.0%
github.com/konveyor/crane/cmd/export/crd.go:58:				collectRelatedCRDs			89.7%
github.com/konveyor/crane/cmd/export/discover.go:39:			hasClusterScopedManifests		100.0%
github.com/konveyor/crane/cmd/export/discover.go:57:			prepareClusterResourceDir		100.0%
github.com/konveyor/crane/cmd/export/discover.go:73:			prepareFailuresDir			100.0%
github.com/konveyor/crane/cmd/export/discover.go:85:			writeResources				85.7%
github.com/konveyor/crane/cmd/export/discover.go:133:			writeErrors				83.3%
github.com/konveyor/crane/cmd/export/discover.go:174:			getFilePath				100.0%
github.com/konveyor/crane/cmd/export/discover.go:185:			discoverPreferredResources		100.0%
github.com/konveyor/crane/cmd/export/discover.go:214:			resourceToExtract			100.0%
github.com/konveyor/crane/cmd/export/discover.go:283:			isAdmittedResource			100.0%
github.com/konveyor/crane/cmd/export/discover.go:292:			getObjects				100.0%
github.com/konveyor/crane/cmd/export/discover.go:326:			iterateItemsByGet			93.8%
github.com/konveyor/crane/cmd/export/discover.go:352:			iterateItemsInList			92.3%
github.com/konveyor/crane/cmd/export/export.go:52:			Complete				90.0%
github.com/konveyor/crane/cmd/export/export.go:91:			Validate				100.0%
github.com/konveyor/crane/cmd/export/export.go:106:			validateExportNamespace			87.5%
github.com/konveyor/crane/cmd/export/export.go:122:			Run					0.0%
github.com/konveyor/crane/cmd/export/export.go:225:			NewExportCommand			50.0%
github.com/konveyor/crane/cmd/plugin-manager/add/add.go:42:		Complete				0.0%
github.com/konveyor/crane/cmd/plugin-manager/add/add.go:47:		Validate				0.0%
github.com/konveyor/crane/cmd/plugin-manager/add/add.go:90:		Run					0.0%
github.com/konveyor/crane/cmd/plugin-manager/add/add.go:94:		NewAddCommand				0.0%
github.com/konveyor/crane/cmd/plugin-manager/add/add.go:126:		addFlagsForOptions			0.0%
github.com/konveyor/crane/cmd/plugin-manager/add/add.go:131:		run					0.0%
github.com/konveyor/crane/cmd/plugin-manager/add/add.go:195:		downloadBinary				0.0%
github.com/konveyor/crane/cmd/plugin-manager/list/list.go:46:		Complete				0.0%
github.com/konveyor/crane/cmd/plugin-manager/list/list.go:51:		Validate				0.0%
github.com/konveyor/crane/cmd/plugin-manager/list/list.go:56:		Run					0.0%
github.com/konveyor/crane/cmd/plugin-manager/list/list.go:60:		NewListCommand				0.0%
github.com/konveyor/crane/cmd/plugin-manager/list/list.go:90:		addFlagsForOptions			0.0%
github.com/konveyor/crane/cmd/plugin-manager/list/list.go:98:		run					0.0%
github.com/konveyor/crane/cmd/plugin-manager/list/list.go:167:		printInstalledInformation		0.0%
github.com/konveyor/crane/cmd/plugin-manager/list/list.go:177:		groupInformationForPlugins		0.0%
github.com/konveyor/crane/cmd/plugin-manager/list/list.go:196:		printInformation			0.0%
github.com/konveyor/crane/cmd/plugin-manager/list/list.go:208:		printParamsInformation			0.0%
github.com/konveyor/crane/cmd/plugin-manager/list/list.go:222:		getOptionalFields			0.0%
github.com/konveyor/crane/cmd/plugin-manager/list/list.go:247:		printTable				0.0%
github.com/konveyor/crane/cmd/plugin-manager/plugin-manager.go:33:	Complete				0.0%
github.com/konveyor/crane/cmd/plugin-manager/plugin-manager.go:38:	Validate				0.0%
github.com/konveyor/crane/cmd/plugin-manager/plugin-manager.go:43:	Run					0.0%
github.com/konveyor/crane/cmd/plugin-manager/plugin-manager.go:47:	NewPluginManagerCommand			0.0%
github.com/konveyor/crane/cmd/plugin-manager/plugin-manager.go:78:	addFlagsForOptions			0.0%
github.com/konveyor/crane/cmd/plugin-manager/plugin-manager.go:86:	run					0.0%
github.com/konveyor/crane/cmd/plugin-manager/remove/remove.go:33:	Complete				0.0%
github.com/konveyor/crane/cmd/plugin-manager/remove/remove.go:38:	Validate				0.0%
github.com/konveyor/crane/cmd/plugin-manager/remove/remove.go:43:	Run					0.0%
github.com/konveyor/crane/cmd/plugin-manager/remove/remove.go:47:	NewRemoveCommand			0.0%
github.com/konveyor/crane/cmd/plugin-manager/remove/remove.go:77:	run					0.0%
github.com/konveyor/crane/cmd/runfn/runfn.go:33:			NewFnRunCommand				0.0%
github.com/konveyor/crane/cmd/runfn/runfn.go:49:			addFlagsForOptions			0.0%
github.com/konveyor/crane/cmd/runfn/runfn.go:59:			runE					0.0%
github.com/konveyor/crane/cmd/runfn/runfn.go:70:			preRunE					0.0%
github.com/konveyor/crane/cmd/runfn/runfn.go:112:			getFunctionImage			0.0%
github.com/konveyor/crane/cmd/runfn/runfn.go:124:			getContainerFunctions			0.0%
github.com/konveyor/crane/cmd/runfn/runfn.go:151:			getFunctionAnnotation			0.0%
github.com/konveyor/crane/cmd/runfn/runfn.go:170:			getFunctionConfig			0.0%
github.com/konveyor/crane/cmd/runfn/util.go:14:				WriteOutput				0.0%
github.com/konveyor/crane/cmd/runfn/util.go:31:				GetDestinationDir			0.0%
github.com/konveyor/crane/cmd/runfn/util.go:58:				ValidateFunctionImageURL		0.0%
github.com/konveyor/crane/cmd/runfn/util.go:80:				checkIfDirExists			0.0%
github.com/konveyor/crane/cmd/skopeo-sync-gen/skopeo-sync-gen.go:61:	Complete				0.0%
github.com/konveyor/crane/cmd/skopeo-sync-gen/skopeo-sync-gen.go:65:	Validate				0.0%
github.com/konveyor/crane/cmd/skopeo-sync-gen/skopeo-sync-gen.go:69:	NewSkopeoSyncGenCommand			0.0%
github.com/konveyor/crane/cmd/skopeo-sync-gen/skopeo-sync-gen.go:103:	shouldAddImageStream			0.0%
github.com/konveyor/crane/cmd/skopeo-sync-gen/skopeo-sync-gen.go:114:	Run					0.0%
github.com/konveyor/crane/cmd/transfer-pvc/progress.go:37:		NewRsyncLogStream			0.0%
github.com/konveyor/crane/cmd/transfer-pvc/progress.go:50:		Init					0.0%
github.com/konveyor/crane/cmd/transfer-pvc/progress.go:138:		writeProgressToFile			0.0%
github.com/konveyor/crane/cmd/transfer-pvc/progress.go:148:		Close					0.0%
github.com/konveyor/crane/cmd/transfer-pvc/progress.go:154:		Streams					0.0%
github.com/konveyor/crane/cmd/transfer-pvc/progress.go:190:		addDataSize				0.0%
github.com/konveyor/crane/cmd/transfer-pvc/progress.go:215:		String					100.0%
github.com/konveyor/crane/cmd/transfer-pvc/progress.go:219:		MarshalJSON				0.0%
github.com/konveyor/crane/cmd/transfer-pvc/progress.go:223:		AsString				0.0%
github.com/konveyor/crane/cmd/transfer-pvc/progress.go:271:		NewProgress				100.0%
github.com/konveyor/crane/cmd/transfer-pvc/progress.go:291:		Completed				0.0%
github.com/konveyor/crane/cmd/transfer-pvc/progress.go:296:		Status					38.5%
github.com/konveyor/crane/cmd/transfer-pvc/progress.go:321:		Merge					0.0%
github.com/konveyor/crane/cmd/transfer-pvc/progress.go:376:		newDataSize				72.7%
github.com/konveyor/crane/cmd/transfer-pvc/progress.go:399:		parseRsyncLogs				76.1%
github.com/konveyor/crane/cmd/transfer-pvc/progress.go:479:		waitForPodRunning			0.0%
github.com/konveyor/crane/cmd/transfer-pvc/progress.go:513:		getFinalPodStatus			0.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:89:		Validate				100.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:117:		Validate				100.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:133:		NewTransferPVCCommand			0.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:169:		addFlagsToTransferPVCCommand		0.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:189:		Complete				0.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:220:		Validate				100.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:246:		Run					0.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:250:		getClientFromContext			0.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:271:		getRestConfigFromContext		0.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:278:		run					0.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:485:		getValidatedResourceName		100.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:495:		getNodeNameForPVC			90.9%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:515:		getIDsForNamespace			88.9%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:541:		getRsyncClientPodSecurityContext	0.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:553:		getRsyncServerPodSecurityContext	0.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:565:		garbageCollect				83.3%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:602:		deleteResourcesIteratively		78.6%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:628:		deleteResourcesForGVK			80.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:649:		followClientLogs			0.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:678:		waitForEndpoint				0.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:690:		createEndpoint				0.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:735:		getRouteHostName			100.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:752:		buildDestinationPVC			100.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:773:		ApplyTo					100.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:793:		ApplyTo					100.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:805:		ApplyTo					100.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:821:		String					100.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:825:		Set					100.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:835:		Type					100.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:841:		parseSourceDestinationMapping		100.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:863:		String					100.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:867:		Set					100.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:876:		Type					100.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:880:		String					0.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:884:		Set					100.0%
github.com/konveyor/crane/cmd/transfer-pvc/transfer-pvc.go:894:		Type					100.0%
github.com/konveyor/crane/cmd/transform/listplugins/listplugins.go:31:	Complete				0.0%
github.com/konveyor/crane/cmd/transform/listplugins/listplugins.go:36:	Validate				0.0%
github.com/konveyor/crane/cmd/transform/listplugins/listplugins.go:41:	Run					0.0%
github.com/konveyor/crane/cmd/transform/listplugins/listplugins.go:45:	NewListPluginsCommand			0.0%
github.com/konveyor/crane/cmd/transform/listplugins/listplugins.go:77:	run					0.0%
github.com/konveyor/crane/cmd/transform/optionals/optionals.go:31:	Complete				0.0%
github.com/konveyor/crane/cmd/transform/optionals/optionals.go:36:	Validate				0.0%
github.com/konveyor/crane/cmd/transform/optionals/optionals.go:41:	Run					0.0%
github.com/konveyor/crane/cmd/transform/optionals/optionals.go:45:	NewOptionalsCommand			0.0%
github.com/konveyor/crane/cmd/transform/optionals/optionals.go:77:	run					0.0%
github.com/konveyor/crane/cmd/transform/transform.go:46:		Complete				0.0%
github.com/konveyor/crane/cmd/transform/transform.go:50:		Validate				0.0%
github.com/konveyor/crane/cmd/transform/transform.go:55:		Run					0.0%
github.com/konveyor/crane/cmd/transform/transform.go:59:		NewTransformCommand			0.0%
github.com/konveyor/crane/cmd/transform/transform.go:93:		addFlagsForOptions			0.0%
github.com/konveyor/crane/cmd/transform/transform.go:111:		run					0.0%
github.com/konveyor/crane/cmd/transform/transform.go:230:		optionalFlagsToLower			0.0%
github.com/konveyor/crane/cmd/transform/transform.go:239:		runStageWithCleanup			0.0%
github.com/konveyor/crane/cmd/transform/transform.go:252:		ensurePreviousStagesRun			0.0%
github.com/konveyor/crane/cmd/transform/transform.go:269:		ensureStagesHaveOutput			0.0%
github.com/konveyor/crane/cmd/tunnel-api/tunnel-api.go:35:		NewTunnelAPIOptions			0.0%
github.com/konveyor/crane/cmd/tunnel-api/tunnel-api.go:65:		addFlagsForTunnelAPIOptions		0.0%
github.com/konveyor/crane/cmd/tunnel-api/tunnel-api.go:77:		Complete				0.0%
github.com/konveyor/crane/cmd/tunnel-api/tunnel-api.go:100:		Validate				0.0%
github.com/konveyor/crane/cmd/tunnel-api/tunnel-api.go:116:		Run					0.0%
github.com/konveyor/crane/cmd/tunnel-api/tunnel-api.go:120:		getClientFromContext			0.0%
github.com/konveyor/crane/cmd/tunnel-api/tunnel-api.go:129:		getRestConfigFromContext		0.0%
github.com/konveyor/crane/cmd/tunnel-api/tunnel-api.go:136:		run					0.0%
github.com/konveyor/crane/cmd/validate/validate.go:30:			Complete				0.0%
github.com/konveyor/crane/cmd/validate/validate.go:39:			Validate				100.0%
github.com/konveyor/crane/cmd/validate/validate.go:56:			Run					0.0%
github.com/konveyor/crane/cmd/validate/validate.go:116:			NewValidateCommand			41.2%
github.com/konveyor/crane/cmd/version/version.go:20:			Complete				0.0%
github.com/konveyor/crane/cmd/version/version.go:25:			Validate				0.0%
github.com/konveyor/crane/cmd/version/version.go:30:			Run					0.0%
github.com/konveyor/crane/cmd/version/version.go:34:			NewVersionCommand			0.0%
github.com/konveyor/crane/cmd/version/version.go:60:			run					0.0%
github.com/konveyor/crane/e2e-tests/utils/utils.go:20:			CreateTempDir				100.0%
github.com/konveyor/crane/e2e-tests/utils/utils.go:27:			ListFilesRecursively			91.7%
github.com/konveyor/crane/e2e-tests/utils/utils.go:50:			ListFilesRecursivelyAsList		80.0%
github.com/konveyor/crane/e2e-tests/utils/utils.go:74:			HasFilesRecursively			80.0%
github.com/konveyor/crane/e2e-tests/utils/utils.go:85:			ReadTestdataFile			88.9%
github.com/konveyor/crane/e2e-tests/utils/utils.go:109:			GoldenManifestsDir			90.0%
github.com/konveyor/crane/e2e-tests/utils/utils.go:128:			CompareDirectoryFileSets		78.9%
github.com/konveyor/crane/e2e-tests/utils/utils.go:163:			CompareDirectoryYAMLSemantics		82.4%
github.com/konveyor/crane/e2e-tests/utils/utils.go:197:			CompareDirectoryYAMLSemanticsExport	89.3%
github.com/konveyor/crane/e2e-tests/utils/utils.go:249:			buildNormalizedExportIndex		81.0%
github.com/konveyor/crane/e2e-tests/utils/utils.go:289:			canonicalizeDocs			87.5%
github.com/konveyor/crane/e2e-tests/utils/utils.go:303:			extractResourceIdentity			77.8%
github.com/konveyor/crane/e2e-tests/utils/utils.go:366:			parseYAMLDocuments			100.0%
github.com/konveyor/crane/e2e-tests/utils/utils.go:385:			compareYAMLFileBytes			100.0%
github.com/konveyor/crane/e2e-tests/utils/utils.go:404:			LooksLikeYAMLFile			100.0%
github.com/konveyor/crane/e2e-tests/utils/utils.go:418:			normalizeUnstableFields			100.0%
github.com/konveyor/crane/e2e-tests/utils/utils.go:455:			normalizePodServiceAccountVolumeNames	90.9%
github.com/konveyor/crane/e2e-tests/utils/utils.go:514:			normalizeWithPath			92.9%
github.com/konveyor/crane/e2e-tests/utils/utils.go:544:			shouldDropField				100.0%
github.com/konveyor/crane/internal/apply/kustomize.go:28:		ApplySingleStage			0.0%
github.com/konveyor/crane/internal/apply/kustomize.go:69:		ApplyMultiStage				0.0%
github.com/konveyor/crane/internal/apply/kustomize.go:115:		runKustomizeBuild			0.0%
github.com/konveyor/crane/internal/apply/kustomize.go:133:		ValidateKubectlAvailable		42.9%
github.com/konveyor/crane/internal/apply/kustomize.go:151:		splitMultiDocYAMLToFiles		87.8%
github.com/konveyor/crane/internal/file/file_helper.go:23:		ReadFiles				100.0%
github.com/konveyor/crane/internal/file/file_helper.go:33:		readFiles				84.0%
github.com/konveyor/crane/internal/file/file_helper.go:84:		GetWhiteOutFilePath			100.0%
github.com/konveyor/crane/internal/file/file_helper.go:88:		GetTransformPath			100.0%
github.com/konveyor/crane/internal/file/file_helper.go:92:		GetIgnoredPatchesPath			0.0%
github.com/konveyor/crane/internal/file/file_helper.go:96:		updateTransformDirPath			100.0%
github.com/konveyor/crane/internal/file/file_helper.go:100:		updateIgnoredPatchesDirPath		0.0%
github.com/konveyor/crane/internal/file/file_helper.go:107:		updatePath				100.0%
github.com/konveyor/crane/internal/file/file_helper.go:114:		GetOutputFilePath			100.0%
github.com/konveyor/crane/internal/file/file_helper.go:124:		GetStageDir				100.0%
github.com/konveyor/crane/internal/file/file_helper.go:130:		GetResourcesDir				100.0%
github.com/konveyor/crane/internal/file/file_helper.go:136:		GetPatchesDir				100.0%
github.com/konveyor/crane/internal/file/file_helper.go:142:		GetReportsDir				100.0%
github.com/konveyor/crane/internal/file/file_helper.go:148:		GetWhiteoutsDir				100.0%
github.com/konveyor/crane/internal/file/file_helper.go:154:		GetKustomizationPath			100.0%
github.com/konveyor/crane/internal/file/file_helper.go:160:		GetMetadataPath				100.0%
github.com/konveyor/crane/internal/file/file_helper.go:166:		GetResourceTypeFilePath			100.0%
github.com/konveyor/crane/internal/file/file_helper.go:172:		GetPatchFilePath			100.0%
github.com/konveyor/crane/internal/file/file_helper.go:178:		GetWhiteoutReportPath			100.0%
github.com/konveyor/crane/internal/file/file_helper.go:184:		GetIgnoredPatchReportPath		100.0%
github.com/konveyor/crane/internal/file/file_helper.go:190:		GetStageWorkDir				0.0%
github.com/konveyor/crane/internal/file/file_helper.go:196:		GetStageInputDir			0.0%
github.com/konveyor/crane/internal/file/file_helper.go:203:		GetStageTransformDir			0.0%
github.com/konveyor/crane/internal/file/file_helper.go:209:		GetStageOutputDir			0.0%
github.com/konveyor/crane/internal/file/file_helper.go:214:		GetKustomizeCommand			0.0%
github.com/konveyor/crane/internal/file/file_helper.go:234:		GetResourceFilename			0.0%
github.com/konveyor/crane/internal/flags/global_flags.go:14:		ApplyFlags				0.0%
github.com/konveyor/crane/internal/flags/global_flags.go:21:		GetLogger				0.0%
github.com/konveyor/crane/internal/flags/global_flags.go:29:		initConfig				0.0%
github.com/konveyor/crane/internal/plugin/plugin_helper.go:21:		GetPlugins				0.0%
github.com/konveyor/crane/internal/plugin/plugin_helper.go:38:		getBinaryPlugins			0.0%
github.com/konveyor/crane/internal/plugin/plugin_helper.go:63:		IsExecAny				0.0%
github.com/konveyor/crane/internal/plugin/plugin_helper.go:67:		GetFilteredPlugins			0.0%
github.com/konveyor/crane/internal/plugin/plugin_helper.go:106:		isPluginInList				0.0%
github.com/konveyor/crane/internal/plugin/plugin_manager_helper.go:24:	BuildManifestMap			0.0%
github.com/konveyor/crane/internal/plugin/plugin_manager_helper.go:68:	GetYamlFromUrl				75.0%
github.com/konveyor/crane/internal/plugin/plugin_manager_helper.go:82:	YamlToManifest				72.7%
github.com/konveyor/crane/internal/plugin/plugin_manager_helper.go:104:	FilterPluginForOsArch			100.0%
github.com/konveyor/crane/internal/plugin/plugin_manager_helper.go:122:	GetDefaultSource			0.0%
github.com/konveyor/crane/internal/plugin/plugin_manager_helper.go:131:	LocateBinaryInPluginDir			0.0%
github.com/konveyor/crane/internal/plugin/plugin_manager_helper.go:143:	IsUrl					100.0%
github.com/konveyor/crane/internal/plugin/plugin_manager_helper.go:149:	getData					80.0%
github.com/konveyor/crane/internal/transform/orchestrator.go:40:	RunMultiStage				75.0%
github.com/konveyor/crane/internal/transform/orchestrator.go:146:	executeStage				72.7%
github.com/konveyor/crane/internal/transform/orchestrator.go:198:	transformResources			68.4%
github.com/konveyor/crane/internal/transform/orchestrator.go:249:	formatResourceID			0.0%
github.com/konveyor/crane/internal/transform/orchestrator.go:256:	getPluginForStage			90.9%
github.com/konveyor/crane/internal/transform/orchestrator.go:283:	getAvailablePluginNames			0.0%
github.com/konveyor/crane/internal/transform/orchestrator.go:296:	applyStageTransforms			83.3%
github.com/konveyor/crane/internal/transform/orchestrator.go:357:	loadResourcesFromDirectory		85.7%
github.com/konveyor/crane/internal/transform/orchestrator.go:372:	writeResourcesToDirectory		69.2%
github.com/konveyor/crane/internal/transform/stages.go:22:		DiscoverStages				90.5%
github.com/konveyor/crane/internal/transform/stages.go:82:		FilterStages				100.0%
github.com/konveyor/crane/internal/transform/stages.go:100:		GetFirstStage				100.0%
github.com/konveyor/crane/internal/transform/stages.go:110:		GetLastStage				66.7%
github.com/konveyor/crane/internal/transform/stages.go:120:		GetPreviousStage			100.0%
github.com/konveyor/crane/internal/transform/stages.go:130:		GetNextStage				100.0%
github.com/konveyor/crane/internal/transform/stages.go:140:		ValidateStageName			100.0%
github.com/konveyor/crane/internal/transform/stages.go:149:		GenerateStageName			100.0%
github.com/konveyor/crane/internal/transform/test_helpers.go:11:	hasKustomizeCommand			66.7%
github.com/konveyor/crane/internal/transform/test_helpers.go:23:	contains				100.0%
github.com/konveyor/crane/internal/transform/test_helpers.go:32:	findInString				100.0%
github.com/konveyor/crane/internal/transform/writer.go:28:		NewKustomizeWriter			100.0%
github.com/konveyor/crane/internal/transform/writer.go:37:		WriteStage				68.4%
github.com/konveyor/crane/internal/transform/writer.go:218:		getResourceID				83.3%
github.com/konveyor/crane/internal/transform/writer.go:231:		filterValidRemoveOps			76.2%
github.com/konveyor/crane/internal/transform/writer.go:275:		pathExists				93.5%
github.com/konveyor/crane/internal/transform/writer.go:352:		generateKustomizationWithComments	93.8%
github.com/konveyor/crane/internal/transform/writer.go:383:		checkStageDirectory			23.1%
github.com/konveyor/crane/internal/validate/matcher.go:21:		MatchResults				93.8%
github.com/konveyor/crane/internal/validate/matcher.go:62:		buildDiscoveryIndex			64.7%
github.com/konveyor/crane/internal/validate/matcher.go:92:		matchEntry				100.0%
github.com/konveyor/crane/internal/validate/matcher.go:121:		buildKindIndex				100.0%
github.com/konveyor/crane/internal/validate/matcher.go:133:		addSuggestion				92.3%
github.com/konveyor/crane/internal/validate/report.go:17:		FormatTable				100.0%
github.com/konveyor/crane/internal/validate/report.go:54:		FormatJSON				100.0%
github.com/konveyor/crane/internal/validate/report.go:61:		FormatYAML				0.0%
github.com/konveyor/crane/internal/validate/report.go:73:		WriteFailures				0.0%
github.com/konveyor/crane/internal/validate/report.go:109:		failureFileName				0.0%
github.com/konveyor/crane/internal/validate/report.go:123:		safeFilePart				0.0%
github.com/konveyor/crane/internal/validate/report.go:139:		parseAPIVersion				0.0%
github.com/konveyor/crane/internal/validate/scanner.go:34:		ScanManifests				75.4%
github.com/konveyor/crane/internal/validate/types.go:43:		HasIncompatible				100.0%
github.com/konveyor/crane/internal/validate/types.go:46:		IncompatibleResults			0.0%
github.com/konveyor/crane/main.go:22:					main					0.0%
total:									(statements)				45.3%

Posted by CI

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
cmd/transfer-pvc/transfer-pvc_test.go (1)

1696-1710: ⚡ Quick win

Don’t ignore List errors in verification assertions.

These checks use _ = client.List(...); if listing fails, the test can still pass on zero-length slices and mask regressions. Assert err == nil before checking item counts.

Suggested patch
-	_ = srcClient.List(context.TODO(), podList, client.InNamespace("src-ns"), client.MatchingLabels(labels))
+	if err := srcClient.List(context.TODO(), podList, client.InNamespace("src-ns"), client.MatchingLabels(labels)); err != nil {
+		t.Fatalf("failed to list source pods: %v", err)
+	}
@@
-	_ = srcClient.List(context.TODO(), cmList, client.InNamespace("src-ns"), client.MatchingLabels(labels))
+	if err := srcClient.List(context.TODO(), cmList, client.InNamespace("src-ns"), client.MatchingLabels(labels)); err != nil {
+		t.Fatalf("failed to list source configmaps: %v", err)
+	}
@@
-	_ = srcClient.List(context.TODO(), secretList, client.InNamespace("src-ns"), client.MatchingLabels(labels))
+	if err := srcClient.List(context.TODO(), secretList, client.InNamespace("src-ns"), client.MatchingLabels(labels)); err != nil {
+		t.Fatalf("failed to list source secrets: %v", err)
+	}
@@
-	_ = destClient.List(context.TODO(), ingressList, client.InNamespace("dest-ns"), client.MatchingLabels(labels))
+	if err := destClient.List(context.TODO(), ingressList, client.InNamespace("dest-ns"), client.MatchingLabels(labels)); err != nil {
+		t.Fatalf("failed to list destination ingresses: %v", err)
+	}
@@
-	_ = destClient.List(context.TODO(), podList, client.InNamespace("dest-ns"), client.MatchingLabels(labels))
+	if err := destClient.List(context.TODO(), podList, client.InNamespace("dest-ns"), client.MatchingLabels(labels)); err != nil {
+		t.Fatalf("failed to list destination pods: %v", err)
+	}
@@
-	_ = destClient.List(context.TODO(), routeList, client.InNamespace("dest-ns"), client.MatchingLabels(labels))
+	if err := destClient.List(context.TODO(), routeList, client.InNamespace("dest-ns"), client.MatchingLabels(labels)); err != nil {
+		t.Fatalf("failed to list destination routes: %v", err)
+	}
@@
-	_ = destClient.List(context.TODO(), podList, client.InNamespace("dest-ns"), client.MatchingLabels(labels))
+	if err := destClient.List(context.TODO(), podList, client.InNamespace("dest-ns"), client.MatchingLabels(labels)); err != nil {
+		t.Fatalf("failed to list destination pods: %v", err)
+	}

As per coding guidelines, "Handle Kubernetes API errors gracefully (not found, forbidden, etc.)" and "Prefer explicit error messages with context in Go code".

Also applies to: 1760-1768, 1818-1826

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/transfer-pvc/transfer-pvc_test.go` around lines 1696 - 1710, The test
currently ignores errors from srcClient.List when building podList, cmList, and
secretList (and the similar checks at the other noted locations), which can mask
failures; update each call to srcClient.List (used to populate podList, cmList,
secretList) to capture the returned error and assert err == nil (use t.Fatalf or
t.Fatalf-like assertion with a clear message including the resource type and
namespace) before checking len(...Items), and do the same for the other
occurrences referenced (around the 1760–1768 and 1818–1826 blocks) so failures
in the Kubernetes API surface as test errors with context.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@cmd/transfer-pvc/transfer-pvc_test.go`:
- Around line 1696-1710: The test currently ignores errors from srcClient.List
when building podList, cmList, and secretList (and the similar checks at the
other noted locations), which can mask failures; update each call to
srcClient.List (used to populate podList, cmList, secretList) to capture the
returned error and assert err == nil (use t.Fatalf or t.Fatalf-like assertion
with a clear message including the resource type and namespace) before checking
len(...Items), and do the same for the other occurrences referenced (around the
1760–1768 and 1818–1826 blocks) so failures in the Kubernetes API surface as
test errors with context.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 66d11575-a913-4d09-9a5f-d699d71a0e9a

📥 Commits

Reviewing files that changed from the base of the PR and between 05ee0de and c752cb2.

📒 Files selected for processing (1)
  • cmd/transfer-pvc/transfer-pvc_test.go

RanWurmbrand and others added 3 commits July 21, 2026 17:08
Adds 41 unit tests covering the core functionality of the
transfer-pvc command using fake Kubernetes clients for all
cluster interactions.

- Flag types and parsing: mappedNameVar, quantityVar, endpointType,
  and parseSourceDestinationMapping with valid/invalid inputs
- Validation: TransferPVCCommand, EndpointFlags, and PvcFlags
  covering nil contexts, same-cluster, and empty field detection
- PVC building: field copying, storage/class overrides, and
  VolumeMode/VolumeName clearing for destination binding
- Rsync options: verify, restrictedContainers, and verbose flag
  application and removal
- Route and node helpers: hostname truncation, ingress lookup,
  pod-to-node resolution filtering by phase
- Namespace IDs: UID/GID extraction from security annotations
- Cleanup: deleteResourcesIteratively label/namespace scoping
  and garbageCollect for both nginx and route endpoints
- Resource naming: getValidatedResourceName length validation
  with MD5 fallback

Signed-off-by: Ran Wurmbrand <rwurmbra@redhat.com>
Update expected hostname to use truncateWithHash instead of plain
truncation, matching upstream's Route hostname collision fix (migtools#625).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Ran Wurmbrand <rwurmbra@redhat.com>
- Drop TestMappedNameVar_Set (delegates to parseSourceDestinationMapping,
  already thoroughly tested)
- Drop TestDeleteResourcesIteratively_SuccessfulDeletion (strict subset
  of MultipleResourceTypes test)
- Drop "succeeded pod" case from SkipsNonRunningPods (same branch as
  pending/failed, mixed-phase case already covers it)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Ran Wurmbrand <rwurmbra@redhat.com>
@RanWurmbrand
RanWurmbrand force-pushed the transfer-pvc-unit-tests branch from c752cb2 to 9a03be4 Compare July 21, 2026 14:28
@RanWurmbrand RanWurmbrand changed the title Add comprehensive unit tests for transfer-pvc command 🧪 Add comprehensive unit tests for transfer-pvc command Jul 21, 2026
@RanWurmbrand

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@RanWurmbrand

Copy link
Copy Markdown
Contributor Author

/rfr

@RanWurmbrand RanWurmbrand self-assigned this Jul 23, 2026
@RanWurmbrand RanWurmbrand added the test Testing related label Jul 23, 2026
@RanWurmbrand RanWurmbrand moved this from Todo to In review in Crane Development Jul 23, 2026
Namespace: mappedNameVar{source: "src-ns", destination: "dest-ns"},
},
wantErr: true,
errMsg: "destnation pvc name cannot be empty",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit:fmt.Errorf("destnation pvc name cannot be empty") (missing the second "i").

if !strings.HasPrefix(got, "crane-") {
t.Errorf("getValidatedResourceName() = %v, expected to start with 'crane-'", got)
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The PR description says tests were added for getIDsForNamespace (the function that reads UID/GID info from namespace annotations), but I couldn't find a test for it anywhere in this diff

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: In review

Development

Successfully merging this pull request may close these issues.

2 participants