vivus-ignis
Hello there!
I have a mix task which grabs some data from a remote API, collects it into a file (a biggish xml), then sucks it in as a stream and processes doing a bunch of text transformations.
Now I’m trying to sketch an integration test for the processing part (skipping the getting-the-data part) and I wonder… is it possible to use a string variable instead of a file for that purpose?
This is what I have in my mix task code:
File.stream!("#{@download_dir}/#{category}.xml", [:read])
|> ... processing part I want to test follows
And this is how I’m trying to simulate (unsuccessfully so far) the File.stream! part:
input_xml = """
... xml fragment ...
...
"""
input_xml
|> Stream.unfold( &(String.split(&1, "~n")) )
|> ... processing part ...
Of course what I’m getting after this Stream.unfold is different from File.stream! – the Stream.unfold results in all the newlines being removed.
And then my processing part breaks as it relies on newlines in certain places (yeah, it sounds crazy, but inside that xml I have wiki markup-formatted fragments where newlines do matter).
So my question is: is it possible to split a string by newlines in such a way that I can preserve those "\n"s? That is, can I emulate FIle.stream! without an actual file?
Would appreciate any hints. Thank you!
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #blog-post
- #phoenix_html
- #iex
- #ai
- #graphql
- #genstage
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex










Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
wmnnd
You’re in luck, you can simply use
StringIO.open/1andIO.binstreamin order to stream any String:vivus-ignis
Thank you.
I’ve rewritten my spec to use the suggested approach, however, now I cannot get my tests to finish running.
When I try to running it in IEX (create a stream, start splitting it as a binstream and then just print every line using Enum.each), my system just goes down to its knees. Output stops after ~ 20 iterations and my Activity Monitor app just shows beam and kernel_task on top of the list for both CPU and memory consumption. The laptop fans are roaring and the window UI in general becomes sloppy.
I’m running macOS Sierra on a Macbook Air (1.6 Ghz i5, 4 Gb RAM), elixir and erlang are installed with homebrew (1.4.2 and 19.3 respectively).
Ah, and the data size is actually tiny for this test: 107 lines.
wmnnd
Could you post the code with which you’re trying this?
vivus-ignis
michalmuskala
Why not use one of the string functions? I understand you want to get an enumerable of lines from the string. This can be achieved eagerly with
String.split(str, "\n")or lazily withString.splitter(str, "\n").NobbZ
Because
String.split/2andString.splitter/2will remove the split-points, but the OP said he needs them intact.wmnnd
This is really odd though, running the code @vivus-ignis posted in IEx completely froze my Ubuntu 16.10 with an i7 after just a couple of lines and I had to do a hard reset.
Even more strange is the fact, that this even happens if the last line was the following:
Could this be a bug in the standard library?
vivus-ignis
Should I report that to elixir-lang github issues?
NobbZ
I did the experiment as well in an VBox, 6th gen i5 here. The Box had 4 GiB of RAM available, another 4 GiB of swap.
I did not reset the Box, but let it run,
The Box took all available CPU I assigned (4 cores at 75%) and I was able to see how memory consumption in the box rose, I had
htopopen in another terminal on that box. After about 2 minutes iex died:eheap_alloc: Cannot allocate 3280272216 bytes of memory (of type "old_heap")..So this seems in fact something we need to report. Since it was only some very quick testing, I took the elixir version available in the ubuntu repositories, 1.1.0. I’d be glad if someone could verify that we get killed because of OOM somewhen even on newer bversions or if at least memory consumption rises before the system gets stale.
Also I have to tell what I observed regarding the speed of the output lines that came. The first one were really quick and then it took longer and longer for each single line until iex died.
aseigo
I can also reproduce this with Elixir 1.4.2 / OTP 19. For a string with a few lines is works fine, but with more lines it takes more and more wall-clock time per line. Using a progressively longer string, this behavior becomes quite obvious, and it looks very much like O(n^2) type behavior with n being the number of lines in the string opened with StringIO.open.