我正在创建一些简单的应用程序来学习Firestore。
我通过以下方式启动了本地Firestore模拟器:
$ gcloud beta仿真器firestore启动
启动模拟器后,我使用“ go test”进行测试
我在Firestore中填充了数据,并创建了一个函数来查询添加的某些记录/文档。
我从我的应用程序中删除了一些文档,但是它们继续显示在查询中。
我尝试过:
以ctrl-c和ctrl d停止
$ gcloud beta仿真器firestore停止
重新启动了Macbook,但文档仍然存在。
我不了解重新启动计算机后数据存储的持久性,我猜测数据存储在JSON文件或类似的文件中。
我进行了搜索,但无法在模拟器上找到任何文档。
我应该启动仿真器,然后针对仿真的Firestore运行测试吗?
如何冲洗Firestore?
答案 0 :(得分:2)
模拟器支持终结点来清除数据库(docs):
curl -v -X DELETE "http://localhost:PORT/emulator/v1/projects/PROJECT_NAME/databases/(default)/documents"
填写PORT
和PROJECT_NAME
。
答案 1 :(得分:1)
您可以使用此:
module.exports.teardown = async () => {
Promise.all(firebase.apps().map(app => app.delete()));
};
现在,每次调用teardown
时,您将从Firestore模拟器中删除所有数据。
答案 2 :(得分:1)
由于您使用的是 Go,这里有一个我实现的小测试助手,它有助于启动模拟器、等待它出现、清除现有数据、初始化客户端以及在完成后关闭操作符。< /p>
它使用了 Juan 答案中的技巧(您应该将其标记为答案)。
要使用此实用程序,您只需说:
client := startFirestoreEmulator(t)
源代码:
// Copyright 2021 Ahmet Alp Balkan
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package firestoretestutil contains test utilities for starting a firestore
// emulator locally for unit tests.
package firestoretestutil
import (
"bytes"
"context"
"fmt"
"net"
"net/http"
"os"
"os/exec"
"sync"
"testing"
"time"
firestore "cloud.google.com/go/firestore"
)
const firestoreEmulatorProj = "dummy-emulator-firestore-project"
// cBuffer is a buffer safe for concurrent use.
type cBuffer struct {
b bytes.Buffer
sync.Mutex
}
func (c *cBuffer) Write(p []byte) (n int, err error) {
c.Lock()
defer c.Unlock()
return c.b.Write(p)
}
func StartEmulator(t *testing.T, ctx context.Context) *firestore.Client {
t.Helper()
port := "8010"
addr := "localhost:" + port
ctx, cancel := context.WithCancel(ctx)
t.Cleanup(func() {
t.Log("shutting down firestore operator")
cancel()
})
// TODO investigate why there are still java processes hanging around
// despite we kill the exec'd command, suspecting /bin/bash wrapper that gcloud
// applies around the java process.
cmd := exec.CommandContext(ctx, "gcloud", "beta", "emulators", "firestore", "start", "--host-port="+addr)
out := &cBuffer{b: bytes.Buffer{}}
cmd.Stderr, cmd.Stdout = out, out
if err := cmd.Start(); err != nil {
t.Fatalf("failed to start firestore emulator: %v -- out:%s", err, out.b.String())
}
dialCtx, clean := context.WithTimeout(ctx, time.Second*10)
defer clean()
var connected bool
for !connected {
select {
case <-dialCtx.Done():
t.Fatalf("emulator did not come up timely: %v -- output: %s", dialCtx.Err(), out.b.String())
default:
c, err := (&net.Dialer{Timeout: time.Millisecond * 200}).DialContext(ctx, "tcp", addr)
if err == nil {
c.Close()
t.Log("firestore emulator started")
connected = true
break
}
time.Sleep(time.Millisecond * 200) //before retrying
}
}
os.Setenv("FIRESTORE_EMULATOR_HOST", addr)
cl, err := firestore.NewClient(ctx, firestoreEmulatorProj)
if err != nil {
t.Fatal(err)
}
os.Unsetenv("FIRESTORE_EMULATOR_HOST")
truncateDB(t, addr)
return cl
}
func truncateDB(t *testing.T, addr string) {
t.Helper()
// technique adopted from https://stackoverflow.com/a/58866194/54929
req, _ := http.NewRequest(http.MethodDelete, fmt.Sprintf("http://%s/emulator/v1/projects/%s/databases/(default)/documents",
addr, firestoreEmulatorProj), nil)
resp, err := http.DefaultClient.Do(req)
if err != nil {
t.Fatal(err)
}
if resp.StatusCode != http.StatusOK {
t.Fatalf("failed to clear db: %v", resp.Status)
}
}