Skip to content

Basic copy_to implementation#242

Open
gossi wants to merge 14 commits intotestcontainers:mainfrom
gossi:container-assets
Open

Basic copy_to implementation#242
gossi wants to merge 14 commits intotestcontainers:mainfrom
gossi:container-assets

Conversation

@gossi
Copy link
Contributor

@gossi gossi commented Feb 24, 2026

Impl for #240

I did some research for the API in rust and node clients:

For elixir, I choose the method from rust with_copy_to and then use pattern matching against the cases.

I personally only need one case here and did the impl for the most basic one 🙈.

@gossi
Copy link
Contributor Author

gossi commented Feb 24, 2026

container_test is reporting issues (socket closed). For once, the introduced copy_to_test is failing.

@gossi
Copy link
Contributor Author

gossi commented Mar 2, 2026

@jarlah this is the last missing feature for me to complete my library using testcontainers, I'd like to see this in 2.0 (it is a blocker for me).

Anything I can help out to get this through?

@jarlah
Copy link
Member

jarlah commented Mar 13, 2026

so sorry.. been awfully busy the last weeks. Actually been a heavy user of testcontainers actually and its not easy to admit that its not as stable as it should be hah

@jarlah
Copy link
Member

jarlah commented Mar 13, 2026

first off the hash test thats because you introduced new struct field in container. So thats easy to fix. Just use the new hash in the test.

@jarlah
Copy link
Member

jarlah commented Mar 15, 2026

ill look into this and the other PR now, plus the AWFUL flakyness of the ryuk connection initialization! Im running two production projects and im not kidding when i say that ryuk fails so many times ai is skipping running tests all together from time to time ..

@jarlah
Copy link
Member

jarlah commented Mar 16, 2026

haha sorry @gossi i destroyed this PR by syncing it. But anway. Master should be extremely more stable now. for ex just see here from a local run, only the periodically 1 in 10 flaky kafka test left

./run_tests.sh
========================================
Run 1/10
========================================
Cleaning up Docker containers...
Running tests...
PASSED

========================================
Run 2/10
========================================
Cleaning up Docker containers...
Running tests...
PASSED

========================================
Run 3/10
========================================
Cleaning up Docker containers...
Running tests...
PASSED

========================================
Run 4/10
========================================
Cleaning up Docker containers...
Running tests...
PASSED

========================================
Run 5/10
========================================
Cleaning up Docker containers...
Running tests...
PASSED

========================================
Run 6/10
========================================
Cleaning up Docker containers...
Running tests...
FAILED on run 6
Finished in 114.0 seconds (27.9s async, 86.1s sync)
  1) test kafka container provides a ready-to-use kafka container (Testcontainers.Container.KafkaContainerTest)
     test/container/kafka_container_test.exs:136
     ** (MatchError) no match of right hand side value: :leader_not_available
     code: {:ok, _} = KafkaEx.produce(topic_name, 0, "hey", worker_name: worker_name, required_acks: 1)
     stacktrace:
       test/container/kafka_container_test.exs:146: (test)

..............
Finished in 114.0 seconds (27.9s async, 86.1s sync)
120 tests, 1 failure

--- Full output saved to test_run_6.log ---

========================================
Run 7/10
========================================
Cleaning up Docker containers...
Running tests...
PASSED

========================================
Run 8/10
========================================
Cleaning up Docker containers...
Running tests...
PASSED

========================================
Run 9/10
========================================
Cleaning up Docker containers...
Running tests...
PASSED

========================================
Run 10/10
========================================
Cleaning up Docker containers...
Running tests...
PASSED

========================================
Summary: 10 runs completed
========================================
1 run(s) failed:
  - Run 6: exit code 2

its also possible to run tests completely offline. For ex when on a plane and you just want to run a couple of tests when you have all images locally.

@jarlah
Copy link
Member

jarlah commented Mar 16, 2026

im making a new version from this. Actually, i think i will release version 2.0.0-rc2. Then, after using it for a couple of days, checking its more resilient, release 2.0.0 end of week

@jarlah
Copy link
Member

jarlah commented Mar 16, 2026

v2.0.0-rc2 released. Will use it on my two prod apps this coming week

@gossi gossi force-pushed the container-assets branch from e25eaac to be4190c Compare March 16, 2026 12:21
Copy link
Contributor Author

@gossi gossi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hash fixes were the easy parts ;)

I run into couple others:

  • Creating, starting and waiting was (and is) inconsistent (see my comments on ryuk, that reveal that)
  • I tried to make the API a bit more explicit (one function each for creating, starting and waiting) - I got quite far I'd say
  • I wanted to solve my connreset problem, I fixed the inotify problem

I still have this issue:

1) test copy contents to target (CopyToTest)
Error:      test/copy_to_test.exs:5
     ** (MatchError) no match of right hand side value: {:error, :socket_closed_remotely}
     code: {:ok, %{body: body}} = Tesla.get("[http://127.0.0.1:#{mapped_port}/hello.txt](http://127.0.0.1/#{mapped_port}/hello.txt)")
     stacktrace:
       test/copy_to_test.exs:18: (test)

So, locally when running the tests, it's green and clear. I think this is a race condition when running this on GH actions, although I have no idea which socket is closed (docker, nginx 🤷).

I tried with and without http wait strategy, seems like something else decides to kill some process here.

Anything we can do to make that execution stable?

Comment on lines +346 to +347
with {:ok, id} <- create_container(conn, ryuk_config, properties),
{:ok, container} <- start_container_with_id(conn, id),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if I made this better or worse here. In the end ryuk is started as any other container, with the same config, with the same expectation.

Yet it is handled differently.

The weird part, ryuk_config in that situation is used for both config and config_builder - which is a separate thing below o_O. That was (and is) super confusing when I tried to run ryuk and any other container through the same "handlers".

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i would like any changes to this part of the code to be done in a separate PR unless explicitly required by the PRs main changes

defp create_and_start_and_wait_for_container(config, config_builder, state) do
with {:ok, id} <- create_container(state.conn, config, state.properties),
{:ok, container} <- start_container_with_id(state.conn, id),
:ok <- ContainerBuilder.after_start(config_builder, container, state.conn),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ie. ryuk doesn't get this after_start check.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again i think we should add minimal changes. are all these changes required just add copy to container?

@gossi
Copy link
Contributor Author

gossi commented Mar 16, 2026

ha! you made the http strategy stable and my PR is green now - WoW!

Please have a look :)


steps:
- uses: actions/checkout@v4
- name: Install inotify-tools
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a specific need for inotify tools ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not necessarily. Inotify tools handle file nodes for i/o.

At times I had this as only error message. So, I fixed this at first. (I did the same at my other project using testcontainers). In the end it makes test output cleaner and does not clutter the console output with errors/warnings that detract from actual debugging, that's helpful.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I gonna extract this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see #246

Copy link
Member

@jarlah jarlah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice job, :) Sorry about the "thumbs down" but i feel the amount of changes in the core startup logic is too much just for a copy to container logic. Can you scope it down? to just copy to container logic? e.g. as little as changes required to get it working ?

@jarlah
Copy link
Member

jarlah commented Mar 16, 2026

there is always a chance i didnt understand the reasoning behind the changes too, so 🐻 that in mind

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants