はじめに
hkob の雑記録の第176回目は、昨日作成したテストデータを使って、10MB を超えるファイルに対する FileUploadObject のコンストラクタのテストおよび実装を作成します。今日は途中までになってしまいました。
with a small file のテスト修正
画像の場合には、15,369バイトの ErSxuLeq.png-medium.png というファイルを spec/fixtures に置いていました。今回、10MB を超えるファイルを用意するのですが、そのようなファイルをリポジトリに起きたくありません。また、テストのたびに Tempfile でファイルを分割するもの無駄なので、ファイルに対するメソッドを全て stub 化すことにしてみます。
まず、with a small file の場合も、ファイルを使わずにテストを通過するようにしてみます。File については、 exist? と size 、その後の FilePart の new でファイルを実際に開くので、これ自体は mock オブジェクトを作成するようにしました。
describe "initialize" do context "with a small file" do let(:fname) { "spec/fixtures/ErSxuLeq.png-medium.png" } let(:id) { TestConnection::FILE_UPLOAD_IMAGE_ID } let(:response) { tc.read_json "upload_file_image" } before do allow(tc.nc.multipart_client).to receive(:send) .and_return(instance_double(Faraday::Response, {body: response})) allow(File).to receive(:exist?).with(fname).and_return(true) allow(File).to receive(:size).with(fname).and_return(15_369) allow(Faraday::Multipart::FilePart).to receive(:new).and_return(instance_double(Faraday::Multipart::FilePart)) end subject { described_class.new(fname: fname) } it { expect(subject.id).to eq id } end end
このように修正することで、ファイルを用意することなくテストが通過しました。
FileUploadObject initialize with a small file is expected to eq "20cd8e4e98ab81aa973b00b23083c115" Finished in 0.01175 seconds (files took 0.47518 seconds to load) 1 example, 0 failures
with a large file テストの追加
これができれば、large file についても大きなファイルがなくてもテストができるはずです。まずはファイルを分割する split_file メソッドのテストを行います。26 バイトのファイルを作成し、20バイトと6バイトの二つのファイルに分割されることを確認します。
describe "split_to_small_files" do before do @org_file = Tempfile.new("org_file") @org_file.write "0" * 26 @org_file.rewind @temp_files = described_class.split_to_small_files(@org_file.path, 20) end after do @temp_files.each { |f| f.close } @org_file.close end it "splits the file into smaller parts" do expect(@temp_files.size).to eq 2 expect(File.size(@temp_files[0].path)).to eq 20 expect(File.size(@temp_files[1].path)).to eq 6 end end
実装は昨日テストした時に作ったコードそのままです。これがテスト通ったので、split_to_small_files は、今後でテストでは stub にしてしまいます。
def self.split_to_small_files(org_file, max_size = MAX_SIZE) raise StandardError, "File does not exist: #{org_file}" unless File.exist?(org_file) temp_files = [] File.open(org_file, "rb") do |file| until file.eof? chunk = file.read(max_size) temp_file = Tempfile.new("part_") temp_file.binmode temp_file.write(chunk) temp_file.rewind temp_files << temp_file end end temp_files end
おわりに
このままテストを続けるつもりでしたが、サンプル shell script で示されている -F による multipart の part_number=1 の部分を Ruby からどのように送付すればいいかの確認ができませんでした。明日、実際に Faraday から Notion API を叩いてみて検証してみます。
curl --request POST \ --url 'https://api.notion.com/v1/file_uploads/a3f9d3e2-1abc-42de-b904-badc0ffee000/send' \ --header 'Authorization: Bearer ntn_****' \ --header 'Notion-Version: 2022-06-28' \ --header 'Content-Type: multipart/form-data' \ -F "file=@image_to_upload_split_aa.png" -F "part_number=1"