diaspora/spec/integration/account_migration_spec.rb

372 lines
13 KiB
Ruby

# frozen_string_literal: true
require "integration/federation/federation_helper"
def create_remote_contact(user, pod_host)
FactoryGirl.create(
:contact,
user: user,
person: FactoryGirl.create(
:person,
pod: Pod.find_or_create_by(url: "http://#{pod_host}"),
diaspora_handle: "#{r_str}@#{pod_host}"
)
)
end
shared_examples_for "every migration scenario" do
it "updates person references" do
contact = FactoryGirl.create(:contact, person: old_person)
post = FactoryGirl.create(:status_message, author: old_person)
reshare = FactoryGirl.create(:reshare, author: old_person)
photo = FactoryGirl.create(:photo, author: old_person)
comment = FactoryGirl.create(:comment, author: old_person)
like = FactoryGirl.create(:like, author: old_person)
participation = FactoryGirl.create(:participation, author: old_person)
poll_participation = FactoryGirl.create(:poll_participation, author: old_person)
mention = FactoryGirl.create(:mention, person: old_person)
message = FactoryGirl.create(:message, author: old_person)
conversation = FactoryGirl.create(:conversation, author: old_person)
block = FactoryGirl.create(:user).blocks.create(person: old_person)
role = FactoryGirl.create(:role, person: old_person)
# Create ConversationVisibility by creating a conversation with participants
conversation2 = FactoryGirl.build(:conversation)
FactoryGirl.create(:contact, user: old_user, person: conversation2.author) if old_person.local?
conversation2.participants << old_person
conversation2.save!
visibility = ConversationVisibility.find_by(person_id: old_person.id)
# In order to create a notification actor we need to create a notification first
notification = FactoryGirl.build(:notification)
notification.actors << old_person
notification.save!
actor = notification.notification_actors.find_by(person_id: old_person.id)
run_migration
expect(contact.reload.person).to eq(new_person)
expect(post.reload.author).to eq(new_person)
expect(reshare.reload.author).to eq(new_person)
expect(photo.reload.author).to eq(new_person)
expect(comment.reload.author).to eq(new_person)
expect(like.reload.author).to eq(new_person)
expect(participation.reload.author).to eq(new_person)
expect(poll_participation.reload.author).to eq(new_person)
expect(mention.reload.person).to eq(new_person)
expect(message.reload.author).to eq(new_person)
expect(conversation.reload.author).to eq(new_person)
expect(block.reload.person).to eq(new_person)
expect(role.reload.person).to eq(new_person)
expect(visibility.reload.person).to eq(new_person)
expect(actor.reload.person).to eq(new_person)
end
describe "old person account is closed and profile is cleared" do
subject { old_person }
before do
run_migration
subject.reload
end
include_examples "it makes account closed and clears profile"
end
describe "old person doesn't have any reference left" do
let(:person) { old_person }
before do
DataGenerator.create(person, :generic_person_data)
end
def account_removal_method
run_migration
person.reload
end
include_examples "it removes the person associations"
it "removes the person conversations" do
expect {
account_removal_method
}.to change(nil, "conversations empty?") { Conversation.where(author: person).empty? }
.to(be_truthy)
.and(change(nil, "conversation visibilities of other participants empty?") {
ConversationVisibility.where(conversation: Conversation.where(author: person)).empty?
}.to(be_truthy))
end
end
end
shared_examples_for "migration scenarios with local old user" do
it "locks the old user account" do
run_migration
expect(old_user.reload).to be_a_locked_account
end
end
shared_examples_for "migration scenarios initiated remotely" do
it "resends known contacts to the new user" do
contacts = Array.new(2) { FactoryGirl.create(:contact, person: old_user.person, sharing: true) }
expect(DiasporaFederation::Federation::Sender).to receive(:private)
.twice do |sender_id, obj_str, _urls, _xml|
expect(sender_id).to eq(contacts.first.user_id)
expect(obj_str).to eq("Contact:#{contacts.first.user.diaspora_handle}:#{new_user.diaspora_handle}")
contacts.shift
[]
end
inlined_jobs { run_migration }
end
end
shared_examples_for "migration scenarios initiated locally" do
it "dispatches account migration message to the federation" do
expect(DiasporaFederation::Federation::Sender).to receive(:public) do |sender_id, obj_str, urls, xml|
if old_user.person.remote?
expect(sender_id).to eq(old_user.diaspora_handle)
else
expect(sender_id).to eq(old_user.id)
end
expect(obj_str).to eq("AccountMigration:#{old_user.diaspora_handle}:#{new_user.diaspora_handle}")
subscribers = [remote_contact.person]
subscribers.push(old_user) if old_user.person.remote?
expect(urls).to match_array(subscribers.map(&:url).map {|url| "#{url}receive/public" })
entity = nil
expect {
magic_env = Nokogiri::XML(xml).root
entity = DiasporaFederation::Salmon::MagicEnvelope
.unenvelop(magic_env, old_user.diaspora_handle).payload
}.not_to raise_error
expect(entity).to be_a(DiasporaFederation::Entities::AccountMigration)
expect(entity.author).to eq(old_user.diaspora_handle)
expect(entity.profile.author).to eq(new_user.diaspora_handle)
[]
end
inlined_jobs do
run_migration
end
end
end
shared_examples_for "migration scenarios with local user rename" do
it "updates user references" do
invited_user = FactoryGirl.create(:user, invited_by: old_user)
aspect = FactoryGirl.create(:aspect, user: old_user, name: r_str)
contact = FactoryGirl.create(:contact, user: old_user)
service = FactoryGirl.create(:service, user: old_user)
pref = UserPreference.create!(user: old_user, email_type: "also_commented")
tag_following = FactoryGirl.create(:tag_following, user: old_user)
block = FactoryGirl.create(:block, user: old_user)
notification = FactoryGirl.create(:notification, recipient: old_user)
report = FactoryGirl.create(:report, user: old_user)
authorization = FactoryGirl.create(:auth_with_read, user: old_user)
share_visibility = FactoryGirl.create(:share_visibility, user: old_user)
run_migration
expect(invited_user.reload.invited_by).to eq(new_user)
expect(aspect.reload.user).to eq(new_user)
expect(contact.reload.user).to eq(new_user)
expect(service.reload.user).to eq(new_user)
expect(pref.reload.user).to eq(new_user)
expect(tag_following.reload.user).to eq(new_user)
expect(block.reload.user).to eq(new_user)
expect(notification.reload.recipient).to eq(new_user)
expect(report.reload.user).to eq(new_user)
expect(authorization.reload.user).to eq(new_user)
expect(share_visibility.reload.user).to eq(new_user)
end
end
describe "account migration" do
# this is the case when we receive account migration message from the federation
context "remotely initiated" do
let(:entity) { create_account_migration_entity(old_user.diaspora_handle, new_user) }
def run_migration
allow_callbacks(%i[queue_public_receive fetch_public_key receive_entity])
post_message(generate_payload(entity, old_user))
end
context "both new and old profiles are remote" do
let(:old_user) { remote_user_on_pod_c }
let(:old_person) { old_user.person }
let(:new_user) { remote_user_on_pod_b }
let(:new_person) { new_user.person }
it "creates AccountMigration db object" do
run_migration
expect(AccountMigration.where(old_person: old_user.person, new_person: new_user.person)).to exist
end
include_examples "every migration scenario"
include_examples "migration scenarios initiated remotely"
context "when new person has been migrated before" do
let(:intermidiate_person) { create_remote_user("remote-d.net").person }
before do
AccountMigration.create!(old_person: intermidiate_person, new_person: new_person).perform!
end
def run_migration
AccountMigration.create!(old_person: old_person, new_person: intermidiate_person).perform!
end
include_examples "every migration scenario"
include_examples "migration scenarios initiated remotely"
end
end
# this is the case when we're a pod, which was left by a person in favor of remote one
context "old user is local, new user is remote" do
let(:old_user) { FactoryGirl.create(:user) }
let(:old_person) { old_user.person }
let(:new_user) { remote_user_on_pod_b }
let(:new_person) { new_user.person }
include_examples "every migration scenario"
include_examples "migration scenarios initiated remotely"
it_behaves_like "migration scenarios with local old user"
it_behaves_like "deletes all of the user data" do
let(:user) { old_user }
before do
DataGenerator.create(user, :generic_user_data)
end
def account_removal_method
run_migration
user.reload
end
end
context "when new person has been migrated before" do
let(:intermidiate_person) { create_remote_user("remote-d.net").person }
before do
AccountMigration.create!(old_person: intermidiate_person, new_person: new_person).perform!
end
def run_migration
AccountMigration.create!(old_person: old_user.person, new_person: intermidiate_person).perform!
end
include_examples "every migration scenario"
include_examples "migration scenarios initiated remotely"
it_behaves_like "migration scenarios with local old user"
end
end
end
context "locally initiated" do
before do
allow(DiasporaFederation.callbacks).to receive(:trigger).and_call_original
end
# this is the case when user migrates to our pod from a remote one
context "old user is remote and new user is local" do
let(:old_user) { remote_user_on_pod_c }
let(:old_person) { old_user.person }
let(:new_user) { FactoryGirl.create(:user) }
let(:new_person) { new_user.person }
def run_migration
AccountMigration.create!(
old_person: old_user.person,
new_person: new_user.person,
old_private_key: old_user.serialized_private_key
).perform!
end
include_examples "every migration scenario"
it_behaves_like "migration scenarios initiated locally" do
let!(:remote_contact) { create_remote_contact(new_user, "remote-friend.org") }
end
context "when new person has been migrated before" do
let(:intermidiate_person) { FactoryGirl.create(:user).person }
before do
AccountMigration.create!(old_person: intermidiate_person, new_person: new_person).perform!
end
def run_migration
AccountMigration.create!(
old_person: old_person,
new_person: intermidiate_person,
old_private_key: old_user.serialized_private_key
).perform!
end
include_examples "every migration scenario"
end
end
# this is the case when a user changes diaspora id but stays on the same pod
context "old user is local and new user is local" do
let(:old_user) { FactoryGirl.create(:user) }
let(:old_person) { old_user.person }
let(:new_user) { FactoryGirl.create(:user) }
let(:new_person) { new_user.person }
def run_migration
AccountMigration.create!(old_person: old_person, new_person: new_person).perform!
end
include_examples "every migration scenario"
it_behaves_like "migration scenarios initiated locally" do
let!(:remote_contact) { create_remote_contact(old_user, "remote-friend.org") }
end
it_behaves_like "migration scenarios with local old user"
it "clears the old user account" do
run_migration
expect(old_user.reload).to be_a_clear_account
end
include_examples "migration scenarios with local user rename"
context "when new user has been migrated before" do
let(:intermidiate_person) { FactoryGirl.create(:user).person }
before do
AccountMigration.create!(old_person: intermidiate_person, new_person: new_person).perform!
end
def run_migration
AccountMigration.create!(
old_person: old_person,
new_person: intermidiate_person
).perform!
end
include_examples "every migration scenario"
it_behaves_like "migration scenarios with local old user"
it "clears the old user account" do
run_migration
expect(old_user.reload).to be_a_clear_account
end
include_examples "migration scenarios with local user rename"
end
end
end
end