Search code examples
rubyunit-testingsinatrarack-test

Mocking a post request with binary data in Sinatra


I have an endpoint in my Sinatra application that will be receiving binary data as part of the body. The other application sending it data will have a Faraday request that looks like this:

    connection = Faraday.new(url: "https://example.com/post_data") do |conn|
      conn.request :multipart
      conn.adapter :net_http
      conn.headers['Content-Type'] = 'octet/stream'
    end

    @response ||= connection.post do |req|
      req.params = { :host => host,
                     :verification => "false"}
      req.body = my_base64_encoded_binary
    end

Then, in Sinatra, I will have an endpoint that receives those request parameters and binary data and passes it along to a model, like so:

post '/post_data' do
  request.body.rewind
  payload = request.body.read

  raise Sinatra::NotFound unless payload and params[:host]
  output = MyOutput.new(params, payload)

  content_type 'application/json'
  body output.data
end

When I try to test this endpoint using Rack::Test helpers, I end up in a weird situation. I can't seem to create the proper mock in order to test this endpoint properly. Based on some manual testing with PostMan, I'm pretty certain my endpoint works properly. It's just the test that's holding me up. Here is the spec:

 it "should return a json response" do
    post(url, :host => host, :verification => "false") do |req|
      req.body = [my_binary]
      req.content_type = "application/octet-stream"
    end

    expect(last_response.status).to eq(200)
    expect(last_response.content_type).to eq("application/json")
  end

And when I inspect what the incoming request looks like in the test, it does not contain a proper body. params is properly set to the host and verification settings I set, but the body is also being set to the params (inspected through payload = request.body.read) instead of the binary.

Is there a different way to set up the mock so that the binary properly is set to the body of the request, and the parameters are still set to the request parameters properly?


Solution

  • The answer is that the only way to post the body is where I was adding the params in the rack test helper. I needed to take the params and move them into the query string of the URL in the request, and then only add the binary as the body of the post request in the test helper.

      let(:url) { "http://example.com/post_data?host=>#{host}&verification=#{verification}" } 
      it "should return a json response" do
        post(url, my_binary)
    
        expect(last_response.status).to eq(200)
        expect(last_response.content_type).to eq("application/json")
      end