require 'spec_helper' module FirebaseIdToken describe Certificates do let (:redis) { Redis::Namespace.new 'firebase_id_token', redis: Redis.new } let (:certs) { File.read('spec/fixtures/files/certificates.json') } let (:cache) { 'public, max-age=19302, must-revalidate, no-transform' } let (:low_cache) { 'public, max-age=2160, must-revalidate, no-transform' } let (:kid) { JSON.parse(certs).first[0] } let (:expires_in) { (DateTime.now + (5/24r)).to_s } let (:response) { double } let (:mock_response) { allow(response).to receive(:code) { 200 } allow(response).to receive(:headers) { { 'cache-control' => cache } } allow(response).to receive(:body) { certs } } let(:mock_request) { mock_response allow(HTTParty).to receive(:get). with(an_instance_of(String)) { response } } before :each do redis.del 'certificates' mock_request end describe '#request' do it 'requests certificates when Redis database is empty' do expect(HTTParty).to receive(:get). with(FirebaseIdToken::Certificates::URL) described_class.request end it 'does not requests certificates when Redis database is written' do expect(HTTParty).to receive(:get). with(FirebaseIdToken::Certificates::URL).once 2.times { described_class.request } end end describe '#request!' do it 'always requests certificates' do expect(HTTParty).to receive(:get). with(FirebaseIdToken::Certificates::URL).twice 2.times { described_class.request! } end it 'sets the certificate expiration time as Redis TTL' do described_class.request! expect(redis.ttl('certificates')).to be > 3600 end it 'raises a error when certificates expires in less than 1 hour' do allow(response).to receive(:headers) {{'cache-control' => low_cache}} expect{ described_class.request! }. to raise_error(Exceptions::CertificatesTtlError) end it 'raises a error when HTTP response code is other than 200' do allow(response).to receive(:code) { 401 } expect{ described_class.request! }. to raise_error(Exceptions::CertificatesRequestError) end end describe '#request_anyway' do it 'also requests certificates' do expect(HTTParty).to receive(:get). with(FirebaseIdToken::Certificates::URL) described_class.request_anyway end end describe '.present?' do it 'returns false when Redis database is empty' do expect(described_class.present?).to be(false) end it 'returns true when Redis database is written' do described_class.request expect(described_class.present?).to be(true) end end describe '.all' do context 'before requesting certificates' do it 'returns a empty Array' do expect(described_class.all).to eq([]) end end context 'after requesting certificates' do it 'returns a array of hashes: String keys' do described_class.request expect(described_class.all.first.keys[0]).to be_a(String) end it 'returns a array of hashes: OpenSSL::X509::Certificate values' do described_class.request expect(described_class.all.first.values[0]). to be_a(OpenSSL::X509::Certificate) end end end describe '.find' do context 'without certificates in Redis database' do it 'raises a exception' do expect{ described_class.find(kid)}. to raise_error(Exceptions::NoCertificatesError) end end context 'with certificates in Redis database' do it 'returns a OpenSSL::X509::Certificate when it finds the kid' do described_class.request expect(described_class.find(kid)).to be_a(OpenSSL::X509::Certificate) end it 'returns nil when it can not find the kid' do described_class.request expect(described_class.find('')).to be(nil) end end end describe '.find!' do context 'without certificates in Redis database' do it 'raises a exception' do expect{ described_class.find!(kid)}. to raise_error(Exceptions::NoCertificatesError) end end context 'with certificates in Redis database' do it 'returns a OpenSSL::X509::Certificate when it finds the kid' do described_class.request expect(described_class.find!(kid)).to be_a(OpenSSL::X509::Certificate) end it 'raises a CertificateNotFound error when it can not find the kid' do described_class.request expect { described_class.find!('') } .to raise_error(Exceptions::CertificateNotFound, /Unable to find/) end end end describe '.ttl' do it 'returns a positive number when has certificates in Redis' do described_class.request expect(described_class.ttl).to be > 0 end it 'returns zero when has no certificates in Redis' do expect(described_class.ttl).to eq(0) end end end end