main
 1# frozen_string_literal: true
 2
 3RSpec.describe Saml::Kit::XsdValidatable do
 4  let(:metadata_xml) do
 5    Saml::Kit::IdentityProviderMetadata.build do |x|
 6      x.entity_id = 'https://idp.example.com/metadata'
 7      x.add_single_sign_on_service(
 8        'https://idp.example.com/login', binding: :http_post
 9      )
10    end.to_xml
11  end
12
13  let(:request_xml) do
14    Saml::Kit::AuthenticationRequest.build do |x|
15      x.issuer = 'https://sp.example.com/metadata'
16    end.to_xml
17  end
18
19  describe 'concurrent validation' do
20    # Compiling the schema inside Dir.chdir mutated process global state, and
21    # ruby raises when one thread enters a chdir block while another is inside
22    # one, so this raised "conflicting chdir during another chdir block".
23    it 'does not raise when many threads validate at once' do
24      threads = 8.times.map do
25        Thread.new do
26          20.times do
27            Saml::Kit::IdentityProviderMetadata.new(metadata_xml).valid?
28            Saml::Kit::AuthenticationRequest.new(request_xml).valid?
29          end
30        end
31      end
32      expect { threads.each(&:value) }.not_to raise_error
33    end
34
35    it 'reports the same result in every thread' do
36      threads = 8.times.map do
37        Thread.new { Saml::Kit::IdentityProviderMetadata.new(metadata_xml).valid? }
38      end
39      expect(threads.map(&:value).uniq).to eql([true])
40    end
41  end
42
43  describe 'schema resolution' do
44    # Our xsds import each other by relative filename, so this fails if they
45    # ever resolve against the working directory instead of the xsd's own.
46    it 'validates from an unrelated working directory' do
47      Dir.chdir('/') do
48        expect(Saml::Kit::IdentityProviderMetadata.new(metadata_xml)).to be_valid
49      end
50    end
51  end
52
53  describe 'schema compilation' do
54    around do |example|
55      cached = described_class.instance_variable_get(:@schemas)
56      described_class.instance_variable_set(:@schemas, {})
57      example.run
58      described_class.instance_variable_set(:@schemas, cached)
59    end
60
61    it 'compiles a schema once however often it is validated' do
62      allow(Nokogiri::XML::Schema).to receive(:from_document).and_call_original
63      3.times { Saml::Kit::IdentityProviderMetadata.new(metadata_xml).valid? }
64      expect(Nokogiri::XML::Schema).to have_received(:from_document).once
65    end
66  end
67end