Skip to content

Instantly share code, notes, and snippets.

@iurev
Created July 10, 2024 14:33
Show Gist options
  • Select an option

  • Save iurev/4cdfd4a2192226e46f17d6e0b2b121ef to your computer and use it in GitHub Desktop.

Select an option

Save iurev/4cdfd4a2192226e46f17d6e0b2b121ef to your computer and use it in GitHub Desktop.
[{"role":"user","content":"You are an experienced Ruby on Rails developer, very accurate for details who loves optimizing the performance of the tests.\nThe last 10 years you've spent optimizing performance of _spec.rb files using TestProf library.\n\nYou must keep your answers very short, concise, simple and informative.\n\nYou have been asked to refactor a test file to improve its performance.\nYou should use TestProf's let_it_be, before_all features\nYou must be very careful and introduce changes only when they are absolutely neccessary and will bring real performance improvements (don't over-optimize).\nAgain, make only minimal and essential changes to the existing code.\nYou MUST always send me back the whole file even if some parts of it didn't change.\n\nUse the following example refactoring as a guide:\n\nGit diff with refactoring:\n\ndiff --git a/spec/controllers/statuses_controller_spec.rb b/spec/controllers/statuses_controller_spec.rb\nindex fe40ee6..122de41 100644\n--- a/spec/controllers/statuses_controller_spec.rb\n+++ b/spec/controllers/statuses_controller_spec.rb\n@@ -2,13 +2,12 @@\n \n require 'rails_helper'\n \n-describe StatusesController do\n+describe StatusesController, :account do\n render_views\n \n- describe 'GET #show' do\n- let(:account) { Fabricate(:account) }\n- let(:status) { Fabricate(:status, account: account) }\n+ let_it_be(:status) { Fabricate(:status, account: account) }\n \n+ describe 'GET #show' do\n context 'when account is permanently suspended' do\n before do\n account.suspend!\n@@ -89,7 +88,7 @@ describe StatusesController do\n end\n \n context 'when status is private' do\n- let(:status) { Fabricate(:status, account: account, visibility: :private) }\n+ before { status.update!(visibility: :private) }\n \n before do\n get :show, params: { account_username: status.account.username, id: status.id, format: format }\n@@ -113,7 +112,7 @@ describe StatusesController do\n end\n \n context 'when status is direct' do\n- let(:status) { Fabricate(:status, account: account, visibility: :direct) }\n+ before { status.update!(visibility: :direct) }\n \n before do\n get :show, params: { account_username: status.account.username, id: status.id, format: format }\n@@ -136,9 +135,7 @@ describe StatusesController do\n end\n end\n \n- context 'when signed-in' do\n- let(:user) { Fabricate(:user) }\n-\n+ context 'when signed-in', :user do\n before do\n sign_in(user)\n end\n@@ -194,7 +191,7 @@ describe StatusesController do\n end\n \n context 'when status is private' do\n- let(:status) { Fabricate(:status, account: account, visibility: :private) }\n+ before { status.update!(visibility: :private) }\n \n context 'when user is authorized to see it' do\n before do\n@@ -261,7 +258,7 @@ describe StatusesController do\n end\n \n context 'when status is direct' do\n- let(:status) { Fabricate(:status, account: account, visibility: :direct) }\n+ before { status.update!(visibility: :direct) }\n \n context 'when user is authorized to see it' do\n before do\n@@ -328,7 +325,7 @@ describe StatusesController do\n end\n \n context 'with signature' do\n- let(:remote_account) { Fabricate(:account, domain: 'example.com') }\n+ let_it_be(:remote_account) { Fabricate(:account, domain: 'example.com') }\n \n before do\n allow(controller).to receive(:signed_request_actor).and_return(remote_account)\n@@ -397,7 +394,7 @@ describe StatusesController do\n end\n \n context 'when status is private' do\n- let(:status) { Fabricate(:status, account: account, visibility: :private) }\n+ before { status.update!(visibility: :private) }\n \n context 'when user is authorized to see it' do\n before do\n@@ -464,7 +461,7 @@ describe StatusesController do\n end\n \n context 'when status is direct' do\n- let(:status) { Fabricate(:status, account: account, visibility: :direct) }\n+ before { status.update!(visibility: :direct) }\n \n context 'when user is authorized to see it' do\n before do\n@@ -531,9 +528,8 @@ describe StatusesController do\n end\n end\n \n- describe 'GET #activity' do\n- let(:account) { Fabricate(:account) }\n- let(:status) { Fabricate(:status, account: account) }\n+ describe 'GET #activity', :account do\n+ let_it_be(:status) { Fabricate(:status, account: account) }\n \n context 'when account is permanently suspended' do\n before do\n@@ -593,9 +589,7 @@ describe StatusesController do\n end\n end\n \n- context 'when signed-in' do\n- let(:user) { Fabricate(:user) }\n-\n+ context 'when signed-in', :user do\n before do\n sign_in(user)\n end\n\n\nInitial performance data of the file you have to optimize:\n\n[TEST PROF INFO] FactoryProf enabled (simple mode)\n[TEST PROF INFO] RSpecDissect enabled\n\nRun options: exclude {:search=>true, :type=>#<Proc: ./spec/rails_helper.rb:82>}\n\nRandomized with seed 53322\n\nProgress: |================================================================================================================================|\n[TEST PROF INFO] RSpecDissect report\n\nTotal time: 00:00.814\n\nTotal `let` time: 00:00.643\nTotal `before(:each)` time: 00:00.688\n\nTop 5 slowest suites (by `let` time):\n\nActivityPub::Activity::Undo (./spec/lib/activitypub/activity/undo_spec.rb:5) – 00:00.643 of 00:00.814 (10)\n ↳ sender – 20\n ↳ recipient – 12\n ↳ subject – 10\n\nTop 5 slowest suites (by `before(:each)` time):\n\nActivityPub::Activity::Undo (./spec/lib/activitypub/activity/undo_spec.rb:5) – 00:00.688 of 00:00.814 (10)\n\n\nFinished in 0.86463 seconds (files took 1.14 seconds to load)\n10 examples, 0 failures\n\nRandomized with seed 53322\n[TEST PROF INFO] Factories usage\n\n Total: 28\n Total top-level: 24\n Total time: 00:00.656 (out of 00:01.414)\n Total uniq factories: 3\n\n total top-level total time time per call top-level time name\n\n 20 16 0.5713s 0.0286s 0.5355s account\n 7 7 0.1182s 0.0169s 0.1182s status\n 1 1 0.0033s 0.0033s 0.0033s favourite\n\n\nYou run in a loop of Thought, Action, PAUSE, Observation.\nAt the end of the loop you may output an Answer or re-enter the loop if you're not satisifed with the Observation.\nUse Thought to describe your thoughts about the question you have been asked.\nUse Action to run one of the actions available to you - then return PAUSE and stop.\nObservation will be the result of running those actions.\n\nEvery step of the loop MUST start with the corresponding keyword (Question, Thought, Action, PAUSE, Observation, Answer) followed by a colon and a space.\n\nThe Action keyword is only followed by the action name; the action payload goes on the next lines.\nThe action payload MUST end with the __END__ keyword.\n\nYour available actions are:\n\nrun_rspec:\n\nExample (it's a multiline action):\n\nAction: run_rspec\n<Ruby RSpec code>\n__END__\n\nRuns the given test contents and returns the output containing RSpec run information (including failures) and TestProf profiling information (FactoryProf, RSpecDissect, etc.).\nThe test contents MUST be the entire file contents, including the test class and any required files; all original scenarios MUST be preserved.\nAgain, you MUST always send me back the whole file even if some parts of it didn't change.\n\nExample session (the format must be exactly like the one below):\n\n Question: Optimize this test file:\n <file contents>\n\n Thought: This file is slow because it uses a lot of let!. I should replace them with let_it_be.\n\n Action: run_rspec\n <new file contents>\n __END__\n\n PAUSE\n\nStop and wait for the next request. You will be called again with this:\n\n Observation:\n\n [TEST PROF INFO] Factories usage\n\n Total: 663\n Total top-level: 319\n Total time: 00:01.612 (out of 00:01.773)\n Total uniq factories: 13\n\n Finished in 1.73 seconds (files took 9.27 seconds to load)\n 33 examples, 0 failures\n\nYou then output:\n\n Answer: It's a 4x speedup! I'm happy with the results. \n\nOptimize this test file:\n\n # frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe ActivityPub::Activity::Undo do\n subject { described_class.new(json, sender) }\n\n let(:sender) { Fabricate(:account, domain: 'example.com') }\n\n let(:json) do\n {\n '@context': 'https://www.w3.org/ns/activitystreams',\n id: 'foo',\n type: 'Undo',\n actor: ActivityPub::TagManager.instance.uri_for(sender),\n object: object_json,\n }.with_indifferent_access\n end\n\n describe '#perform' do\n context 'with Announce' do\n let(:status) { Fabricate(:status) }\n\n let(:object_json) do\n {\n id: 'bar',\n type: 'Announce',\n actor: ActivityPub::TagManager.instance.uri_for(sender),\n object: ActivityPub::TagManager.instance.uri_for(status),\n atomUri: 'barbar',\n }\n end\n\n context 'when not atomUri' do\n before do\n Fabricate(:status, reblog: status, account: sender, uri: 'bar')\n end\n\n it 'deletes the reblog' do\n subject.perform\n expect(sender.reblogged?(status)).to be false\n end\n end\n\n context 'with atomUri' do\n before do\n Fabricate(:status, reblog: status, account: sender, uri: 'barbar')\n end\n\n it 'deletes the reblog by atomUri' do\n subject.perform\n expect(sender.reblogged?(status)).to be false\n end\n end\n\n context 'with only object uri' do\n let(:object_json) { 'bar' }\n\n before do\n Fabricate(:status, reblog: status, account: sender, uri: 'bar')\n end\n\n it 'deletes the reblog by uri' do\n subject.perform\n expect(sender.reblogged?(status)).to be false\n end\n end\n end\n\n context 'with Accept' do\n let(:recipient) { Fabricate(:account) }\n let(:object_json) do\n {\n id: 'bar',\n type: 'Accept',\n actor: ActivityPub::TagManager.instance.uri_for(sender),\n object: 'follow-to-revoke',\n }\n end\n\n before do\n recipient.follow!(sender, uri: 'follow-to-revoke')\n end\n\n it 'deletes follow from recipient to sender' do\n subject.perform\n expect(recipient.following?(sender)).to be false\n end\n\n it 'creates a follow request from recipient to sender' do\n subject.perform\n expect(recipient.requested?(sender)).to be true\n end\n end\n\n context 'with Block' do\n let(:recipient) { Fabricate(:account) }\n\n let(:object_json) do\n {\n id: 'bar',\n type: 'Block',\n actor: ActivityPub::TagManager.instance.uri_for(sender),\n object: ActivityPub::TagManager.instance.uri_for(recipient),\n }\n end\n\n before do\n sender.block!(recipient, uri: 'bar')\n end\n\n it 'deletes block from sender to recipient' do\n subject.perform\n expect(sender.blocking?(recipient)).to be false\n end\n\n context 'with only object uri' do\n let(:object_json) { 'bar' }\n\n it 'deletes block from sender to recipient' do\n subject.perform\n expect(sender.blocking?(recipient)).to be false\n end\n end\n end\n\n context 'with Follow' do\n let(:recipient) { Fabricate(:account) }\n\n let(:object_json) do\n {\n id: 'bar',\n type: 'Follow',\n actor: ActivityPub::TagManager.instance.uri_for(sender),\n object: ActivityPub::TagManager.instance.uri_for(recipient),\n }\n end\n\n before do\n sender.follow!(recipient, uri: 'bar')\n end\n\n it 'deletes follow from sender to recipient' do\n subject.perform\n expect(sender.following?(recipient)).to be false\n end\n\n context 'with only object uri' do\n let(:object_json) { 'bar' }\n\n it 'deletes follow from sender to recipient' do\n subject.perform\n expect(sender.following?(recipient)).to be false\n end\n end\n end\n\n context 'with Like' do\n let(:status) { Fabricate(:status) }\n\n let(:object_json) do\n {\n id: 'bar',\n type: 'Like',\n actor: ActivityPub::TagManager.instance.uri_for(sender),\n object: ActivityPub::TagManager.instance.uri_for(status),\n }\n end\n\n before do\n Fabricate(:favourite, account: sender, status: status)\n end\n\n it 'deletes favourite from sender to status' do\n subject.perform\n expect(sender.favourited?(status)).to be false\n end\n end\n end\nend\n"},{"role":"assistant","content":"Thought: The file uses multiple `let` statements for `sender`, `recipient`, and `status`, which are created for each test. We can optimize this by using `let_it_be` for these shared resources. We should also consider using `before_all` for setup that's repeated across multiple contexts.\n\nAction: run_rspec\n# frozen_string_literal: true\n\nrequire 'rails_helper'\n\nRSpec.describe ActivityPub::Activity::Undo do\n subject { described_class.new(json, sender) }\n\n let_it_be(:sender) { Fabricate(:account, domain: 'example.com') }\n let_it_be(:recipient) { Fabricate(:account) }\n let_it_be(:status) { Fabricate(:status) }\n\n let(:json) do\n {\n '@context': 'https://www.w3.org/ns/activitystreams',\n id: 'foo',\n type: 'Undo',\n actor: ActivityPub::TagManager.instance.uri_for(sender),\n object: object_json,\n }.with_indifferent_access\n end\n\n describe '#perform' do\n context 'with Announce' do\n let(:object_json) do\n {\n id: 'bar',\n type: 'Announce',\n actor: ActivityPub::TagManager.instance.uri_for(sender),\n object: ActivityPub::TagManager.instance.uri_for(status),\n atomUri: 'barbar',\n }\n end\n\n context 'when not atomUri' do\n before do\n Fabricate(:status, reblog: status, account: sender, uri: 'bar')\n end\n\n it 'deletes the reblog' do\n subject.perform\n expect(sender.reblogged?(status)).to be false\n end\n end\n\n context 'with atomUri' do\n before do\n Fabricate(:status, reblog: status, account: sender, uri: 'barbar')\n end\n\n it 'deletes the reblog by atomUri' do\n subject.perform\n expect(sender.reblogged?(status)).to be false\n end\n end\n\n context 'with only object uri' do\n let(:object_json) { 'bar' }\n\n before do\n Fabricate(:status, reblog: status, account: sender, uri: 'bar')\n end\n\n it 'deletes the reblog by uri' do\n subject.perform\n expect(sender.reblogged?(status)).to be false\n end\n end\n end\n\n context 'with Accept' do\n let(:object_json) do\n {\n id: 'bar',\n type: 'Accept',\n actor: ActivityPub::TagManager.instance.uri_for(sender),\n object: 'follow-to-revoke',\n }\n end\n\n before_all do\n recipient.follow!(sender, uri: 'follow-to-revoke')\n end\n\n it 'deletes follow from recipient to sender' do\n subject.perform\n expect(recipient.following?(sender)).to be false\n end\n\n it 'creates a follow request from recipient to sender' do\n subject.perform\n expect(recipient.requested?(sender)).to be true\n end\n end\n\n context 'with Block' do\n let(:object_json) do\n {\n id: 'bar',\n type: 'Block',\n actor: ActivityPub::TagManager.instance.uri_for(sender),\n object: ActivityPub::TagManager.instance.uri_for(recipient),\n }\n end\n\n before_all do\n sender.block!(recipient, uri: 'bar')\n end\n\n it 'deletes block from sender to recipient' do\n subject.perform\n expect(sender.blocking?(recipient)).to be false\n end\n\n context 'with only object uri' do\n let(:object_json) { 'bar' }\n\n it 'deletes block from sender to recipient' do\n subject.perform\n expect(sender.blocking?(recipient)).to be false\n end\n end\n end\n\n context 'with Follow' do\n let(:object_json) do\n {\n id: 'bar',\n type: 'Follow',\n actor: ActivityPub::TagManager.instance.uri_for(sender),\n object: ActivityPub::TagManager.instance.uri_for(recipient),\n }\n end\n\n before_all do\n sender.follow!(recipient, uri: 'bar')\n end\n\n it 'deletes follow from sender to recipient' do\n subject.perform\n expect(sender.following?(recipient)).to be false\n end\n\n context 'with only object uri' do\n let(:object_json) { 'bar' }\n\n it 'deletes follow from sender to recipient' do\n subject.perform\n expect(sender.following?(recipient)).to be false\n end\n end\n end\n\n context 'with Like' do\n let(:object_json) do\n {\n id: 'bar',\n type: 'Like',\n actor: ActivityPub::TagManager.instance.uri_for(sender),\n object: ActivityPub::TagManager.instance.uri_for(status),\n }\n end\n\n before do\n Fabricate(:favourite, account: sender, status: status)\n end\n\n it 'deletes favourite from sender to status' do\n subject.perform\n expect(sender.favourited?(status)).to be false\n end\n end\n end\nend\n__END__\n\nPAUSE"},{"role":"user","content":"Observation:\n\n[TEST PROF INFO] FactoryProf enabled (simple mode)\n[TEST PROF INFO] RSpecDissect enabled\n\nRun options: exclude {:search=>true, :type=>#<Proc: ./spec/rails_helper.rb:82>}\n\nRandomized with seed 25802\n\nProgress: |================================================================================================================================|\n[TEST PROF INFO] RSpecDissect report\n\nTotal time: 00:00.144\n\nTotal `let` time: 00:00.008\nTotal `before(:each)` time: 00:00.022\n\nTop 5 slowest suites (by `let` time):\n\nActivityPub::Activity::Undo (./spec/lib/activitypub/activity/undo_ai_suggest_1_spec.rb:5) – 00:00.008 of 00:00.144 (10)\n ↳ sender – 14\n ↳ subject – 10\n ↳ status – 8\n\nTop 5 slowest suites (by `before(:each)` time):\n\nActivityPub::Activity::Undo (./spec/lib/activitypub/activity/undo_ai_suggest_1_spec.rb:5) – 00:00.022 of 00:00.144 (10)\n\n\nFinished in 0.56433 seconds (files took 1.1 seconds to load)\n10 examples, 0 failures\n\nRandomized with seed 25802\n[TEST PROF INFO] Factories usage\n\n Total: 8\n Total top-level: 7\n Total time: 00:00.370 (out of 00:01.038)\n Total uniq factories: 3\n\n total top-level total time time per call top-level time name\n\n 4 4 0.0515s 0.0129s 0.0515s status\n 3 2 0.3216s 0.1072s 0.3163s account\n 1 1 0.0028s 0.0028s 0.0028s favourite\n"},{"role":"assistant","content":"Thought: The optimization has significantly improved the performance of the test file. The total time has decreased from 0.814 seconds to 0.144 seconds, which is about a 5.6x speedup. The number of factory calls has also been reduced from 28 to 8, which is a substantial improvement. The `let` time and `before(:each)` time have both decreased significantly.\n\nAnswer: The optimization has been successful. We've achieved a 5.6x speedup in total time and reduced factory calls by 71%. The use of `let_it_be` for shared resources and `before_all` for setup has significantly improved the test performance. No further optimizations are necessary at this point."}]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment