Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add alias for creating a generic container definition #194

Merged
merged 8 commits into from
Nov 1, 2021
Merged

Add alias for creating a generic container definition #194

merged 8 commits into from
Nov 1, 2021

Conversation

alejandrohdezma
Copy link
Contributor

@alejandrohdezma alejandrohdezma commented Oct 6, 2021

Just adds an alias for creating a ContainerDef for a GenericContainer that doesn't involve creating a new object/class.

Example:

import scala.io.Source

import java.net.URL

import org.scalatest.flatspec.AnyFlatSpec

import com.dimafeng.testcontainers.GenericContainer
import com.dimafeng.testcontainers.scalatest.TestContainerForAll

import org.testcontainers.containers.wait.strategy.Wait

class GenericContainerSpec extends AnyFlatSpec with TestContainerForAll {
  
  override val containerDef = GenericContainer.Def.anonymous("nginx:latest",
    exposedPorts = Seq(80),
    waitStrategy = Wait.forHttp("/")
  )

  "GenericContainer" should "start nginx and expose 80 port" in withContainers { container =>
    assert(Source.fromInputStream(
      new URL(s"http://${container.containerIpAddress}::${container.mappedPort(80)}/").openConnection().getInputStream
    ).mkString.contains("If you see this page, the nginx web server is successfully installed"))
  }

}

@dimafeng
Copy link
Collaborator

dimafeng commented Oct 7, 2021

Hey @LMnet I'm a bit rusty on the original idea of Def. Do you remember why it wasn't added initially?

@LMnet
Copy link
Contributor

LMnet commented Oct 7, 2021

Hi @alejandrohdezma

I tried to compile your example but it's not compiling. Could you fix it? After that, we will be able to discuss your idea in more detail.

@alejandrohdezma
Copy link
Contributor Author

Hey @LMnet, thanks for the swift response? What exactly is not compiling? I just run +Test/compile and everything is working fine.

@LMnet
Copy link
Contributor

LMnet commented Oct 7, 2021

I'm talking about your example in the merge request description:

class GenericContainerSpec extends AnyFlatSpec with TestContainersForAll {
  
  override val containerDef = GenericContainer.Def("nginx:latest",
    exposedPorts = Seq(80),
    waitStrategy = Wait.forHttp("/")
  )

  "GenericContainer" should "start nginx and expose 80 port" in {
    assert(Source.fromInputStream(
      new URL(s"http://${container.containerIpAddress}:${container.mappedPort(80)}/").openConnection().getInputStream
    ).mkString.contains("If you see this page, the nginx web server is successfully installed"))
  }
}

@alejandrohdezma
Copy link
Contributor Author

Thanks @LMnet, I have updated the example and the changes. The example was using the wrong trait and missing the withContainers. I've also updated the changes since previous changes didn't allow the suite to use the container as a GenericContainer and thus unable to use methods like mappedPort, should be fixed now.

@LMnet
Copy link
Contributor

LMnet commented Oct 7, 2021

Thanks, @alejandrohdezma Now it looks fine.

But I'm a bit concerned about the impact of this apply method. apply usually means something like a default constructor. But in this case, it's not true. Your use case feels like you want to use an anonymous generic container. So maybe it is worth renaming your new apply to anonymous? @dimafeng wdyt?

Signed-off-by: Alejandro Hernández <[email protected]>
@alejandrohdezma
Copy link
Contributor Author

@LMnet done!

@dimafeng
Copy link
Collaborator

dimafeng commented Oct 9, 2021

@alejandrohdezma would you mind updating your example snippet. It seems I'm not following the idea with anonymous but an example should help

@alejandrohdezma
Copy link
Contributor Author

Done!

@dimafeng
Copy link
Collaborator

Hey @LMnet quick question - why GenericContainer.Def.anonymous is better than just GenericContainer.Def? I think I'm missing something.

@LMnet
Copy link
Contributor

LMnet commented Oct 10, 2021

All my concerns I described above. The default use case for GenericContainer.Def is described here.

Overall, GenericContainer.Def is a building block for a container definition for some container. But @alejandrohdezma's use case is about creating an anonymous container definition (means without corresponding class for a container).

If we will use apply instead of anonymous, I think users may misuse this API. They could think that this apply is just an another form of a default constructor, but it's not actually true.

@dimafeng
Copy link
Collaborator

Got it! It makes sense.

@LMnet @alejandrohdezma would it make sense to create a new class instead e.g.AnonymousGenericContainer / AnonymousContainer? In that case, it's going to be a bit more consistent with other Def's (override val containerDef = AnonymousGenericContainer.Def(...)) What do you think?

@alejandrohdezma
Copy link
Contributor Author

Got it! It makes sense.

