#PHP SDK Integration tests

1 messages ยท Page 1 of 1 (latest)

shy moth
#

I'm turning this into a thread so I can keep help in one place:

#

This will sound silly but, how do I run the module_php_test.go independently?

#

or as close to as possible?

shy moth
#

Okay I think I got that part... I just ran go test --run ./module_php_test.go

gray escarp
#

so, i do this: dagger call test specific --race --pkg="./core/integration" --run="<regex for my test>"

#

this spins up the dev engine alongside

#

and manages all that

#

you can also do ./hack/with-dev go test --run ...

#

which is slightly different, because it starts a dev engine in-docker, and keeps it around afterwards

shy moth
#

What does the --run"regex" bit do?

#

is that like: "I want to run TestInit only"

gray escarp
#

the go test --run flag takes a regex for your test name

shy moth
#

Right so..

dagger call test specific --race --pkg="./core/integration/module_php_test.go" --run="TestInit"

would work?

#

Right now I just ran a test on integration full stop

gray escarp
#

uh, i don't actually know about putting file names in there, mayyyybe it works

#

i would make a new TestPHP function (copying the suite logic that we do in other test files)

#

then it should just be --run=TestPHP

shy moth
#

Oh I see!

gray escarp
shy moth
#

I think that already exists

#

I'm quite new to Go, so thank you.

#

It's quite a nice language, I can read it, write it with references. but the intricacies escape me currently

shy moth
#

I'm trying to make a simple "The local branch doesn't explode when initialized" test:

    t.Run("from local", func(ctx context.Context, t *testctx.T) {
        c := connect(ctx, t)

        sdkSrc, err := filepath.Abs("../../sdk/php/")
        require.NoError(t, err)
        
        out, err := daggerCliBase(t, c).
            WithDirectory("/sdk/php", c.Host().Directory(sdkSrc)).
            With(daggerExec(
                "init",
                "--name=bare",
                "--sdk=/sdk/php/")).
            With(daggerCall("container-echo", "--string-arg", "hello", "stdout")).
            Stdout(ctx)

        require.NoError(t, err)
        require.Equal(t, "hello\n", out)
    })

Right now that is what I'm trying but I get this:

