require 'spec_helper' describe RightSupport::Rack::RequestTracker do let(:app) { flexmock('next middleware or rack app') } let(:generator) { described_class::Generator } let(:generated_request_uuid) { 'generated-uuid' } let(:request_uuid) { 'given-uuid' } subject { described_class.new(app) } context :call do context 'when ID is missing from request headers' do it 'generates a new request ID and responds as UUID for legacy reasons' do flexmock(generator). should_receive(:generate). and_return(generated_request_uuid). once original_env = {} expected_env = original_env.merge(described_class::REQUEST_UUID_ENV_NAME => generated_request_uuid) app.should_receive(:call).with(expected_env).and_return([200, {}, 'body']).once actual = subject.call(original_env) expected_headers = { described_class::REQUEST_UUID_HEADER => generated_request_uuid } actual[1].should == expected_headers end end context 'when ID sent with request' do it 'passes incoming request ID and responds as ID' do flexmock(generator).should_receive(:generate).never original_env = { described_class::HTTP_REQUEST_ID_HEADER => request_uuid } expected_env = original_env.merge(described_class::REQUEST_UUID_ENV_NAME => request_uuid) app.should_receive(:call).with(expected_env).and_return([200, {}, 'body']).once actual = subject.call(original_env) expected_headers = { described_class::REQUEST_ID_HEADER => request_uuid } actual[1].should == expected_headers end end context 'when UUID sent with request' do it 'passes incoming request UUID and responds as UUID' do flexmock(generator).should_receive(:generate).never original_env = { described_class::HTTP_REQUEST_UUID_HEADER => request_uuid } expected_env = original_env.merge(described_class::REQUEST_UUID_ENV_NAME => request_uuid) app.should_receive(:call).with(expected_env).and_return([200, {}, 'body']).once actual = subject.call(original_env) expected_headers = { described_class::REQUEST_UUID_HEADER => request_uuid } actual[1].should == expected_headers end end context 'when lineage sent with request' do it 'passes all UUIDs in header under length limit' do uuids = [] 3.times do uuids << ::RightSupport::Data::UUID.generate end lineage_uuid = uuids.join(described_class::UUID_SEPARATOR) flexmock(generator).should_receive(:generate).never original_env = { described_class::REQUEST_LINEAGE_UUID_HEADER => lineage_uuid } expected_env = original_env.merge(described_class::REQUEST_UUID_ENV_NAME => lineage_uuid) app.should_receive(:call).with(expected_env).and_return([200, {}, 'body']).once actual = subject.call(original_env) expected_headers = { described_class::REQUEST_UUID_HEADER => lineage_uuid } actual[1].should == expected_headers end end context 'when sent ID exceeds length limit' do it 'passes truncated request ID' do flexmock(generator).should_receive(:generate).never too_long_id = 'x' * 1024 truncated_id = 'x' * described_class::MAX_REQUEST_UUID_LENGTH original_env = { described_class::HTTP_REQUEST_ID_HEADER => too_long_id } expected_env = original_env.merge(described_class::REQUEST_UUID_ENV_NAME => truncated_id) app.should_receive(:call).with(expected_env).and_return([200, {}, 'body']).once actual = subject.call(original_env) expected_headers = { described_class::REQUEST_ID_HEADER => truncated_id } actual[1].should == expected_headers end end end context :copy_request_uuid do it 'does nothing when request UUID is missing' do described_class.copy_request_uuid(nil, nil).should be_empty end it 'copies request UUID to target hash when present' do env = { described_class::REQUEST_UUID_ENV_NAME => request_uuid, 'other' => 'stuff' } other_headers = { 'Foo' => 'bar' } expected = { described_class::REQUEST_ID_HEADER => request_uuid }.merge(other_headers) actual = described_class.copy_request_uuid(env, other_headers) actual.should == expected end end end