@LMnet @alejandrohdezma would it make sense to create a new class instead e.g.AnonymousGenericContainer / AnonymousContainer? In that case, it's going to be a bit more consistent with other Def's (override val containerDef = AnonymousGenericContainer.Def(...)) What do you think?

Of course! I'll send a new commit tomorrow morning :(

@dimafeng
Copy link
Collaborator

dimafeng commented Oct 10, 2021

Thanks!

@LMnet does it sound good to you?

@LMnet
Copy link
Contributor

LMnet commented Oct 11, 2021

@dimafeng I'm not sure. Discoverability of AnonymousGenericContainer.Def will be definitely worse, than GenericContainer.Def.anonymous.

@alejandrohdezma
Copy link
Contributor Author

If we go with that I would remove the anonymous too, and leave it just as apply, since discoverability would be better as it would be as any other container definition, where the apply method constructs the definition. In this case we will be just creating a "generic" container definition.

@dimafeng
Copy link
Collaborator

dimafeng commented Oct 11, 2021

Seems we're comparing several non-ideal solutions:

  1. GenericContainer.Def.anonymous goes against the convention that all other Defs use
  2. AnonymousGenericContainer.Def breaks the 1:1 mapping with old api
  3. GenericContainer.Def uses apply non-canonically

4th option:
Should we consider renaming abstract class Def[C <: GenericContainer] to something else and then reusing it for a definition of GenericContainer.Def?

@alejandrohdezma
Copy link
Contributor Author

Sorry @dimafeng I didn't see your reply :(

What I like about the apply idea is that it doesn't involve a breaking change (like renaming Def) and it is consistent with all the other containers, where you have PostgresContainer.Def#apply, but in this case for creating a "generic" one.

@dimafeng
Copy link
Collaborator

After thinking a bit, I'm leaning toward your options with Def.apply with potential breaking-change migration to the option 4 in the future. For me, consistency is pretty important for discoverability.

@LMnet any final thoughts?

@LMnet
Copy link
Contributor

LMnet commented Oct 19, 2021

I prefer option 1. But option 3 is acceptable.

@dimafeng
Copy link
Collaborator

@alejandrohdezma can we proceed with the option 3? Would you mind also changing README and adding a simple test?

@alejandrohdezma
Copy link
Contributor Author

Of course, I'll do it as soon as possible :)

@alejandrohdezma
Copy link
Contributor Author

@alejandrohdezma can we proceed with the option 3? Would you mind also changing README and adding a simple test?

Done! :)

@dimafeng
Copy link
Collaborator

@alejandrohdezma thank you! Seems some tests failed

README.md Outdated
@@ -181,13 +181,13 @@ The most flexible but less convenient container type is `GenericContainer`. This
with custom configuration.

```scala
class GenericContainerSpec extends AnyFlatSpec with ForAllTestContainer {
override val container: GenericContainer = GenericContainer("nginx:latest",
class GenericContainerSpec extends AnyFlatSpec with TestContainerForAll {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we update this section instead - https://github.com/testcontainers/testcontainers-scala#genericcontainer-usage

I'd like to keep it consistent until we finally migrate to one way of doing it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done here: 4e8e553

@dimafeng
Copy link
Collaborator

@alejandrohdezma thanks! The test is failing with scala 3

 [info] compiling 13 Scala sources and 1 Java source to /home/runner/work/testcontainers-scala/testcontainers-scala/test-framework/scalatest/target/scala-3.0.2/test-classes ...
[error] -- [E008] Not Found Error: /home/runner/work/testcontainers-scala/testcontainers-scala/test-framework/scalatest/src/test/scala/com/dimafeng/testcontainers/GenericContainerSpec.scala:17:35 
[error] 17 |      new URL(s"http://${container.containerIpAddress}:${container.mappedPort(80)}/").openConnection().getInputStream
[error]    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[error]    |value containerIpAddress is not a member of GenericContainerSpec.this.Containers
[error] -- [E008] Not Found Error: /home/runner/work/testcontainers-scala/testcontainers-scala/test-framework/scalatest/src/test/scala/com/dimafeng/testcontainers/GenericContainerSpec.scala:17:67 
[error] 17 |      new URL(s"http://${container.containerIpAddress}:${container.mappedPort(80)}/").openConnection().getInputStream
[error]    |                                                         ^^^^^^^^^^^^^^^^^^^^
[error]    |value mappedPort is not a member of GenericContainerSpec.this.Containers
[error] two errors found
[error] two errors found

@alejandrohdezma
Copy link
Contributor Author

@dimafeng should be fixed now

@dimafeng dimafeng merged commit 3c89787 into testcontainers:master Nov 1, 2021
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.

3 participants