require 'spec_helper' #require 'synchromesh/test_components' describe "regulate_broadcast" do before(:each) do stub_const "TestModel1", Class.new TestModel1.class_eval do include ActiveModel::Model def react_serializer as_json # does not include type: xxx as per reactive-record end def attribute_names [:id, :attr1, :attr2, :attr3, :attr4, :attr5] end def previous_changes Hash[*as_json.keys.collect { |attr| [attr, send(attr)] }.flatten(1)] end attr_accessor :id, :attr1, :attr2, :attr3, :attr4, :attr5 end stub_const "TestModel2", Class.new TestModel2.class_eval do include ActiveModel::Model def react_serializer as_json # does not include type: xxx as per reactive-record end def attribute_names [:id, :attrA, :attrB, :attrC, :attrD, :attrE] end def previous_changes Hash[*as_json.keys.collect { |attr| [attr, send(attr)] }.flatten(1)] end attr_accessor :id, :attrA, :attrB, :attrC, :attrD, :attrE end allow(HyperMesh::Connection).to receive(:active).and_return(['Application', 'TestModel1-1', 'TestModel1-7', 'TestModel2-8']) allow_any_instance_of(HyperMesh::InternalPolicy).to receive(:id).and_return(:unique_broadcast_id) end it "will broadcast the instance policies for a model" do stub_const "TestModel1Policy", Class.new TestModel1Policy.class_eval do regulate_broadcast do | policy | policy.send_all.to(self) end end model = TestModel1.new(id: 1, attr1: 1, attr2: 2, attr3: 3, attr4: 4, attr5: 5) expect { |b| HyperMesh::InternalPolicy.regulate_broadcast(model, &b) }.to yield_successive_args( { broadcast_id: :unique_broadcast_id, channel: 'TestModel1-1', channels: ['TestModel1-1'], klass: 'TestModel1', record: {id: 1, attr1: 1, attr2: 2, attr3: 3, attr4: 4, attr5: 5}, previous_changes: {id: 1, attr1: 1, attr2: 2, attr3: 3, attr4: 4, attr5: 5} } ) end it "will raise an error if the policy is not sent" do stub_const "TestModel1Policy", Class.new TestModel1Policy.class_eval do regulate_broadcast do | policy | policy.send_all end end model = TestModel1.new(id: 1, attr1: 1, attr2: 2, attr3: 3, attr4: 4, attr5: 5) expect { |b| HyperMesh::InternalPolicy.regulate_broadcast(model, &b) }. to raise_error("TestModel1 instance broadcast policy not sent to any channel") end it "will intersect all policies for the same channel" do stub_const "TestModel1Policy", Class.new TestModel1Policy.class_eval do regulate_broadcast do | policy | policy.send_only(:attr1, :attr2).to(self) policy.send_only(:attr2, :attr3).to(self) end end model = TestModel1.new(id: 1, attr1: 1, attr2: 2, attr3: 3, attr4: 4, attr5: 5) expect { |b| HyperMesh::InternalPolicy.regulate_broadcast(model, &b) }.to yield_successive_args( { broadcast_id: :unique_broadcast_id, channel: 'TestModel1-1', channels: ['TestModel1-1'], klass: 'TestModel1', record: {id: 1, attr2: 2}, previous_changes: {id: 1, attr2: 2} } ) end it "will broadcast the instance policies for a model and on a class channel" do stub_const "TestModel1Policy", Class.new stub_const "Application", Class.new TestModel1Policy.class_eval do regulate_broadcast do | policy | policy.send_all.to(self, Application) end end model = TestModel1.new(id: 1, attr1: 1, attr2: 2, attr3: 3, attr4: 4, attr5: 5) expect { |b| HyperMesh::InternalPolicy.regulate_broadcast(model, &b) }.to yield_successive_args( { broadcast_id: :unique_broadcast_id, channel: 'TestModel1-1', channels: ['TestModel1-1', 'Application'], klass: 'TestModel1', record: {id: 1, attr1: 1, attr2: 2, attr3: 3, attr4: 4, attr5: 5}, previous_changes: {id: 1, attr1: 1, attr2: 2, attr3: 3, attr4: 4, attr5: 5} }, { broadcast_id: :unique_broadcast_id, channel: 'Application', channels: ['TestModel1-1', 'Application'], klass: 'TestModel1', record: {id: 1, attr1: 1, attr2: 2, attr3: 3, attr4: 4, attr5: 5}, previous_changes: {id: 1, attr1: 1, attr2: 2, attr3: 3, attr4: 4, attr5: 5} } ) end it "will handle arrays and falsy values in the to method" do stub_const "TestModel1Policy", Class.new stub_const "Application", Class.new TestModel1Policy.class_eval do regulate_broadcast do | policy | policy.send_all.to(false, [self, Application], nil) end end model = TestModel1.new(id: 1, attr1: 1, attr2: 2, attr3: 3, attr4: 4, attr5: 5) expect { |b| HyperMesh::InternalPolicy.regulate_broadcast(model, &b) }.to yield_successive_args( { broadcast_id: :unique_broadcast_id, channel: 'TestModel1-1', channels: ['TestModel1-1', 'Application'], klass: 'TestModel1', record: {id: 1, attr1: 1, attr2: 2, attr3: 3, attr4: 4, attr5: 5}, previous_changes: {id: 1, attr1: 1, attr2: 2, attr3: 3, attr4: 4, attr5: 5} }, { broadcast_id: :unique_broadcast_id, channel: 'Application', channels: ['TestModel1-1', 'Application'], klass: 'TestModel1', record: {id: 1, attr1: 1, attr2: 2, attr3: 3, attr4: 4, attr5: 5}, previous_changes: {id: 1, attr1: 1, attr2: 2, attr3: 3, attr4: 4, attr5: 5} } ) end it "will broadcast different instance policies on different channels" do stub_const "TestModel1Policy", Class.new stub_const "Application", Class.new TestModel1Policy.class_eval do regulate_broadcast do | policy | policy.send_all.to(self) policy.send_only(:id).to(Application) end end model = TestModel1.new(id: 1, attr1: 1, attr2: 2, attr3: 3, attr4: 4, attr5: 5) expect { |b| HyperMesh::InternalPolicy.regulate_broadcast(model, &b) }.to yield_successive_args( { broadcast_id: :unique_broadcast_id, channel: 'TestModel1-1', channels: ['TestModel1-1', 'Application'], klass: 'TestModel1', record: {id: 1, attr1: 1, attr2: 2, attr3: 3, attr4: 4, attr5: 5}, previous_changes: {id: 1, attr1: 1, attr2: 2, attr3: 3, attr4: 4, attr5: 5} }, { broadcast_id: :unique_broadcast_id, channel: 'Application', channels: ['TestModel1-1', 'Application'], klass: 'TestModel1', record: {id: 1}, previous_changes: {id: 1} } ) end it "will pass the proper policy object" do stub_const "TestModel1Policy", Class.new stub_const "Application", Class.new TestModel1Policy.class_eval do def public_attributes [:id] end regulate_broadcast do | policy | policy.send_all.to(self) policy.send_only(*policy.public_attributes).to(Application) end end model = TestModel1.new(id: 1, attr1: 1, attr2: 2, attr3: 3, attr4: 4, attr5: 5) expect { |b| HyperMesh::InternalPolicy.regulate_broadcast(model, &b) }.to yield_successive_args( { broadcast_id: :unique_broadcast_id, channel: 'TestModel1-1', channels: ['TestModel1-1', 'Application'], klass: 'TestModel1', record: {id: 1, attr1: 1, attr2: 2, attr3: 3, attr4: 4, attr5: 5}, previous_changes: {id: 1, attr1: 1, attr2: 2, attr3: 3, attr4: 4, attr5: 5} }, { broadcast_id: :unique_broadcast_id, channel: 'Application', channels: ['TestModel1-1', 'Application'], klass: 'TestModel1', record: {id: 1}, previous_changes: {id: 1} } ) end it "will evaluates the regulation in the context of model being broadcast" do stub_const "TestModel1Policy", Class.new stub_const "Application", Class.new TestModel1Policy.class_eval do def public_attributes [:id] end regulate_broadcast do | policy | policy.send_all_but(:attr2).to(self) if attr2 == "YES" end end model = TestModel1.new(id: 1, attr1: 1, attr2: "YES", attr3: 3, attr4: 4, attr5: 5) expect { |b| HyperMesh::InternalPolicy.regulate_broadcast(model, &b) }.to yield_successive_args( { broadcast_id: :unique_broadcast_id, channel: 'TestModel1-1', channels: ['TestModel1-1'], klass: 'TestModel1', record: {id: 1, attr1: 1, attr3: 3, attr4: 4, attr5: 5}, previous_changes: {id: 1, attr1: 1, attr3: 3, attr4: 4, attr5: 5} } ) model = TestModel1.new(id: 1, attr1: 1, attr2: "NO", attr3: 3, attr4: 4, attr5: 5) expect { |b| HyperMesh::InternalPolicy.regulate_broadcast(model, &b) }.not_to yield_control end it "will adds the obj method to the policy which points back to the model being broadcast" do stub_const "TestModel1Policy", Class.new stub_const "Application", Class.new TestModel1Policy.class_eval do def send? obj.attr2 == "YES" end regulate_broadcast do | policy | policy.send_all_but(:attr2).to(self) if policy.send? end end model = TestModel1.new(id: 1, attr1: 1, attr2: "YES", attr3: 3, attr4: 4, attr5: 5) expect { |b| HyperMesh::InternalPolicy.regulate_broadcast(model, &b) }.to yield_successive_args( { broadcast_id: :unique_broadcast_id, channel: 'TestModel1-1', channels: ['TestModel1-1'], klass: 'TestModel1', record: {id: 1, attr1: 1, attr3: 3, attr4: 4, attr5: 5}, previous_changes: {id: 1, attr1: 1, attr3: 3, attr4: 4, attr5: 5} } ) model = TestModel1.new(id: 1, attr1: 1, attr2: "NO", attr3: 3, attr4: 4, attr5: 5) expect { |b| HyperMesh::InternalPolicy.regulate_broadcast(model, &b) }.not_to yield_control end it "will not broadcast an empty record" do stub_const "TestModel1Policy", Class.new stub_const "Application", Class.new TestModel1Policy.class_eval do def attributes_to_send [:attr1] if obj.attr2 == "YES" end regulate_broadcast do | policy | policy.send_only(*policy.attributes_to_send).to(self) end end model = TestModel1.new(id: 1, attr1: 1, attr2: "YES", attr3: 3, attr4: 4, attr5: 5) expect { |b| HyperMesh::InternalPolicy.regulate_broadcast(model, &b) }.to yield_successive_args( { broadcast_id: :unique_broadcast_id, channel: 'TestModel1-1', channels: ['TestModel1-1'], klass: 'TestModel1', record: {id: 1, attr1: 1}, previous_changes: {id: 1, attr1: 1} } ) model = TestModel1.new(id: 1, attr1: 1, attr2: "NO", attr3: 3, attr4: 4, attr5: 5) expect { |b| HyperMesh::InternalPolicy.regulate_broadcast(model, &b) }.not_to yield_control end it "will apply the same policy to several models" do stub_const "ApplicationPolicy", Class.new ApplicationPolicy.class_eval do regulate_broadcast(TestModel1, TestModel2) do |policy| policy.send_all_but(:attr1).to(self) end end model1 = TestModel1.new(id: 7, attr1: 1) model2 = TestModel2.new(id: 8, attrA: 1) expect { |b| HyperMesh::InternalPolicy.regulate_broadcast(model1, &b) }.to yield_successive_args( { broadcast_id: :unique_broadcast_id, channel: 'TestModel1-7', channels: ['TestModel1-7'], klass: 'TestModel1', record: {id: 7}, previous_changes: {id: 7} } ) expect { |b| HyperMesh::InternalPolicy.regulate_broadcast(model2, &b) }.to yield_successive_args( { broadcast_id: :unique_broadcast_id, channel: 'TestModel2-8', channels: ['TestModel2-8'], klass: 'TestModel2', record: {id: 8, attrA: 1}, previous_changes: {id: 8, attrA: 1} } ) end it "exposes the policy methods on the synchromesh_internal_policy_object" do stub_const "TestModel1Policy", Class.new stub_const "Application", Class.new TestModel1Policy.class_eval do regulate_broadcast do | policy | case policy.synchromesh_internal_policy_object.obj.attr1 when "send_all" policy.synchromesh_internal_policy_object.send_all.to(self) when "send_all_but" policy.synchromesh_internal_policy_object.send_all_but(:attr2).to(self) when "send_only" policy.synchromesh_internal_policy_object.send_only(:attr2).to(self) end end end model = TestModel1.new(id: 1, attr1: "send_all", attr2: "YES", attr3: 3, attr4: 4, attr5: 5) expect { |b| HyperMesh::InternalPolicy.regulate_broadcast(model, &b) }.to yield_successive_args( { broadcast_id: :unique_broadcast_id, channel: 'TestModel1-1', channels: ['TestModel1-1'], klass: 'TestModel1', record: {id: 1, attr1: "send_all", attr2: "YES", attr3: 3, attr4: 4, attr5: 5}, previous_changes: {id: 1, attr1: "send_all", attr2: "YES", attr3: 3, attr4: 4, attr5: 5} } ) model = TestModel1.new(id: 1, attr1: "send_all_but", attr2: "YES", attr3: 3, attr4: 4, attr5: 5) expect { |b| HyperMesh::InternalPolicy.regulate_broadcast(model, &b) }.to yield_successive_args( { broadcast_id: :unique_broadcast_id, channel: 'TestModel1-1', channels: ['TestModel1-1'], klass: 'TestModel1', record: {id: 1, attr1: "send_all_but", attr3: 3, attr4: 4, attr5: 5}, previous_changes: {id: 1, attr1: "send_all_but", attr3: 3, attr4: 4, attr5: 5} } ) model = TestModel1.new(id: 1, attr1: "send_only", attr2: "YES", attr3: 3, attr4: 4, attr5: 5) expect { |b| HyperMesh::InternalPolicy.regulate_broadcast(model, &b) }.to yield_successive_args( { broadcast_id: :unique_broadcast_id, channel: 'TestModel1-1', channels: ['TestModel1-1'], klass: 'TestModel1', record: {id: 1, attr2: "YES"}, previous_changes: {id: 1, attr2: "YES"} } ) end end