Error: failed to generate code: input: moduleSource.withName.withSDK failed to loa            
dule source: local module dep source path "/sdk/php" is absolute: unknown builtin             
The "/sdk/php" SDK does not exist. The available SDKs are:                                    
- go                                                                                          
- python                                                                                      
- typescript                                                                                  
- php                                                                                         
- elixir                                                                                      
- java                                                                                        
- any non-bundled SDK from its git ref (e.g. github.com/dagger/dagger/sdk/elixir@m  
#

I see the Java one does this for modules (Which you helped me find before, thank you):

func javaModule(t *testctx.T, c *dagger.Client, moduleName string) *dagger.Container {
    t.Helper()
    modSrc, err := filepath.Abs(filepath.Join("./testdata/modules/java", moduleName))
    require.NoError(t, err)

    sdkSrc, err := filepath.Abs("../../sdk/java")
    require.NoError(t, err)

    return goGitBase(t, c).
        WithDirectory("modules/"+moduleName, c.Host().Directory(modSrc)).
        WithDirectory("sdk/java", c.Host().Directory(sdkSrc)).
        WithWorkdir("/work/modules/" + moduleName)
}
#

But I'm not testing a module just yet, I literally just want to check that TestInit doesn't explode from current changes

#

Is that possible? As I can't find any tests like that for other SDKs

gray escarp
#

huh

#

local module dep source path "/sdk/php" is absolute is a bit sus

#

technically. this is true.

#

oohhh lol

#

(use goGitBase instead of daggerCliBase)

#

the reason for this is that .git is a magical directory that sets the root (yes, this is painful)

shy moth
#

I still seem to be struggling with it. Absolute, relative. It isn't happy

#
    t.Run("from local", func(ctx context.Context, t *testctx.T) {
        c := connect(ctx, t)

        sdkSrc, err := filepath.Abs("../../sdk/php/")
        require.NoError(t, err)

        out, err := goGitBase(t, c).
            WithDirectory("work/sdk/php", c.Host().Directory(sdkSrc)).
            With(daggerExec(
                "init",
                "--name=bare",
                "--sdk=./sdk/php")).
            With(daggerCall("container-echo", "--string-arg", "hello", "stdout")).
            Stdout(ctx)

        require.NoError(t, err)
        require.Equal(t, "hello\n", out)
gray escarp
#

what error do you get?

shy moth
#

failed to load sdk for module source: failed to load local dep: select: local path "/work/sdk/php" does not exist: unknown builtin sdk

#

It wasn't happy when it was in /sdk/php because it was outside of scope

gray escarp
#

if you put the sdk in /work/sdk/php

#

and then set workdir to /work

#

then --sdk=./sdk/php should work

#

if not, i'll take a look

shy moth
#

But this should be the case already:

func goGitBase(t testing.TB, c *dagger.Client) *dagger.Container {
    t.Helper()
    return c.Container().From(golangImage).
        WithExec([]string{"apk", "add", "git"}).
        WithExec([]string{"git", "config", "--global", "user.email", "dagger@example.com"}).
        WithExec([]string{"git", "config", "--global", "user.name", "Dagger Tests"}).
        WithMountedFile(testCLIBinPath, daggerCliFile(t, c)).
        WithWorkdir("/work").
        WithExec([]string{"git", "init"})
#

goGitBase sets the work dir to "/work"

#

I'll update the withDirectory to have that forward slash at the front. Giving it a whirl now.

gray escarp
#

yeah that's worked for me

#
    t.Run("from local", func(ctx context.Context, t *testctx.T) {
        c := connect(ctx, t)

        sdkSrc, err := filepath.Abs("../../sdk/php/")
        require.NoError(t, err)

        out, err := goGitBase(t, c).
            WithDirectory("/work/sdk/php", c.Host().Directory(sdkSrc)).
            With(daggerExec(
                "init",
                "--name=bare",
                "--sdk=./sdk/php")).
            With(daggerCall("container-echo", "--string-arg", "hello", "stdout")).
            Stdout(ctx)

        require.NoError(t, err)
        require.Equal(t, "hello\n", out)
    })
shy moth
#

Yeah I'm getting somewhere with it, I had a slight error but it did make a difference

#

I didn't want to send out the fireworks before it ran XD

#

Okay. Success Protocol has begun
๐ŸŽ† ๐ŸŽ‰ ๐Ÿš€ ๐Ÿฆœ exit code 0

#

Thank you very much! I will tidy it up and put in a small PR shortly

shy moth
#

Next I will add in some actual module tests like the Java one does

shy moth
#

I'm doing something wrong here:

func (PHPSuite) TestPhpSignatures(ctx context.Context, t *testctx.T) {
bla bla bla t.Run yadayada
call test specific --race --pkg="./core/integration" --run="TestPhpSignatures"
.withExec(
args:
[
"go", 
"test", 
"-ldflags", 
"-X github.com/dagger/dagger/engine.Version=v0.17.0-250320123519-05ec7d865ca2 -X github.com/dagger/dagger/engine.Tag=05ec7d865ca261b2aee920144937757514e74607", 
"-timeout=30m", 
"-race", 
"-count=1", 
"-run", 
"TestPhpSignatures", 
"./core/integration"
]
)
29ms

ok      github.com/dagger/dagger/core/integration    1.218s [no tests to run]
gray escarp
#

it should be --run=TestPHP/TestPhpSignatures

shy moth
#

I plan to rename it to TestSignatures later, but for now, I just want to run it quick

#

Riiight.

shy moth
#

Nice! I have failing tests. One more question... should returning null actually give back an empty string?

#
                                                /go/pkg/mod/github.com/dagger/testctx@v0.0.4/tes        
295                                                                                                     
                                                /go/pkg/mod/github.com/dagger/testctx/oteltest@v        
g.go:37                                                                                                 
                                                /go/pkg/mod/github.com/dagger/testctx/oteltest@v        
ace.go:83                                                                                               
                                                /go/pkg/mod/github.com/dagger/testctx@v0.0.4/mid        
go:25                                                                                                   
                                                /go/pkg/mod/github.com/dagger/testctx@v0.0.4/tes        
149                                                                                                     
        Error:          Not equal:                                                                      
                        expected: <nil>(<nil>)                                                          
                        actual  : string("")                                                            
        Test:           TestPHP/TestSignatures/null                                                     
! test failed

#

This is the function it calls:

    #[DaggerFunction]
    public function getNull(): null
    {
        return null;
    }
#

Rather basic, but it's worth covering the basics

gray escarp
#

what does your test look like ๐Ÿ‘€

shy moth
#
func (PHPSuite) TestSignatures(ctx context.Context, t *testctx.T) {
    c := connect(ctx, t)
    module := phpModule(t, c, "signatures")

    t.Run("null", func(ctx context.Context, t *testctx.T) {
        out, err := module. With(daggerCall("get-null")). Stdout(ctx)
        require.NoError(t, err)
        require.Equal(t, nil, out)
    })

    // ...
gray escarp
#

ah yeah, that makes sense. the stdout is going to be the empty string

shy moth
#

Of course it is.

#

Is there a way to test the exact value?

gray escarp
#

you should just be able to do require.Equal(t, "", out)

#

you can also do require.Empty sometimes?

shy moth
#

But that's fine. I just wanted to make sure I hadn't found a bug with PHP nulls

shy moth
#

Everything else is just, generated stuff required to run the test modules

gray escarp
#

awesome! looking now!

#

was on holiday in the lake district ๐Ÿ‘€

shy moth
#

Oh nice ๐Ÿ•ถ๏ธ

#

Tom reviewed it so it's been merged but we've got a few more tests ๐Ÿ˜Œ

#

I'm adding some built-in object ones as well.

#

Genuine relief ๐Ÿ˜…

It removes so much worry of "Okay, have I broken anything?"

shy moth
#

I'm hoping you may be able to save me on this one: I want to test that I can pass a custom object as an argument.

#[DaggerObject] class Custom
{
    #[DaggerFunction] public function daggerOrganization(): Organization
    {
        // ...
    }

    #[DaggerFunction, ReturnsListOfType('string')]
    public function getUrlsOfMembers(Organization $arg): array
    {
        // ...
    }
}

So I need to call dagger-organization and then pass that object to the get-urls-of-members function.

But I have no idea how to write that bit in Go.

    t.Run("Custom Object", func(ctx context.Context, t *testctx.T) {
        c := connect(ctx, t)
        module := phpModule(t, c, "object-kind/custom")

        // org := module.With(daggerCall("dagger-organization"))

        // out, err := module.
        //         Call("get-urls-of-members", org).
        //         Stdout(ctx)

        require.NoError(t, err)
        require.Equal(t, "https://github.com/jane\nhttps://github.com/john\n", out)
    })
#

I've put some pseudo code in there atm. But I only know how to get the stdout. I'm just not sure how I should go about testing this.

gray escarp
#

ah, you can't pass objects on the cli using call

shy moth
#

Yeah sorry, pseudocode

gray escarp
#

you can either:

  • create the php module as a depdency (scan for ./dep usage), and then call it
#
  • or, use shell, which can use a subshell $() to create the object
#

there should be a pattern of the first somewhere

shy moth
#

Is the shell option something I can do inline?

#

like daggerCall("get-urls-of-members", "--arg=$(dagger-organization)"

gray escarp
#

uhhh using daggerShell as a helper i think works

#

(not daggerCall)