require 'rails_helper' RSpec.describe PostBulkCreator do include_context 'English locale' it 'limits workers to two and keeps failures in their request slots' do locale = Locale.nipponese actor = instance_double(User, id: 123) allow(User).to receive(:find).with(123) { instance_double(User, id: 123) } mutex = Mutex.new active = 0 maximum_active = 0 creators = [] allow(PostCreatePreflight).to receive(:new) do |attributes:, **| preflight = instance_double(PostCreatePreflight) allow(preflight).to receive(:run) do mutex.synchronize do active += 1 maximum_active = [maximum_active, active].max end sleep 0.02 mutex.synchronize { active -= 1 } attributes.symbolize_keys.merge( existing_post_id: nil, field_warnings: { }, base_warnings: []) end preflight end allow(PostCreator).to receive(:new) do |attributes:, **| creator = instance_double(PostCreator) mutex.synchronize { creators << creator } if attributes[:title] == 'broken' allow(creator).to receive(:create!).and_raise(StandardError, 'broken') else post = instance_double(Post, id: attributes[:title].delete_prefix('post ').to_i) allow(creator).to receive(:create!).and_return(post) end creator end posts = [ { 'title' => 'post 1', 'url' => 'https://example.com/1' }, { 'title' => 'broken', 'url' => 'https://example.com/2' }, { 'title' => 'post 3', 'url' => 'https://example.com/3' }, { 'title' => 'post 4', 'url' => 'https://example.com/4' }] results = described_class.new( actor:, posts:, thumbnails: { }).run(locale).fetch(:results) expect(creators.length).to eq(posts.length) creators.each do |creator| expect(creator).to have_received(:create!).with(locale).once end expect(maximum_active).to eq(2) expect(results.length).to eq(posts.length) expect(results.map { _1[:status] }).to eq( ['created', 'failed', 'created', 'created']) expect(results[0].dig(:post, :id)).to eq(1) expect(results[1]).to include(status: 'failed', recoverable: false) expect(results[2].dig(:post, :id)).to eq(3) expect(results[3].dig(:post, :id)).to eq(4) end it 'passes a future English locale to preflight and creation in every worker' do pending '日本語以外の Locale 有効化は別課題で実装する' locale actor = instance_double(User, id: 123) allow(User).to receive(:find).with(123).and_return(actor) preflight = instance_double(PostCreatePreflight) creator = instance_double(PostCreator) post = instance_double(Post, id: 1) allow(PostCreatePreflight).to receive(:new).and_return(preflight) allow(preflight).to receive(:run).with(locale).and_return(existing_post_id: nil) allow(PostCreator).to receive(:new).and_return(creator) allow(creator).to receive(:create!).with(locale).and_return(post) results = described_class.new( actor:, posts: [{ title: 'future post' }], thumbnails: { }).run(locale) expect(results.fetch(:results)).to contain_exactly( hash_including(status: 'created', post: { id: 1 })) expect(preflight).to have_received(:run).with(locale).once expect(creator).to have_received(:create!).with(locale).once end end