Skip to content

Test optimization#4897

Draft
johha wants to merge 20 commits intomainfrom
test-optimization
Draft

Test optimization#4897
johha wants to merge 20 commits intomainfrom
test-optimization

Conversation

@johha
Copy link
Contributor

@johha johha commented Mar 2, 2026

Thanks for contributing to cloud_controller_ng. To speed up the process of reviewing your pull request please provide us with:

  • A short explanation of the proposed change:

  • An explanation of the use cases your change solves

  • Links to any other associated PRs

  • I have reviewed the contributing guide

  • I have viewed, signed, and submitted the Contributor License Agreement

  • I have made this pull request to the main branch

  • I have run all the unit tests using bundle exec rake

  • I have run CF Acceptance Tests

johha added 11 commits March 2, 2026 13:43
Convert the following message specs to use lightweight_spec_helper
instead of full spec_helper for faster test execution:

- app_feature_update_message_spec.rb
- app_show_message_spec.rb
- buildpack_create_message_spec.rb
- buildpack_update_message_spec.rb
- domain_delete_shared_org_message_spec.rb
- domain_show_message_spec.rb
- domain_update_message_spec.rb
- feature_flags_update_message_spec.rb

These specs don't require database access, Config, Lifecycles,
or the errors_on helper, making them suitable for lightweight testing.
Convert the following message specs to use lightweight_spec_helper:

- isolation_segment_relationship_org_message_spec.rb
- manifest_buildpack_message_spec.rb
- manifest_process_update_message_spec.rb
- manifest_service_binding_create_message_spec.rb
- organization_quota_apply_message_spec.rb
- organization_quotas_create_message_spec.rb
- organization_quotas_update_message_spec.rb
- package_update_message_spec.rb

Total converted: 16 message specs
Convert the following message specs to use lightweight_spec_helper:

- process_scale_message_spec.rb
- process_show_message_spec.rb
- process_update_message_spec.rb
- purge_message_spec.rb
- quotas_apps_message_spec.rb
- quotas_routes_message_spec.rb
- quotas_services_message_spec.rb
- revisions_update_message_spec.rb
- role_create_message_spec.rb
- role_show_message_spec.rb
- route_mappings_update_message_spec.rb
- route_show_message_spec.rb

Total converted: 28 message specs
Convert the following message specs to use lightweight_spec_helper:

- service_credential_binding_create_message_spec.rb
- sidecar_create_message_spec.rb
- sidecar_update_message_spec.rb
- space_delete_unmapped_routes_message_spec.rb
- space_feature_update_message_spec.rb
- stack_create_message_spec.rb
- to_many_relationship_message_spec.rb
- user_create_message_spec.rb
- user_update_message_spec.rb
- v2_v3_resource_translator_spec.rb

Total converted: 38 message specs
- Add require for cloud_controller/diego/constants in instances_reporter.rb
  to ensure LRP_RUNNING constant is defined before use
- Add require for 'oj' in db_spec_helper to ensure Oj is available before
  initializers run

This fixes the broken db_spec_helper which was failing with:
  NameError: uninitialized constant VCAP::CloudController::Diego::LRP_RUNNING
Add Sequel timezone configuration to db_spec_helper to fix
timestamp comparison issues in tests.

Converted specs:
- app_fetcher_spec.rb
- assign_current_droplet_fetcher_spec.rb
- base_list_fetcher_spec.rb
- build_list_fetcher_spec.rb

These specs only need database models, not the full controller stack,
so they can use the lighter db_spec_helper for faster load times.
Converted specs:
- droplet_fetcher_spec.rb
- event_list_fetcher_spec.rb
- organization_quota_list_fetcher_spec.rb
- organization_user_roles_fetcher_spec.rb
- package_fetcher_spec.rb
- process_fetcher_spec.rb
- route_destinations_list_fetcher_spec.rb
- service_binding_list_fetcher_spec.rb
- space_quota_list_fetcher_spec.rb

These specs only need database models, not the full controller stack,
reducing test load time from ~7s to ~2s per file.
Converted specs:
- app_env_presenter_spec.rb
- cache_key_presenter_spec.rb
- domain_shared_orgs_presenter_spec.rb
- organization_quota_presenter_spec.rb
- relationship_presenter_spec.rb
- route_destination_presenter_spec.rb
- route_destinations_presenter_spec.rb
- service_offering_presenter_spec.rb
- space_quota_presenter_spec.rb
- space_usage_summary_presenter_spec.rb
- to_many_relationship_presenter_spec.rb

These specs only need database models, not the full controller stack.
Converted specs:
- embed_process_instances_decorator_spec.rb
- field_service_offering_service_broker_decorator_spec.rb
- field_service_plan_service_broker_decorator_spec.rb
- event_types_spec.rb

Added explicit requires for decorator classes since db_spec_helper
doesn't autoload all application classes.
Original file: spec/request/apps_spec.rb (3,542 lines, 402 examples)

Split into:
- create_spec.rb (POST /v3/apps) - 451 lines
- list_spec.rb (GET /v3/apps) - 939 lines
- show_spec.rb (GET /v3/apps/:guid) - 494 lines
- builds_and_ssh_spec.rb - 221 lines
- delete_and_update_spec.rb - 328 lines
- actions_spec.rb (start, stop, restart) - 663 lines
- droplet_spec.rb (current_droplet endpoints) - 328 lines
- environment_spec.rb (environment_variables, permissions) - 177 lines

