#@Nipuna Perera here's another pattern I'

1 messages ยท Page 1 of 1 (latest)

twin wing
#

Given the following module function:

func (m *Lala) Echo(ctx context.Context,
    // +default=true
    alpine bool,
) *Container {
    var c *Container
    if alpine {
        c = dag.Container().From("alpine")
    } else {
        c = dag.Container().From("ubuntu")
    }
    return c.WithExec([]string{"echo", "hello"})
}

Imagine you want to test this Echo function

#

You can currently, create a main_test.go file to test this as follows:

func Test(t *testing.T) {
    ctx := context.Background()
    m := &Lala{}
    c := m.Echo(ctx, true)
    if c == nil {
        t.Error("Expected a container but got nil")
    }
    _, err := c.File("/etc/alpine-release").Size(ctx)
    if err != nil {
        t.Fatal("container is not alpine")
     }
}
#

the question is: how do you call that test? since it requires a Dagger context to be present in order to run.

Well.. there's a nice trick you can use which is to leverage on the runtime container and session nesting for that. You can just create another function in your module like this:

#
func (m *Lala) TestModule(ctx context.Context) *Container {
    return dag.CurrentModule().
        Source().
        AsModule().
        Runtime().
        WithWorkdir("/src").
        WithExec([]string{"go", "test", "-v", "./..."}, ContainerWithExecOpts{
            ExperimentalPrivilegedNesting: true,
        })
}
#

and as you can see, I'm leveraging the module's default runtime container (go in this case) to run my test suite with a nested engine.

This way, my Echo function is fully tested.

#

disclaimer: this is an experimental pattern that I've been playing with lately. It has its trade-offs but in my personal opinion, I'm starting to like more this approach than the extenral tests submodule

tender elbow
#

That's an interesting pattern. I am tempted to test this out. Does the test class still have access to the dagger client when I want to pull a new image for example?

twin wing
#

cc @mellow junco also for visibility

tender elbow
#

The downside I see is it's hard to test the default/optional values and the New() constructor with this pattern. I'd have to call it by hand, possibly in a setup function.

twin wing
# tender elbow The downside I see is it's hard to test the default/optional values and the `New...

true.

for optional / default arguments I'm generally using the anonymous struct way (#1257784771845554236 message) which I like more since that makes my function cleaner when called from other modules and also testable.

re the constructor thing yes, in the case of Go you have to manually call it. That's generally the first test and helper function I write when I create my New function, assert that it's being called ๐Ÿ˜„

twin wing
tender elbow
#

Hey @twin wing how do you run this when you have module dependencies in a parent folder? For example I have a dependency for ../mymodule and when I run your code I get failed to resolve dependency: select: module dep source root path "../mymodule" escapes root

twin wing