<commit_before>require_relative "spec_helper"

describe Alephant::Broker::Application do
  include Rack::Test::Methods
  let(:options) do
    {
      :lookup_table_name => "test_table",
      :bucket_id         => "test_bucket",
      :path              => "bucket_path"
    }
  end

  let(:app) do
    described_class.new(
      Alephant::Broker::LoadStrategy::S3::Sequenced.new,
      options
    )
  end
  let(:content) do
    AWS::Core::Data.new(
      :content_type => "test/content",
      :content      => "Test",
      :meta         => {
        "head_ETag" => "123",
        "head_Last-Modified" => "Mon, 11 Apr 2016 10:39:57 GMT"
      }
    )
  end
  let(:sequencer_double) do
    instance_double(
      "Alephant::Sequencer::Sequencer",
      :get_last_seen => "111"
    )
  end

  let(:lookup_location_double) do
    instance_double("Alephant::Lookup::Location", :location => "test/location")
  end
  let(:lookup_helper_double) do
    instance_double(
      "Alephant::Lookup::LookupHelper",
      :read => lookup_location_double
    )
  end

  let(:s3_double) { instance_double("Alephant::Storage", :get => content) }

  before do
    allow_any_instance_of(Logger).to receive(:info)
    allow_any_instance_of(Logger).to receive(:debug)
    allow(Alephant::Lookup).to receive(:create) { lookup_helper_double }
    allow(Alephant::Sequencer).to receive(:create) { sequencer_double }
  end

  describe "Status endpoint `/status`" do
    before { get "/status" }
    specify { expect(last_response.status).to eql 200 }
    specify { expect(last_response.body).to eql "ok" }
  end

  describe "404 endpoint `/banana`" do
    before { get "/banana" }
    specify { expect(last_response.status).to eql 404 }
    specify { expect(last_response.body).to eq "Not found" }
    specify { expect(last_response.headers).to include("Cache-Control") }
    specify { expect(last_response.headers).to include("Pragma") }
    specify { expect(last_response.headers).to include("Expires") }
  end

  describe "Component endpoint '/component/...'" do
    before do
      allow(Alephant::Storage).to receive(:new) { s3_double }
      get "/component/test_component"
    end

    context "for a valid component ID" do
      specify { expect(last_response.status).to eql 200 }
      specify { expect(last_response.body).to eql "Test" }
      specify { expect(last_response.headers).to_not include("Cache-Control") }
      specify { expect(last_response.headers).to_not include("Pragma") }
      specify { expect(last_response.headers).to_not include("Expires") }
      specify { expect(last_response.headers["ETag"]).to eq("123") }
      specify { expect(last_response.headers["Last-Modified"]).to eq("Mon, 11 Apr 2016 10:39:57 GMT") }
    end

    context "for valid URL parameters in request" do
      before { get "/component/test_component?variant=test_variant" }
      specify { expect(last_response.status).to eq 200 }
      specify { expect(last_response.body).to eq "Test" }
    end
  end

  describe "Components endpoint '/components'" do
    let(:fixture_path) { "#{File.dirname(__FILE__)}/../fixtures/json" }
    let(:batch_json) do
      IO.read("#{fixture_path}/batch.json").strip
    end
    let(:batch_compiled_json) do
      IO.read("#{fixture_path}/batch_compiled.json").strip
    end

    before do
      allow(Alephant::Storage).to receive(:new) { s3_double }
    end

    context "when using valid batch asset data" do
      let(:path) { "/components/batch" }
      let(:content_type) { "application/json" }
      before { post path, batch_json, "CONTENT_TYPE" => content_type }

      specify { expect(last_response.status).to eql 200 }
      specify { expect(last_response.body).to eq batch_compiled_json }
      specify {
        expect(last_response.headers).to eq({
          "Content-Type"   => "application/json",
          "ETag"           => "685f7ccf4a31c7c150d396df1baa3de7",
          "Last-Modified"  => "Mon, 11 Apr 2016 10:39:57 GMT",
          "Content-Length" => "266"
        })
      }
    end
  end

  describe "S3 headers" do
    let(:content) do
      AWS::Core::Data.new(
        :content => "missing_content",
        :meta    => {}
      )
    end
    let(:s3_double) do
      instance_double(
        "Alephant::Storage",
        :get => content
      )
    end

    context "with 404 status code set" do
      before do
        content[:meta]["status"] = 404
        allow(Alephant::Storage).to receive(:new) { s3_double }
        get "/component/test_component"
      end
<commit_msg>Add spec for ETag and Last-Modified headers<commit_after>require_relative "spec_helper"

