RSpec.shared_examples_for 'Metasploit::Credential::CoreValidations' do # # Context Methods # # Returns correlation with the given `name` from options. # # @param options [Hash{Symbol => :different, :same}] # @param name [Symbol] name of correlation option in `options`. # @return [:different, :same] # @raise [ArgumentError] if `options[name]` is not `:different` or `:same` # @raise [KeyError] if `options` does not contain key `name` def self.correlation!(options, name) correlation = options.fetch(name) unless [:different, :same].include? correlation raise ArgumentError, "#{name} must be :different or :same" end correlation end # Declares a `context` with correlation on `name` and body of `block` # # @param options [Hash{Symbol => :different, :same}] # @param name [Symbol] name of correlation option in `options`. # @yield Block that functions as body of `context` # @return [void] # @raise (see correlation!) def self.context_with_correlation(options, name, &block) correlation = correlation!(options, name) context "with #{correlation} #{name}" do if correlation == :same let("second_#{name}") { send("first_#{name}") } end instance_eval(&block) end end # # Shared Contexts # shared_context 'two metasploit_credential_cores' do # # lets # let(:first_workspace) { FactoryGirl.create(:mdm_workspace) } let(:origin) { # use an origin where the workspace does not need to correlate FactoryGirl.create(:metasploit_credential_origin_manual) } let(:factory_name) { :metasploit_credential_core } let(:first_factory_options) { { origin: origin, private: first_private, public: first_public, realm: first_realm, workspace: first_workspace } } let(:second_factory_options) { { origin: origin, private: second_private, public: second_public, realm: second_realm, workspace: second_workspace } } let(:second_metasploit_credential_core) { FactoryGirl.build( factory_name, second_factory_options) } # # let!s # let!(:first_metasploit_credential_core) { FactoryGirl.create(factory_name, first_factory_options) } end context 'database' do context 'indices' do context 'foreign keys' do let(:first_private) { FactoryGirl.create(:metasploit_credential_private) } let(:second_public) { FactoryGirl.create(:metasploit_credential_username) } let(:second_private) { FactoryGirl.create(:metasploit_credential_private) } let(:second_realm) { FactoryGirl.create(:metasploit_credential_realm) } let(:second_workspace) { FactoryGirl.create(:mdm_workspace) } shared_examples_for 'potential collision' do |options={}| options.assert_valid_keys(:collision, :index) if options.fetch(:collision) it 'raises ActiveRecord::RecordNotUnique' do expect { second_metasploit_credential_core.save(validate: false) }.to raise_error(ActiveRecord::RecordNotUnique) { |error| expect(error.message).to include( "duplicate key value violates unique constraint \"#{options.fetch(:index)}\"" ) } end else it 'does not raise ActiveRecord::RecordNotUnique' do expect { second_metasploit_credential_core.save(validate: false) }.not_to raise_error end end end shared_examples_for 'unique_private_metasploit_credential_cores' do |options={}| include_context 'two metasploit_credential_cores' options.assert_valid_keys(:collision, :private, :workspace) # # lets # let(:first_public) { nil } let(:first_realm) { nil } let(:second_public) { nil } let(:second_realm) { nil } context_with_correlation(options, :workspace) do context_with_correlation(options, :private) do it_should_behave_like 'potential collision', collision: options.fetch(:collision), index: 'unique_private_metasploit_credential_cores' end end end shared_examples_for 'unique_public_metasploit_credential_cores' do |options={}| include_context 'two metasploit_credential_cores' options.assert_valid_keys(:collision, :public, :workspace) # # lets # let(:first_private) { nil } let(:first_public) { FactoryGirl.create(:metasploit_credential_username) } let(:first_realm) { nil } let(:second_private) { nil } let(:second_realm) { nil } context_with_correlation(options, :workspace) do context_with_correlation(options, :public) do it_should_behave_like 'potential collision', collision: options.fetch(:collision), index: 'unique_public_metasploit_credential_cores' end end end shared_examples_for 'unique_realmless_metasploit_credential_cores' do |options={}| include_context 'two metasploit_credential_cores' options.assert_valid_keys(:collision, :private, :public, :workspace) let(:first_public) { FactoryGirl.create(:metasploit_credential_username) } let(:first_realm) { nil } let(:second_realm) { nil } context_with_correlation(options, :workspace) do context_with_correlation(options, :public) do context_with_correlation(options, :private) do it_should_behave_like 'potential collision', collision: options.fetch(:collision), index: 'unique_realmless_metasploit_credential_cores' end end end end shared_examples_for 'unique_publicless_metasploit_credential_cores' do |options={}| include_context 'two metasploit_credential_cores' options.assert_valid_keys(:collision, :private, :realm, :workspace) let(:first_public) { nil } let(:first_realm) { FactoryGirl.create(:metasploit_credential_realm) } let(:second_public) { nil } context_with_correlation(options, :workspace) do context_with_correlation(options, :realm) do context_with_correlation(options, :private) do it_should_behave_like 'potential collision', collision: options.fetch(:collision), index: 'unique_publicless_metasploit_credential_cores' end end end end shared_examples_for 'unique_privateless_metasploit_credential_cores' do |options={}| include_context 'two metasploit_credential_cores' options.assert_valid_keys(:collision, :public, :realm, :workspace) let(:first_private) { nil } let(:first_public) { FactoryGirl.create(:metasploit_credential_username) } let(:first_realm) { FactoryGirl.create(:metasploit_credential_realm) } let(:second_private) { nil } context_with_correlation(options, :workspace) do context_with_correlation(options, :realm) do context_with_correlation(options, :public) do it_should_behave_like 'potential collision', collision: options.fetch(:collision), index: 'unique_privateless_metasploit_credential_cores' end end end end shared_examples_for 'unique_complete_metasploit_credential_cores' do |options={}| include_context 'two metasploit_credential_cores' options.assert_valid_keys(:collision, :private, :public, :realm, :workspace) let(:first_public) { FactoryGirl.create(:metasploit_credential_username) } let(:first_realm) { FactoryGirl.create(:metasploit_credential_realm) } context_with_correlation(options, :workspace) do context_with_correlation(options, :realm) do context_with_correlation(options, :public) do context_with_correlation(options, :private) do it_should_behave_like 'potential collision', collision: options.fetch(:collision), index: 'unique_complete_metasploit_credential_cores' end end end end end it_should_behave_like 'unique_private_metasploit_credential_cores', workspace: :same, private: :same, collision: true it_should_behave_like 'unique_private_metasploit_credential_cores', workspace: :same, private: :different, collision: false it_should_behave_like 'unique_private_metasploit_credential_cores', workspace: :different, private: :same, collision: false it_should_behave_like 'unique_private_metasploit_credential_cores', workspace: :different, private: :different, collision: false it_should_behave_like 'unique_public_metasploit_credential_cores', workspace: :same, public: :same, collision: true it_should_behave_like 'unique_public_metasploit_credential_cores', workspace: :same, public: :different, collision: false it_should_behave_like 'unique_public_metasploit_credential_cores', workspace: :different, public: :same, collision: false it_should_behave_like 'unique_public_metasploit_credential_cores', workspace: :different, public: :different, collision: false it_should_behave_like 'unique_realmless_metasploit_credential_cores', workspace: :same, public: :same, private: :same, collision: true it_should_behave_like 'unique_realmless_metasploit_credential_cores', workspace: :same, public: :same, private: :different, collision: false it_should_behave_like 'unique_realmless_metasploit_credential_cores', workspace: :same, public: :different, private: :same, collision: false it_should_behave_like 'unique_realmless_metasploit_credential_cores', workspace: :same, public: :different, private: :different, collision: false it_should_behave_like 'unique_realmless_metasploit_credential_cores', workspace: :different, public: :same, private: :same, collision: false it_should_behave_like 'unique_realmless_metasploit_credential_cores', workspace: :different, public: :same, private: :different, collision: false it_should_behave_like 'unique_realmless_metasploit_credential_cores', workspace: :different, public: :different, private: :same, collision: false it_should_behave_like 'unique_realmless_metasploit_credential_cores', workspace: :different, public: :different, private: :different, collision: false it_should_behave_like 'unique_publicless_metasploit_credential_cores', workspace: :same, realm: :same, private: :same, collision: true it_should_behave_like 'unique_publicless_metasploit_credential_cores', workspace: :same, realm: :same, private: :different, collision: false it_should_behave_like 'unique_publicless_metasploit_credential_cores', workspace: :same, realm: :different, private: :same, collision: false it_should_behave_like 'unique_publicless_metasploit_credential_cores', workspace: :same, realm: :different, private: :different, collision: false it_should_behave_like 'unique_publicless_metasploit_credential_cores', workspace: :different, realm: :same, private: :same, collision: false it_should_behave_like 'unique_publicless_metasploit_credential_cores', workspace: :different, realm: :same, private: :different, collision: false it_should_behave_like 'unique_publicless_metasploit_credential_cores', workspace: :different, realm: :different, private: :same, collision: false it_should_behave_like 'unique_publicless_metasploit_credential_cores', workspace: :different, realm: :different, private: :different, collision: false it_should_behave_like 'unique_privateless_metasploit_credential_cores', workspace: :same, realm: :same, public: :same, collision: true it_should_behave_like 'unique_privateless_metasploit_credential_cores', workspace: :same, realm: :same, public: :different, collision: false it_should_behave_like 'unique_privateless_metasploit_credential_cores', workspace: :same, realm: :different, public: :same, collision: false it_should_behave_like 'unique_privateless_metasploit_credential_cores', workspace: :same, realm: :different, public: :different, collision: false it_should_behave_like 'unique_privateless_metasploit_credential_cores', workspace: :different, realm: :same, public: :same, collision: false it_should_behave_like 'unique_privateless_metasploit_credential_cores', workspace: :different, realm: :same, public: :different, collision: false it_should_behave_like 'unique_privateless_metasploit_credential_cores', workspace: :different, realm: :different, public: :same, collision: false it_should_behave_like 'unique_privateless_metasploit_credential_cores', workspace: :different, realm: :different, public: :different, collision: false it_should_behave_like 'unique_complete_metasploit_credential_cores', workspace: :same, realm: :same, public: :same, private: :same, collision: true it_should_behave_like 'unique_complete_metasploit_credential_cores', workspace: :same, realm: :same, public: :same, private: :different, collision: false it_should_behave_like 'unique_complete_metasploit_credential_cores', workspace: :same, realm: :same, public: :different, private: :same, collision: false it_should_behave_like 'unique_complete_metasploit_credential_cores', workspace: :same, realm: :same, public: :different, private: :different, collision: false it_should_behave_like 'unique_complete_metasploit_credential_cores', workspace: :same, realm: :different, public: :same, private: :same, collision: false it_should_behave_like 'unique_complete_metasploit_credential_cores', workspace: :same, realm: :different, public: :same, private: :different, collision: false it_should_behave_like 'unique_complete_metasploit_credential_cores', workspace: :same, realm: :different, public: :different, private: :same, collision: false it_should_behave_like 'unique_complete_metasploit_credential_cores', workspace: :same, realm: :different, public: :different, private: :different, collision: false it_should_behave_like 'unique_complete_metasploit_credential_cores', workspace: :different, realm: :same, public: :same, private: :same, collision: false it_should_behave_like 'unique_complete_metasploit_credential_cores', workspace: :different, realm: :same, public: :same, private: :different, collision: false it_should_behave_like 'unique_complete_metasploit_credential_cores', workspace: :different, realm: :same, public: :different, private: :same, collision: false it_should_behave_like 'unique_complete_metasploit_credential_cores', workspace: :different, realm: :same, public: :different, private: :different, collision: false it_should_behave_like 'unique_complete_metasploit_credential_cores', workspace: :different, realm: :different, public: :same, private: :same, collision: false it_should_behave_like 'unique_complete_metasploit_credential_cores', workspace: :different, realm: :different, public: :same, private: :different, collision: false it_should_behave_like 'unique_complete_metasploit_credential_cores', workspace: :different, realm: :different, public: :different, private: :same, collision: false it_should_behave_like 'unique_complete_metasploit_credential_cores', workspace: :different, realm: :different, public: :different, private: :different, collision: false end end context 'validations' do it { is_expected.to validate_presence_of :workspace } context 'of uniqueness' do let(:first_private) { FactoryGirl.create(:metasploit_credential_private) } let(:second_public) { FactoryGirl.create(:metasploit_credential_username) } let(:second_private) { FactoryGirl.create(:metasploit_credential_private) } let(:second_realm) { FactoryGirl.create(:metasploit_credential_realm) } let(:second_workspace) { FactoryGirl.create(:mdm_workspace) } shared_examples_for 'potential collision' do |options={}| options.assert_valid_keys(:attribute, :collision, :message) subject { second_metasploit_credential_core } # # Callbacks # if options.fetch(:collision) it 'add validation error' do second_metasploit_credential_core.valid? expect( second_metasploit_credential_core.errors[options.fetch(:attribute)] ).to include options.fetch(:message) end else it { is_expected.to be_valid } end end shared_examples_for 'on (workspace_id, realm_id, public_id, private_id) without realm_id without public_id' do |options={}| include_context 'two metasploit_credential_cores' options.assert_valid_keys(:collision, :private, :workspace) # # lets # let(:first_public) { nil } let(:first_realm) { nil } let(:second_public) { nil } let(:second_realm) { nil } context_with_correlation(options, :workspace) do context_with_correlation(options, :private) do it_should_behave_like 'potential collision', attribute: :private_id, collision: options.fetch(:collision), message: 'is already taken for credential cores with only a private credential' end end end shared_examples_for 'on (workspace_id, realm_id, private_id, public_id) without realm_id without private_id' do |options={}| include_context 'two metasploit_credential_cores' options.assert_valid_keys(:collision, :public, :workspace) # # lets # let(:first_private) { nil } let(:first_public) { FactoryGirl.create(:metasploit_credential_username) } let(:first_realm) { nil } let(:second_private) { nil } let(:second_realm) { nil } context_with_correlation(options, :workspace) do context_with_correlation(options, :public) do it_should_behave_like 'potential collision', attribute: :public_id, collision: options.fetch(:collision), message: 'is already taken for credential cores with only a public credential' end end end shared_examples_for 'on (workspace_id, realm_id, public_id, private_id) without realm_id' do |options={}| include_context 'two metasploit_credential_cores' options.assert_valid_keys(:collision, :private, :public, :workspace) let(:first_realm) { nil } let(:first_public) { FactoryGirl.create(:metasploit_credential_username) } let(:second_realm) { nil } context_with_correlation(options, :workspace) do context_with_correlation(options, :public) do context_with_correlation(options, :private) do it_should_behave_like 'potential collision', attribute: :private_id, collision: options.fetch(:collision), message: 'is already taken for credential cores without a credential realm' end end end end shared_examples_for 'on (workspace_id, realm_id, public_, private_id) without public_id' do |options={}| include_context 'two metasploit_credential_cores' options.assert_valid_keys(:collision, :private, :realm, :workspace) let(:first_public) { nil } let(:first_realm) { FactoryGirl.create(:metasploit_credential_realm) } let(:second_public) { nil } context_with_correlation(options, :workspace) do context_with_correlation(options, :realm) do context_with_correlation(options, :private) do it_should_behave_like 'potential collision', attribute: :private_id, collision: options.fetch(:collision), message: 'is already taken for credential cores without a public credential' end end end end shared_examples_for 'on (workspace_id, realm_id, public_id, private_id) without private_id' do |options={}| include_context 'two metasploit_credential_cores' options.assert_valid_keys(:collision, :public, :realm, :workspace) let(:first_private) { nil } let(:first_public) { FactoryGirl.create(:metasploit_credential_username) } let(:first_realm) { FactoryGirl.create(:metasploit_credential_realm) } let(:second_private) { nil } context_with_correlation(options, :workspace) do context_with_correlation(options, :realm) do context_with_correlation(options, :public) do it_should_behave_like 'potential collision', attribute: :public_id, collision: options.fetch(:collision), message: 'is already taken for credential cores without a private credential' end end end end shared_examples 'on (workspace_id, realm_id, public_id, private_id)' do |options={}| include_context 'two metasploit_credential_cores' options.assert_valid_keys(:collision, :private, :public, :realm, :workspace) let(:first_public) { FactoryGirl.create(:metasploit_credential_username) } let(:first_realm) { FactoryGirl.create(:metasploit_credential_realm) } context_with_correlation(options, :workspace) do context_with_correlation(options, :realm) do context_with_correlation(options, :public) do context_with_correlation(options, :private) do it_should_behave_like 'potential collision', attribute: :private_id, collision: options.fetch(:collision), message: 'is already taken for complete credential cores' end end end end end # # Examples # it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id) without realm_id without public_id', workspace: :same, private: :same, collision: true it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id) without realm_id without public_id', workspace: :same, private: :different, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id) without realm_id without public_id', workspace: :different, private: :same, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id) without realm_id without public_id', workspace: :different, private: :different, collision: false it_should_behave_like 'on (workspace_id, realm_id, private_id, public_id) without realm_id without private_id', workspace: :same, public: :same, collision: true it_should_behave_like 'on (workspace_id, realm_id, private_id, public_id) without realm_id without private_id', workspace: :same, public: :different, collision: false it_should_behave_like 'on (workspace_id, realm_id, private_id, public_id) without realm_id without private_id', workspace: :different, public: :same, collision: false it_should_behave_like 'on (workspace_id, realm_id, private_id, public_id) without realm_id without private_id', workspace: :different, public: :different, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id) without realm_id', workspace: :same, public: :same, private: :same, collision: true it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id) without realm_id', workspace: :same, public: :same, private: :different, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id) without realm_id', workspace: :same, public: :different, private: :same, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id) without realm_id', workspace: :same, public: :different, private: :different, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id) without realm_id', workspace: :different, public: :same, private: :same, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id) without realm_id', workspace: :different, public: :same, private: :different, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id) without realm_id', workspace: :different, public: :different, private: :same, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id) without realm_id', workspace: :different, public: :different, private: :different, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_, private_id) without public_id', workspace: :same, realm: :same, private: :same, collision: true it_should_behave_like 'on (workspace_id, realm_id, public_, private_id) without public_id', workspace: :same, realm: :same, private: :different, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_, private_id) without public_id', workspace: :same, realm: :different, private: :same, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_, private_id) without public_id', workspace: :same, realm: :different, private: :different, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_, private_id) without public_id', workspace: :different, realm: :same, private: :same, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_, private_id) without public_id', workspace: :different, realm: :same, private: :different, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_, private_id) without public_id', workspace: :different, realm: :different, private: :same, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_, private_id) without public_id', workspace: :different, realm: :different, private: :different, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id) without private_id', workspace: :same, realm: :same, public: :same, collision: true it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id) without private_id', workspace: :same, realm: :same, public: :different, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id) without private_id', workspace: :same, realm: :different, public: :same, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id) without private_id', workspace: :same, realm: :different, public: :different, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id) without private_id', workspace: :different, realm: :same, public: :same, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id) without private_id', workspace: :different, realm: :same, public: :different, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id) without private_id', workspace: :different, realm: :different, public: :same, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id) without private_id', workspace: :different, realm: :different, public: :different, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id)', workspace: :same, realm: :same, private: :same, public: :same, collision: true it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id)', workspace: :same, realm: :same, private: :same, public: :different, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id)', workspace: :same, realm: :same, private: :different, public: :same, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id)', workspace: :same, realm: :same, private: :different, public: :different, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id)', workspace: :same, realm: :different, private: :same, public: :same, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id)', workspace: :same, realm: :different, private: :same, public: :different, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id)', workspace: :same, realm: :different, private: :different, public: :same, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id)', workspace: :same, realm: :different, private: :different, public: :different, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id)', workspace: :different, realm: :same, private: :same, public: :same, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id)', workspace: :different, realm: :same, private: :same, public: :different, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id)', workspace: :different, realm: :same, private: :different, public: :same, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id)', workspace: :different, realm: :same, private: :different, public: :different, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id)', workspace: :different, realm: :different, private: :same, public: :same, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id)', workspace: :different, realm: :different, private: :same, public: :different, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id)', workspace: :different, realm: :different, private: :different, public: :same, collision: false it_should_behave_like 'on (workspace_id, realm_id, public_id, private_id)', workspace: :different, realm: :different, private: :different, public: :different, collision: false # # Cross-uniqueness validation tests # context 'across validations' do include_context 'two metasploit_credential_cores' subject { second_metasploit_credential_core } let(:first_public) { FactoryGirl.create(:metasploit_credential_username) } let(:first_realm) { FactoryGirl.create(:metasploit_credential_realm) } let(:second_private) { first_private } let(:second_public) { first_public } let(:second_realm) { first_realm } let(:second_workspace) { first_workspace } context 'with workspace with realm with public with private' do context 'with same workspace without realm without public with same private' do let(:second_public) { nil } let(:second_realm) { nil } it { is_expected.to be_valid } end context 'with same workspace without realm with same public without private' do let(:second_private) { nil } let(:second_realm) { nil } it { is_expected.to be_valid } end context 'with same workspace with same realm without public with same private' do let(:second_public) { nil } it { is_expected.to be_valid } end context 'with same workspace with same realm with same public without private' do let(:second_private) { nil } let(:second_realm) { nil } it { is_expected.to be_valid } end end context 'with workspace without realm without public with private' do let(:first_public) { nil } let(:first_realm) { nil } context 'with same workspace without realm with public without private' do let(:second_public) { FactoryGirl.create(:metasploit_credential_public) } let(:second_private) { nil } it { is_expected.to be_valid } end context 'with same workspace without realm with public with same private' do let(:second_public) { FactoryGirl.create(:metasploit_credential_public) } it { is_expected.to be_valid } end context 'with same workspace with realm without public with same private' do let(:second_realm) { FactoryGirl.create(:metasploit_credential_realm) } it { is_expected.to be_valid } end end context 'with workspace without realm with public without private' do let(:first_private) { nil } let(:first_realm) { nil } context 'with workspace without realm with same public with private' do let(:second_private) { FactoryGirl.create(:metasploit_credential_private) } it { is_expected.to be_valid } end context 'with workspace with realm without public with private' do let(:second_private) { FactoryGirl.create(:metasploit_credential_private) } let(:second_realm) { FactoryGirl.create(:metasploit_credential_realm) } it { is_expected.to be_valid} end end context 'with workspace without realm with public with private' do let(:first_realm) { nil } context 'with same workspace with realm without public with same private' do let(:second_public) { nil } let(:second_realm) { FactoryGirl.create(:metasploit_credential_realm) } it { is_expected.to be_valid } end end context 'with workspace with realm without public with private' do let(:first_public) { nil } context 'with same workspace with same realm with public without private' do let(:second_private) { nil } let(:second_public) { FactoryGirl.create(:metasploit_credential_public) } it { is_expected.to be_valid } end end end end end end end