<commit_before>require 'securerandom'
require 'helper'
require 'flipper/cloud'
require 'flipper/cloud/middleware'
require 'flipper/adapters/operation_logger'

RSpec.describe Flipper::Cloud::Middleware do
  let(:flipper) {
    Flipper::Cloud.new("regular") do |config|
      config.local_adapter = Flipper::Adapters::OperationLogger.new(Flipper::Adapters::Memory.new)
      config.sync_secret = "regular_tasty"
      config.sync_method = :webhook
    end
  }

  let(:env_flipper) {
    Flipper::Cloud.new("env") do |config|
      config.local_adapter = Flipper::Adapters::OperationLogger.new(Flipper::Adapters::Memory.new)
      config.sync_secret = "env_tasty"
      config.sync_method = :webhook
    end
  }

  let(:app) { Flipper::Cloud.app(flipper) }
  let(:response_body) { JSON.generate({features: {}}) }
  let(:request_body) {
    JSON.generate({
      "environment_id" => 1,
      "webhook_id" => 1,
      "delivery_id" => SecureRandom.uuid,
      "action" => "sync",
    })
  }
  let(:timestamp) { Time.now }
  let(:signature) {
    Flipper::Cloud::MessageVerifier.new(secret: flipper.sync_secret).generate(request_body, timestamp)
  }
  let(:signature_header_value) {
    Flipper::Cloud::MessageVerifier.new(secret: "").header(signature, timestamp)
  }

  context 'when initializing middleware with flipper instance' do
    let(:app) { Flipper::Cloud.app(flipper) }

    it 'uses instance to sync' do
      Flipper.register(:admins) { |*args| false }
      Flipper.register(:staff) { |*args| false }
      Flipper.register(:basic) { |*args| false }
      Flipper.register(:plus) { |*args| false }
      Flipper.register(:premium) { |*args| false }

      stub = stub_request_for_token('regular')
      env = {
        "HTTP_FLIPPER_CLOUD_SIGNATURE" => signature_header_value,
      }
      post '/', request_body, env

      expect(last_response.status).to eq(200)
      expect(JSON.parse(last_response.body)).to eq({
        "groups" => [
          {"name" => "admins"},
          {"name" => "staff"},
          {"name" => "basic"},
          {"name" => "plus"},
          {"name" => "premium"},
        ],
      })
      expect(stub).to have_been_requested
    end
  end

  context 'when signature is invalid' do
    let(:app) { Flipper::Cloud.app(flipper) }
    let(:signature) {
      Flipper::Cloud::MessageVerifier.new(secret: "nope").generate(request_body, timestamp)
    }

    it 'uses instance to sync' do
      stub = stub_request_for_token('regular')
      env = {
        "HTTP_FLIPPER_CLOUD_SIGNATURE" => signature_header_value,
      }
      post '/', request_body, env

      expect(last_response.status).to eq(400)
      expect(stub).not_to have_been_requested
    end
  end

  context "when flipper cloud responds with 402" do
    let(:app) { Flipper::Cloud.app(flipper) }

    it "results in 402" do
      Flipper.register(:admins) { |*args| false }
      Flipper.register(:staff) { |*args| false }
      Flipper.register(:basic) { |*args| false }
      Flipper.register(:plus) { |*args| false }
      Flipper.register(:premium) { |*args| false }

      stub = stub_request_for_token('regular', status: 402)
      env = {
        "HTTP_FLIPPER_CLOUD_SIGNATURE" => signature_header_value,
      }
      post '/', request_body, env

      expect(last_response.status).to eq(402)
      expect(last_response.headers["Flipper-Cloud-Response-Error-Class"]).to eq("Flipper::Adapters::Http::Error")
      expect(last_response.headers["Flipper-Cloud-Response-Error-Message"]).to eq("Failed with status: 402")
      expect(stub).to have_been_requested
    end
  end

  context "when flipper cloud responds with non-402 and non-2xx code" do
    let(:app) { Flipper::Cloud.app(flipper) }

    it "results in 500" do
      Flipper.register(:admins) { |*args| false }
      Flipper.register(:staff) { |*args| false }
      Flipper.register(:basic) { |*args| false }
      Flipper.register(:plus) { |*args| false }
      Flipper.register(:premium) { |*args| false }

      stub = stub_request_for_token('regular', status: 503)
      env = {
        "HTTP_FLIPPER_CLOUD_SIGNATURE" => signature_header_value,
      }
      post '/', request_body, env

      expect(last_response.status).to eq(500)
      expect(last_response.headers["Flipper-Cloud-Response-Error-Class"]).to eq("Flipper::Adapters::Http::Error")
      expect(last_response.headers["Flipper-Cloud-Response-Error-Message"]).to eq("Failed with status: 503")
      expect(stub).to have_been_requested
    end
  end

  context "when flipper cloud responds with timeout" do
    let(:app) { Flipper::Cloud.app(flipper) }

    it "results in 500" do
      Flipper.register(:admins) { |*args| false }
      Flipper.register(:staff) { |*args| false }
      Flipper.register(:basic) { |*args| false }<commit_msg>Fix failures due to body change<commit_after>require 'securerandom'
require 'helper'
require 'flipper/cloud'
require 'flipper/cloud/middleware'
require 'flipper/adapters/operation_logger'