Shared test setup extracted to shared_context.rb

This split enables better parallel test distribution since each file
can run on a separate worker.
Original file: spec/request/routes_spec.rb (3,748 lines, 401 examples)
**Deleted original file after splitting**

Split into:
- list_spec.rb (GET /v3/routes) - 937 lines
- show_spec.rb (GET /v3/routes/:guid) - 171 lines
- create_spec.rb (POST /v3/routes) - 1289 lines
- update_and_delete_spec.rb - 277 lines
- sharing_spec.rb (shared_spaces relationships) - 917 lines
- apps_routes_spec.rb (GET /v3/apps/:app_guid/routes) - 173 lines

Shared test setup extracted to shared_context.rb

This split enables better parallel test distribution.
@johha johha force-pushed the test-optimization branch from 3ca551a to 67690e9 Compare March 2, 2026 14:48
johha added 6 commits March 2, 2026 16:18
Reverts the apps_spec.rb and routes_spec.rb splits since they don't
provide performance benefits with the current CI setup. The splits
only help when the CI is configured to run spec files in parallel
across workers.

Focus optimization efforts on:
- lightweight_spec_helper/db_spec_helper conversions (reduce load time)
- Test data optimization (let! -> let)
- Reducing database operations
Add errors_on helper and VCAP::CloudController::Config stub to
lightweight_spec_helper to enable more message spec conversions.

Converted specs:
- deployment_update_message_spec.rb
- domain_create_message_spec.rb
- droplet_copy_message_spec.rb
- droplet_create_message_spec.rb
- droplet_update_message_spec.rb
- isolation_segment_create_message_spec.rb
- isolation_segment_update_message_spec.rb
- metadata_base_message_spec.rb
- organization_quotas_list_message_spec.rb
- service_brokers_list_message_spec.rb
- space_quotas_list_message_spec.rb
- update_environment_variables_message_spec.rb
- users_list_message_spec.rb
- validators/url_validator_spec.rb

Now 70 message specs use lightweight_spec_helper (vs 82 on spec_helper).
Only define the minimal Config stub if it's not already defined,
to avoid overriding the real Config class when spec_helper is also loaded.
Move Fog mock bucket setup to before(:suite) and only reset Fog mocks
for tests that explicitly need it (tagged with :fog_reset).

This optimization saves ~5.3ms per test by avoiding unnecessary bucket
recreation. Only ~6% of tests actually use blobstores, so this benefits
the majority of tests.

Tests that need a clean Fog state can add `:fog_reset` metadata to opt-in
to the previous behavior.
Move Fog mock reset from global spec_helper to opt-in fog_spec_helper.
This prevents fog reset from running for all specs, which caused
conflicts with migration specs that stub Config.get differently.

The fog_spec_helper now:
- Uses metadata-based hook (:fog_isolation) that only runs for tagged specs
- Resets Fog mocks and recreates buckets before each tagged test
- Avoids interfering with specs that mock Config differently

24 blobstore-related specs are tagged with :fog_isolation metadata.
@johha johha force-pushed the test-optimization branch from 9f8ccf4 to 99b2c57 Compare March 3, 2026 08:34
Spork is no longer used in this project. This removes:
- The require 'spork' with rescue block
- The shell command that checked for running spork processes
- The Spork-related documentation/instructions
- The conditional Spork.prefork/each_run blocks

The init_block and each_run_block are now called directly.
@Gerg
Copy link
Member

Gerg commented Mar 3, 2026

I have some PRs that may be relevant to this:

  1. Improve CC's usage of Spring pre-loader to speed up test loading #4802
  2. Add Bootsnap gem to speed up app boot time #4803
  3. Direnv (.envrc) adds ./bin to path #4810
  4. Remove spork #4811

@johha
Copy link
Contributor Author

johha commented Mar 3, 2026

I have some PRs that may be relevant to this:

1. [Improve CC's usage of Spring pre-loader to speed up test loading #4802](https://github.com/cloudfoundry/cloud_controller_ng/pull/4802)

2. [Add Bootsnap gem to speed up app boot time #4803](https://github.com/cloudfoundry/cloud_controller_ng/pull/4803)

3. [Direnv (.envrc) adds ./bin to path #4810](https://github.com/cloudfoundry/cloud_controller_ng/pull/4810)

4. [Remove spork #4811](https://github.com/cloudfoundry/cloud_controller_ng/pull/4811)

This PR is 'just' AI trying to find some optimizations. I might split it up once I'm satisfied with the results.

johha added 2 commits March 3, 2026 10:55
TestConfig.reset is expensive (~1.9ms per call) as it reloads config
from file and resets all dependencies. Previously it ran for every test,
but only ~57 specs use non-default job_context.

Now TestConfig.reset only runs when the context actually changes:
- First test: reset happens (context transitions from nil to :api)
- Subsequent :api tests: no reset needed
- Tests with :worker or :clock context: reset only on context change

This saves ~1.9ms per test for the vast majority of specs.
This reverts the optimization because it broke test isolation.
Tests use Config.config.set() to override config values, and without
TestConfig.reset between tests, these changes persist and pollute
subsequent tests.

For example, tests setting max_annotations_per_resource=1 caused
other tests to fail with "AnnotationLimitExceeded" errors.
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.

2 participants