require 'rails_helper' require 'webmock/rspec' require 'digest' RSpec.describe EjabberdManager::SetAvatar, type: :model do let(:user) { create :user, cn: "willherschel", ou: "kosmos.org" } let(:fixture_path) { Rails.root.join("spec/fixtures/files/bender.png") } let(:img_data) do ImageProcessing::Vips .source(File.open(fixture_path)) .resize_to_fill(256, 256) .convert("png") .call.read end let(:sha1_hash) { Digest::SHA1.hexdigest(img_data) } let(:base64_data) { Base64.strict_encode64(img_data) } before do ActiveStorage::Blob.create_and_upload!( io: File.open(fixture_path), filename: "bender.png", content_type: "image/png" ).tap { |blob| user.avatar.attach(blob) } end def stub_send_stanza_ok stub_request(:post, "http://xmpp.example.com/api/send_stanza") .to_return(status: 200, body: "", headers: {}) end context "when an avatar is already set and overwrite is false" do before do allow(EjabberdManager::GetAvatar).to receive(:call).with(user: user).and_return({ img_base64: "abc", content_type: "image/png" }) stub_send_stanza_ok end it "does not send any stanzas" do described_class.call(user: user) expect(WebMock).not_to have_requested(:post, "http://xmpp.example.com/api/send_stanza") end end context "when no avatar is set yet" do let(:sent_stanzas) { [] } before do allow(EjabberdManager::GetAvatar).to receive(:call).with(user: user).and_return(nil) stub_request(:post, "http://xmpp.example.com/api/send_stanza") .to_return(status: 200, body: "", headers: {}) end it "publishes the XEP-0084 data and metadata stanzas" do service = described_class.new(user: user) allow(service).to receive(:send_stanza) do |payload| sent_stanzas << payload[:stanza] double(status: 200) end service.call expect(sent_stanzas.length).to eq(2) data_stanza = sent_stanzas.find { |s| s.include?("urn:xmpp:avatar:data") } meta_stanza = sent_stanzas.find { |s| s.include?("urn:xmpp:avatar:metadata") } expect(data_stanza).to include("from='willherschel@kosmos.org'") expect(data_stanza).to include("") expect(data_stanza).to include("#{base64_data}") expect(meta_stanza).to include("from='willherschel@kosmos.org'") expect(meta_stanza).to include("") expect(meta_stanza).to include("bytes='#{img_data.size}'") expect(meta_stanza).to include("id='#{sha1_hash}'") expect(meta_stanza).to include("type='image/png'") expect(meta_stanza).to include("height='256'") expect(meta_stanza).to include("width='256'") end end context "when overwrite is true" do before do allow(EjabberdManager::GetAvatar).to receive(:call).and_return({ img_base64: "abc", content_type: "image/png" }) stub_send_stanza_ok end it "does not check for an existing avatar and sends stanzas" do described_class.call(user: user, overwrite: true) expect(EjabberdManager::GetAvatar).not_to have_received(:call) expect(WebMock).to have_requested(:post, "http://xmpp.example.com/api/send_stanza").twice end end context "when the ejabberd API returns a non-200 status" do before do allow(EjabberdManager::GetAvatar).to receive(:call).with(user: user).and_return(nil) stub_request(:post, "http://xmpp.example.com/api/send_stanza") .to_return(status: 500, body: "error", headers: {}) end it "raises" do expect { described_class.call(user: user) }.to raise_error(RuntimeError) end end end