shahryarjb

shahryarjb

Req application/octet-stream tar file mock test

Hello friends, Imagine you want to download a tar file from hex.pm website.

I have this function and do not want to install req hex plugin. as you see I find the "contents.tar.gz" and it is the binary of file.

  @spec download(download_type, pkg) :: okey_return | error_return
  def download(:hex, %{app: app, tag: tag_name}) when not is_nil(tag_name) do
    case build_url("https://repo.hex.pm/tarballs/#{app}-#{tag_name}.tar") do
      %Req.Response{status: 200, body: body} ->
        converted = Map.new(body, fn {key, value} -> {to_string(key), value} end)
        {:ok, converted["contents.tar.gz"]}

      _ ->
        mix_global_err()
    end
  end

And downloader function:

  defp build_url(location) do
    [base_url: location]
    |> Keyword.merge(Application.get_env(:mishka_installer, :downloader_req_options, []))
    |> Keyword.merge(Application.get_env(:mishka_installer, :proxy, []))
    |> Req.request!()
  end

Now I want to mock it, so this is the place I can not be able to fix.

One of my function test is what does not work:

body = [
        {~c"VERSION", "3"},
        {~c"CHECKSUM", "1D5EC32825E5AF1B5CF58933F4C918909BC79E4391EBE2B9315B02705145B18F"},
        {~c"metadata.config", "{<<\"app\">>,<<\"mishka_installer\">>}.\n{<<\"build_tools\">>"},
        {~c"contents.tar.gz", <<31, 139, 8, 0, 0, 0>>}
      ]

      body_iolist_to_binary =
        Enum.reduce(body, "", fn {key, value}, acc -> acc <> "#{key}:#{value}\n" end)
        |> :erlang.iolist_to_binary()

      Req.Test.expect(Downloader, fn conn ->
        conn
        |> Plug.Conn.put_resp_content_type("application/octet-stream")
        |> Plug.Conn.send_resp(200, body_iolist_to_binary)
      end)

If I put body directly I have error!! I have no idea how can simulate the hex output.

It should be noted my function works as well, my problem is located in testing this

Thank you in advance

Most Liked

wojtekmach

wojtekmach

Hex Core Team

Even if you end up not using req_hex, I’d still consider using hex_core to get more realistic tests. Here is an example:

Mix.install([
  :req,
  :plug,
  :hex_core
])

Req.Test.expect(Downloader, fn conn ->
  {:ok, %{tarball: tarball}} =
    :hex_tarball.create(
      %{
        "name" => "foo",
        "version" => "1.0.0"
      },
      [
        {~c"mix.exs",
         """
         defmodule Foo.MixProject do
           use Mix.Project
           def project do
             [app: :foo, version: "1.0.0"]
           end
         end
         """}
      ]
    )

  conn
  |> Plug.Conn.put_resp_content_type("application/octet-stream", nil)
  |> Plug.Conn.send_resp(200, tarball)
end)

Req.get!(url: "/foo.tar", plug: {Req.Test, Downloader})
|> IO.inspect()

Thanks @LostKobrakai for reporting the format detection bug btw. application/octet-stream; charset=utf-8 is not a proper content-type for tar, these bytes are not utf8. I’ll see if I can make any improvements anyway though.

LostKobrakai

LostKobrakai

Good point. I didn’t really think about that tbh. So Plug.Conn.put_resp_content_type(conn, "application/octet-stream", nil) is actually the way to go then, not just a workaround.

LostKobrakai

LostKobrakai

A tar file is not some kind of map, like you’re building here in your test. The body you get from Req has the tar already extracted, which gives you a map (see Req.Steps — req v0.5.0). In your mock you need to build a proper .tar file, e.g. by using :erl_tar.

LostKobrakai

LostKobrakai

This looks to be a bug. Tracing in Req it determines tar as format on the real request, but bin for the mocked request – hence no automatic decoding happening. You could work around this by disabling the built in decoding and doing it manually.

LostKobrakai

LostKobrakai

Where Next?

Popular in Questions Top

lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
chrisalley
ExUnit now has describe blocks which is a welcome addition coming from RSpec. In the docs, it states that nested hierarchies of describe ...
New
sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
wernerlaude
In AR this is so simple @articles = current_user.articles How to do in Ecto? def index(conn, _params) do current_user = conn.assig...
New

Other popular topics Top

minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
yurko
Here are few pieces of (common) Linux knowledge that we use for reasonably small one server apps. We use Ubuntu but this should work for ...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
AstonJ
We’ve put together this wiki for Phoenix LiveView - please feel free to add any info you feel is worth including. What is Phoenix LiveV...
New
AstonJ
by Lance Halvorsen Elixir and Phoenix are generating tremendous excitement as an unbeatable platform for building modern web application...
460 27162 124
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New
magnetic
Hey :wave:t3: Elixir community, I’ve been learning Elixir, and working on some side projects. My editor of choice is VSCode, and althoug...
New

We're in Beta

About us Mission Statement