RSpec.describe Flipper::Cloud::Middleware do
  let(:flipper) {
    Flipper::Cloud.new("regular") do |config|
      config.local_adapter = Flipper::Adapters::OperationLogger.new(Flipper::Adapters::Memory.new)
      config.sync_secret = "regular_tasty"
      config.sync_method = :webhook
    end
  }

  let(:env_flipper) {
    Flipper::Cloud.new("env") do |config|
      config.local_adapter = Flipper::Adapters::OperationLogger.new(Flipper::Adapters::Memory.new)
      config.sync_secret = "env_tasty"
      config.sync_method = :webhook
    end
  }

  let(:app) { Flipper::Cloud.app(flipper) }
  let(:response_body) { JSON.generate({features: {}}) }
  let(:request_body) {
    JSON.generate({
      "environment_id" => 1,
      "webhook_id" => 1,
      "delivery_id" => SecureRandom.uuid,
      "action" => "sync",
    })
  }
  let(:timestamp) { Time.now }
  let(:signature) {
    Flipper::Cloud::MessageVerifier.new(secret: flipper.sync_secret).generate(request_body, timestamp)
  }
  let(:signature_header_value) {
    Flipper::Cloud::MessageVerifier.new(secret: "").header(signature, timestamp)
  }

  context 'when initializing middleware with flipper instance' do
    let(:app) { Flipper::Cloud.app(flipper) }

    it 'uses instance to sync' do
      Flipper.register(:admins) { |*args| false }
      Flipper.register(:staff) { |*args| false }
      Flipper.register(:basic) { |*args| false }
      Flipper.register(:plus) { |*args| false }
      Flipper.register(:premium) { |*args| false }

      stub = stub_request_for_token('regular')
      env = {
        "HTTP_FLIPPER_CLOUD_SIGNATURE" => signature_header_value,
      }
      post '/', request_body, env

      expect(last_response.status).to eq(200)
      expect(JSON.parse(last_response.body)).to eq({
        "groups" => [
          {"name" => "admins"},
          {"name" => "staff"},
          {"name" => "basic"},
          {"name" => "plus"},
          {"name" => "premium"},
        ],
      })
      expect(stub).to have_been_requested
    end
  end

  context 'when signature is invalid' do
    let(:app) { Flipper::Cloud.app(flipper) }
    let(:signature) {
      Flipper::Cloud::MessageVerifier.new(secret: "nope").generate(request_body, timestamp)
    }

    it 'uses instance to sync' do
      stub = stub_request_for_token('regular')
      env = {
        "HTTP_FLIPPER_CLOUD_SIGNATURE" => signature_header_value,
      }
      post '/', request_body, env

      expect(last_response.status).to eq(400)
      expect(stub).not_to have_been_requested
    end
  end

  context "when flipper cloud responds with 402" do
    let(:app) { Flipper::Cloud.app(flipper) }

    it "results in 402" do
      Flipper.register(:admins) { |*args| false }
      Flipper.register(:staff) { |*args| false }
      Flipper.register(:basic) { |*args| false }
      Flipper.register(:plus) { |*args| false }
      Flipper.register(:premium) { |*args| false }

      stub = stub_request_for_token('regular', status: 402)
      env = {
        "HTTP_FLIPPER_CLOUD_SIGNATURE" => signature_header_value,
      }
      post '/', request_body, env

      expect(last_response.status).to eq(402)
      expect(last_response.headers["Flipper-Cloud-Response-Error-Class"]).to eq("Flipper::Adapters::Http::Error")
      expect(last_response.headers["Flipper-Cloud-Response-Error-Message"]).to include("Failed with status: 402")
      expect(stub).to have_been_requested
    end
  end

  context "when flipper cloud responds with non-402 and non-2xx code" do
    let(:app) { Flipper::Cloud.app(flipper) }

    it "results in 500" do
      Flipper.register(:admins) { |*args| false }
      Flipper.register(:staff) { |*args| false }
      Flipper.register(:basic) { |*args| false }
      Flipper.register(:plus) { |*args| false }
      Flipper.register(:premium) { |*args| false }

      stub = stub_request_for_token('regular', status: 503)
      env = {
        "HTTP_FLIPPER_CLOUD_SIGNATURE" => signature_header_value,
      }
      post '/', request_body, env

      expect(last_response.status).to eq(500)
      expect(last_response.headers["Flipper-Cloud-Response-Error-Class"]).to eq("Flipper::Adapters::Http::Error")
      expect(last_response.headers["Flipper-Cloud-Response-Error-Message"]).to include("Failed with status: 503")
      expect(stub).to have_been_requested
    end
  end

  context "when flipper cloud responds with timeout" do
    let(:app) { Flipper::Cloud.app(flipper) }

    it "results in 500" do
      Flipper.register(:admins) { |*args| false }
      Flipper.register(:staff) { |*args| false }
      Flipper.register(:basic) { |*args| false }
{'fraction_non_alphanumeric': 0.1456594323873122, 'fraction_numerical': 0.008764607679465776, 'mean_word_length': 3.344968268359021, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 31, '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': '2633176', 'n_tokens_mistral': 3234, 'n_tokens_neox': 3207, 'n_words': 569}