describe Alephant::Broker::Application do
  include Rack::Test::Methods
  let(:options) do
    {
      :lookup_table_name => "test_table",
      :bucket_id         => "test_bucket",
      :path              => "bucket_path"
    }
  end

  let(:app) do
    described_class.new(
      Alephant::Broker::LoadStrategy::S3::Sequenced.new,
      options
    )
  end
  let(:content) do
    AWS::Core::Data.new(
      :content_type => "test/content",
      :content      => "Test",
      :meta         => {
        "head_ETag" => "123",
        "head_Last-Modified" => "Mon, 11 Apr 2016 10:39:57 GMT"
      }
    )
  end
  let(:sequencer_double) do
    instance_double(
      "Alephant::Sequencer::Sequencer",
      :get_last_seen => "111"
    )
  end

  let(:lookup_location_double) do
    instance_double("Alephant::Lookup::Location", :location => "test/location")
  end
  let(:lookup_helper_double) do
    instance_double(
      "Alephant::Lookup::LookupHelper",
      :read => lookup_location_double
    )
  end

  let(:s3_double) { instance_double("Alephant::Storage", :get => content) }

  before do
    allow_any_instance_of(Logger).to receive(:info)
    allow_any_instance_of(Logger).to receive(:debug)
    allow(Alephant::Lookup).to receive(:create) { lookup_helper_double }
    allow(Alephant::Sequencer).to receive(:create) { sequencer_double }
  end

  describe "Status endpoint `/status`" do
    before { get "/status" }
    specify { expect(last_response.status).to eql 200 }
    specify { expect(last_response.body).to eql "ok" }
  end

  describe "404 endpoint `/banana`" do
    before { get "/banana" }
    specify { expect(last_response.status).to eql 404 }
    specify { expect(last_response.body).to eq "Not found" }
    specify { expect(last_response.headers).to include("Cache-Control") }
    specify { expect(last_response.headers).to include("Pragma") }
    specify { expect(last_response.headers).to include("Expires") }
  end

  describe "Component endpoint '/component/...'" do
    before do
      allow(Alephant::Storage).to receive(:new) { s3_double }
      get "/component/test_component"
    end

    context "for a valid component ID" do
      specify { expect(last_response.status).to eql 200 }
      specify { expect(last_response.body).to eql "Test" }
      specify { expect(last_response.headers).to_not include("Cache-Control") }
      specify { expect(last_response.headers).to_not include("Pragma") }
      specify { expect(last_response.headers).to_not include("Expires") }
      specify { expect(last_response.headers["ETag"]).to eq("123") }
      specify { expect(last_response.headers["Last-Modified"]).to eq("Mon, 11 Apr 2016 10:39:57 GMT") }
    end

    context "for valid URL parameters in request" do
      before { get "/component/test_component?variant=test_variant" }
      specify { expect(last_response.status).to eq 200 }
      specify { expect(last_response.body).to eq "Test" }
    end
  end

  describe "Components endpoint '/components'" do
    let(:fixture_path) { "#{File.dirname(__FILE__)}/../fixtures/json" }
    let(:batch_json) do
      IO.read("#{fixture_path}/batch.json").strip
    end
    let(:batch_compiled_json) do
      IO.read("#{fixture_path}/batch_compiled.json").strip
    end

    before do
      allow(s3_double).to receive(:get).and_return(
        content,
        AWS::Core::Data.new(
          :content_type => "test/content",
          :content      => "Test",
          :meta         => {
            "head_ETag" => "abc",
            "head_Last-Modified" => "Mon, 11 Apr 2016 09:39:57 GMT"
          }
        )
      )

      allow(Alephant::Storage).to receive(:new) { s3_double }
    end

    context "when using valid batch asset data" do
      let(:path) { "/components/batch" }
      let(:content_type) { "application/json" }

      before { post path, batch_json, "CONTENT_TYPE" => content_type }

      specify { expect(last_response.status).to eql 200 }
      specify { expect(last_response.body).to eq batch_compiled_json }
      specify {
        expect(last_response.headers).to eq({
          "Content-Type"   => "application/json",
          "ETag"           => "34774567db979628363e6e865127623f",
          "Last-Modified"  => "Mon, 11 Apr 2016 10:39:57 GMT",
          "Content-Length" => "266"
        })
      }
    end
  end

  describe "S3 headers" do
    let(:content) do
      AWS::Core::Data.new(
        :content => "missing_content",
        :meta    => {}
      )
    end
    let(:s3_double) do
      instance_double(
        "Alephant::Storage",
        :get => content
      )
    end

    context "with 404 status code set" do
      before do
        content[:meta]["status"] = 404
        allow(Alephant::Storage).to receive(:new) { s3_double }
        get "/component/test_component"
      end

{'fraction_non_alphanumeric': 0.13353872304260067, 'fraction_numerical': 0.022840752151280144, 'mean_word_length': 2.8471597874948915, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 48, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3925367', 'n_tokens_mistral': 3132, 'n_tokens_neox': 2955, 'n_words': 606}