使用Golang exec命令运行时,Firebase仿真器不会停止

时间:2020-10-13 20:59:08

标签: firebase go firebase-tools

我正在使用此article中的信息来使用Firebase模拟器为Firestore构建测试。

仿真器可以正常启动,可以运行测试,但是尽管有SIGKILL(我尝试了其他信号),但测试完成后仍未清除仿真器。

这是我的main_test.go的样子:

package main

import (
    "fmt"
    "io"
    "log"
    "os"
    "os/exec"
    "strings"
    "syscall"
    "testing"
    "time"
)

func TestMain(m *testing.M) {
    // command to start firestore emulator
    cmd := exec.Command("firebase", "emulators:start")

    // this makes it killable
    cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}

    // we need to capture it's output to know when it's started
    stdout, err := cmd.StdoutPipe()
    if err != nil {
        log.Fatal(err)
    }
    defer stdout.Close()

    if err := cmd.Start(); err != nil {
        log.Fatal(err)
    }

    var result int
    defer func() {
        syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)
        os.Exit(result)
    }()

    started := make(chan bool)
    go func() {
        buf := make([]byte, 512, 512)
        for {
            n, err := stdout.Read(buf[:])
            if err != nil {
                if err == io.EOF {
                    break
                }
                log.Fatalf("reading stdout %v", err)
            }

            if n > 0 {
                d := string(buf[:n])

                // only required if we want to see the emulator output
                fmt.Printf("%s", d)

                // checking for the message that it's started
                if strings.Contains(d, "All emulators ready") {
                    started <- true
                    break
                }
            }
        }
    }()

    done := make(chan error, 1)
    go func() {
        done <- cmd.Wait()
    }()

    select {
    case <-time.After(10 * time.Second):
        log.Fatal("Failed to start the command for 10 seconds")
    case err := <-done:
        log.Fatalf("------\nCommand has finished unexpectedly with error: %v", err)
    case <-started:
        fmt.Println("--------")
        log.Print("Command started successully... running tests")
    }

    log.Print("BEFORE running tests")
    result = m.Run()
    time.Sleep(time.Minute) // to simulate that it take some times to run tests
    log.Print("AFTER running tests")
}

go test . -v的输出看起来不错:

i  emulators: Starting emulators: firestore
i  firestore: Firestore Emulator logging to firestore-debug.log
i  ui: Emulator UI logging to ui-debug.log

┌───────────────────────────────────────────────────────────────────────┐
│ ✔  All emulators ready! View status and logs at http://localhost:4000 │
└────────────────────────────────────────────────────────────--------
2020/10/13 16:20:29 Command started successully... running tests
2020/10/13 16:20:29 BEFORE running tests
testing: warning: no tests to run
PASS
2020/10/13 16:20:29 AFTER running tests
ok      go/src/test (cached) [no tests to run]

但是firebase仿真器没有正确清理(如果我再次启动同一命令,则无法抱怨端口4000已被使用)。发现以下过程持续存在:

### snippet from netstat -anp:
tcp        0      0 127.0.0.1:4000          0.0.0.0:*               LISTEN      25187/firebase
tcp6       0      0 127.0.0.1:8080          :::*                    LISTEN      25160/cloud-firesto

### snippet from ps axu:
user 25187 /usr/local/bin/firebase /home/.cache/firebase/emulators/ui-v1.1.1/server.bundle.js
...
user 25160 /home/.cache/firebase/emulators/cloud-firestore-emulator-v1.11.7.jar --launcher_javabase=/usr/local/buildtools/java/jdk11 -Duser.language=en run --host localhost --port 8080 --rules /home/firestore.rules

有什么想法吗? ...或其他有关如何测试我的主要功能(使用Firestore作为后端)的想法?

1 个答案:

答案 0 :(得分:0)

简短的回答:执行exec不会终止子进程。此处有更多详细信息:Why won't Go kill a child process correctly?

根据here中的建议,我决定使用:

firebase emulators:exec "go test"

这将在测试完成后正确清除模拟器。