diff --git a/ci/release/docker/Dockerfile b/ci/release/docker/Dockerfile index 33acac831..0d7789a26 100644 --- a/ci/release/docker/Dockerfile +++ b/ci/release/docker/Dockerfile @@ -7,8 +7,7 @@ RUN apt-get update && apt-get install -y ca-certificates curl dumb-init sudo RUN curl -fsSL https://deb.nodesource.com/setup_19.x | bash -s - && \ apt-get install -y nodejs -# See https://github.com/microsoft/playwright/issues/18319 -RUN npx playwright@1.31.1 install-deps chromium +RUN npx playwright@1.31.1 install --with-deps chromium RUN adduser --gecos '' --disabled-password debian \ && echo "debian ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/nopasswd diff --git a/ci/test.sh b/ci/test.sh index da523b72d..f7d92a6de 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -8,5 +8,6 @@ fi if [ "${CI:-}" ]; then export FORCE_COLOR=1 + npx playwright@1.31.1 install --with-deps chromium fi go test --timeout=30m "$@" diff --git a/d2cli/main.go b/d2cli/main.go index 11f534569..a96277ce3 100644 --- a/d2cli/main.go +++ b/d2cli/main.go @@ -152,6 +152,12 @@ func Run(ctx context.Context, ms *xmain.State) (err error) { outputPath = renameExt(inputPath, ".svg") } } + inputPath = filepath.Join(ms.PWD, inputPath) + d, err := os.Stat(inputPath) + if err == nil && d.IsDir() { + inputPath = filepath.Join(inputPath, "index.d2") + } + outputPath = filepath.Join(ms.PWD, outputPath) match := d2themescatalog.Find(*themeFlag) if match == (d2themes.Theme{}) { diff --git a/e2etests-cli/main_test.go b/e2etests-cli/main_test.go index 22d88dac1..29529b867 100644 --- a/e2etests-cli/main_test.go +++ b/e2etests-cli/main_test.go @@ -2,20 +2,125 @@ package e2etests_cli import ( "context" + "os" + "path/filepath" "testing" "time" + + "oss.terrastruct.com/d2/d2cli" + "oss.terrastruct.com/util-go/assert" + "oss.terrastruct.com/util-go/diff" + "oss.terrastruct.com/util-go/xmain" + "oss.terrastruct.com/util-go/xos" ) func TestCLI_E2E(t *testing.T) { t.Parallel() tca := []struct { - name string - run func(t *testing.T, ctx context.Context) + name string + skipCI bool + run func(t *testing.T, ctx context.Context, dir string, env *xos.Env) }{ { - name: "hello_world", - run: func(t *testing.T, ctx context.Context) {}, + name: "hello_world_png", + skipCI: true, + run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) { + writeFile(t, dir, "hello-world.d2", `x -> y`) + err := runTestMain(t, ctx, dir, env, "hello-world.d2", "hello-world.png") + assert.Success(t, err) + png := readFile(t, dir, "hello-world.png") + testdataIgnoreDiff(t, ".png", png) + }, + }, + { + name: "hello_world_png_pad", + skipCI: true, + run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) { + writeFile(t, dir, "hello-world.d2", `x -> y`) + err := runTestMain(t, ctx, dir, env, "--pad=400", "hello-world.d2", "hello-world.png") + assert.Success(t, err) + png := readFile(t, dir, "hello-world.png") + testdataIgnoreDiff(t, ".png", png) + }, + }, + { + name: "hello_world_png_sketch", + skipCI: true, + run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) { + writeFile(t, dir, "hello-world.d2", `x -> y`) + err := runTestMain(t, ctx, dir, env, "--sketch", "hello-world.d2", "hello-world.png") + assert.Success(t, err) + png := readFile(t, dir, "hello-world.png") + // https://github.com/terrastruct/d2/pull/963#pullrequestreview-1323089392 + testdataIgnoreDiff(t, ".png", png) + }, + }, + { + name: "multiboard/life", + run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) { + writeFile(t, dir, "life.d2", `x -> y +layers: { + core: { + belief + food + diet + } + broker: { + mortgage + realtor + } + stocks: { + TSX + NYSE + NASDAQ + } +} + +scenarios: { + why: { + y -> x + } +} +`) + err := runTestMain(t, ctx, dir, env, "life.d2") + assert.Success(t, err) + + assert.TestdataDir(t, filepath.Join(dir, "life")) + }, + }, + { + name: "multiboard/life_index_d2", + run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) { + writeFile(t, dir, "life/index.d2", `x -> y +layers: { + core: { + belief + food + diet + } + broker: { + mortgage + realtor + } + stocks: { + TSX + NYSE + NASDAQ + } +} + +scenarios: { + why: { + y -> x + } +} +`) + err := runTestMain(t, ctx, dir, env, "life") + assert.Success(t, err) + + assert.TestdataDir(t, filepath.Join(dir, "life")) + }, }, } @@ -25,10 +130,74 @@ func TestCLI_E2E(t *testing.T) { t.Run(tc.name, func(t *testing.T) { t.Parallel() + if tc.skipCI && os.Getenv("CI") != "" { + t.SkipNow() + } + ctx, cancel := context.WithTimeout(ctx, time.Minute*5) defer cancel() - tc.run(t, ctx) + dir, cleanup := assert.TempDir(t) + defer cleanup() + + env := xos.NewEnv(nil) + + tc.run(t, ctx, dir, env) }) } } + +// We do not run the CLI in its own process even though that makes it not truly e2e to +// test whether we're cleaning up state correctly. +func testMain(dir string, env *xos.Env, args ...string) *xmain.TestState { + return &xmain.TestState{ + Run: d2cli.Run, + Env: env, + Args: append([]string{"e2etests-cli/d2"}, args...), + PWD: dir, + } +} + +func runTestMain(tb testing.TB, ctx context.Context, dir string, env *xos.Env, args ...string) error { + tms := testMain(dir, env, args...) + tms.Start(tb, ctx) + defer tms.Cleanup(tb) + err := tms.Wait(ctx) + if err != nil { + return err + } + removeD2Files(tb, dir) + return nil +} + +func writeFile(tb testing.TB, dir, fp, data string) { + tb.Helper() + err := os.MkdirAll(filepath.Dir(filepath.Join(dir, fp)), 0755) + assert.Success(tb, err) + assert.WriteFile(tb, filepath.Join(dir, fp), []byte(data), 0644) +} + +func readFile(tb testing.TB, dir, fp string) []byte { + tb.Helper() + return assert.ReadFile(tb, filepath.Join(dir, fp)) +} + +func removeD2Files(tb testing.TB, dir string) { + ea, err := os.ReadDir(dir) + assert.Success(tb, err) + + for _, e := range ea { + if e.IsDir() { + removeD2Files(tb, filepath.Join(dir, e.Name())) + continue + } + ext := filepath.Ext(e.Name()) + if ext == ".d2" { + assert.Remove(tb, filepath.Join(dir, e.Name())) + } + } +} + +func testdataIgnoreDiff(tb testing.TB, ext string, got []byte) { + _ = diff.Testdata(filepath.Join("testdata", tb.Name()), ext, got) +} diff --git a/e2etests-cli/testdata/TestCLI_E2E/hello_world_png.exp.png b/e2etests-cli/testdata/TestCLI_E2E/hello_world_png.exp.png new file mode 100644 index 000000000..613ca9a63 Binary files /dev/null and b/e2etests-cli/testdata/TestCLI_E2E/hello_world_png.exp.png differ diff --git a/e2etests-cli/testdata/TestCLI_E2E/hello_world_png_pad.exp.png b/e2etests-cli/testdata/TestCLI_E2E/hello_world_png_pad.exp.png new file mode 100644 index 000000000..296288588 Binary files /dev/null and b/e2etests-cli/testdata/TestCLI_E2E/hello_world_png_pad.exp.png differ diff --git a/e2etests-cli/testdata/TestCLI_E2E/hello_world_png_sketch.exp.png b/e2etests-cli/testdata/TestCLI_E2E/hello_world_png_sketch.exp.png new file mode 100644 index 000000000..bef8fb071 Binary files /dev/null and b/e2etests-cli/testdata/TestCLI_E2E/hello_world_png_sketch.exp.png differ diff --git a/e2etests-cli/testdata/TestCLI_E2E/multiboard/life/index.exp.svg b/e2etests-cli/testdata/TestCLI_E2E/multiboard/life/index.exp.svg new file mode 100644 index 000000000..4787423c1 --- /dev/null +++ b/e2etests-cli/testdata/TestCLI_E2E/multiboard/life/index.exp.svg @@ -0,0 +1,23 @@ +xy + + + diff --git a/e2etests-cli/testdata/TestCLI_E2E/multiboard/life/layers/broker.exp.svg b/e2etests-cli/testdata/TestCLI_E2E/multiboard/life/layers/broker.exp.svg new file mode 100644 index 000000000..adaadb7a2 --- /dev/null +++ b/e2etests-cli/testdata/TestCLI_E2E/multiboard/life/layers/broker.exp.svg @@ -0,0 +1,23 @@ +mortgagerealtor + + + diff --git a/e2etests-cli/testdata/TestCLI_E2E/multiboard/life/layers/core.exp.svg b/e2etests-cli/testdata/TestCLI_E2E/multiboard/life/layers/core.exp.svg new file mode 100644 index 000000000..c3aac3445 --- /dev/null +++ b/e2etests-cli/testdata/TestCLI_E2E/multiboard/life/layers/core.exp.svg @@ -0,0 +1,23 @@ +belieffooddiet + + + diff --git a/e2etests-cli/testdata/TestCLI_E2E/multiboard/life/layers/stocks.exp.svg b/e2etests-cli/testdata/TestCLI_E2E/multiboard/life/layers/stocks.exp.svg new file mode 100644 index 000000000..bbfda5151 --- /dev/null +++ b/e2etests-cli/testdata/TestCLI_E2E/multiboard/life/layers/stocks.exp.svg @@ -0,0 +1,23 @@ +TSXNYSENASDAQ + + + diff --git a/e2etests-cli/testdata/TestCLI_E2E/multiboard/life/scenarios/why.exp.svg b/e2etests-cli/testdata/TestCLI_E2E/multiboard/life/scenarios/why.exp.svg new file mode 100644 index 000000000..e5ed30e0c --- /dev/null +++ b/e2etests-cli/testdata/TestCLI_E2E/multiboard/life/scenarios/why.exp.svg @@ -0,0 +1,23 @@ +xy + + + diff --git a/e2etests-cli/testdata/TestCLI_E2E/multiboard/life_index_d2/index.exp.svg b/e2etests-cli/testdata/TestCLI_E2E/multiboard/life_index_d2/index.exp.svg new file mode 100644 index 000000000..4787423c1 --- /dev/null +++ b/e2etests-cli/testdata/TestCLI_E2E/multiboard/life_index_d2/index.exp.svg @@ -0,0 +1,23 @@ +xy + + + diff --git a/e2etests-cli/testdata/TestCLI_E2E/multiboard/life_index_d2/layers/broker.exp.svg b/e2etests-cli/testdata/TestCLI_E2E/multiboard/life_index_d2/layers/broker.exp.svg new file mode 100644 index 000000000..adaadb7a2 --- /dev/null +++ b/e2etests-cli/testdata/TestCLI_E2E/multiboard/life_index_d2/layers/broker.exp.svg @@ -0,0 +1,23 @@ +mortgagerealtor + + + diff --git a/e2etests-cli/testdata/TestCLI_E2E/multiboard/life_index_d2/layers/core.exp.svg b/e2etests-cli/testdata/TestCLI_E2E/multiboard/life_index_d2/layers/core.exp.svg new file mode 100644 index 000000000..c3aac3445 --- /dev/null +++ b/e2etests-cli/testdata/TestCLI_E2E/multiboard/life_index_d2/layers/core.exp.svg @@ -0,0 +1,23 @@ +belieffooddiet + + + diff --git a/e2etests-cli/testdata/TestCLI_E2E/multiboard/life_index_d2/layers/stocks.exp.svg b/e2etests-cli/testdata/TestCLI_E2E/multiboard/life_index_d2/layers/stocks.exp.svg new file mode 100644 index 000000000..bbfda5151 --- /dev/null +++ b/e2etests-cli/testdata/TestCLI_E2E/multiboard/life_index_d2/layers/stocks.exp.svg @@ -0,0 +1,23 @@ +TSXNYSENASDAQ + + + diff --git a/e2etests-cli/testdata/TestCLI_E2E/multiboard/life_index_d2/scenarios/why.exp.svg b/e2etests-cli/testdata/TestCLI_E2E/multiboard/life_index_d2/scenarios/why.exp.svg new file mode 100644 index 000000000..e5ed30e0c --- /dev/null +++ b/e2etests-cli/testdata/TestCLI_E2E/multiboard/life_index_d2/scenarios/why.exp.svg @@ -0,0 +1,23 @@ +xy + + + diff --git a/go.mod b/go.mod index 34b2a85ea..a3d90206c 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 gonum.org/v1/plot v0.12.0 nhooyr.io/websocket v1.8.7 - oss.terrastruct.com/util-go v0.0.0-20230301015829-35b30391c74d + oss.terrastruct.com/util-go v0.0.0-20230303051516-f04d4d93bed8 ) require ( diff --git a/go.sum b/go.sum index 4c1b4fb99..f7c198223 100644 --- a/go.sum +++ b/go.sum @@ -277,6 +277,6 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= -oss.terrastruct.com/util-go v0.0.0-20230301015829-35b30391c74d h1:+1Bp2bYA7bieedJuqbiwOLhnMs6GQQLB4sNX7BcDbSQ= -oss.terrastruct.com/util-go v0.0.0-20230301015829-35b30391c74d/go.mod h1:Fwy72FDIOOM4K8F96ScXkxHHppR1CPfUyo9+x9c1PBU= +oss.terrastruct.com/util-go v0.0.0-20230303051516-f04d4d93bed8 h1:sXAJ18qH3RfrhvAo3YaGv1mDewEKV8etsFq1KqhbvIM= +oss.terrastruct.com/util-go v0.0.0-20230303051516-f04d4d93bed8/go.mod h1:eMWv0sOtD9T2RUl90DLWfuShZCYp4NrsqNpI8eqO6U4= rsc.io/pdf v0.1.1 h1:k1MczvYDUvJBe93bYd7wrZLLUEcLZAuF824/I4e5Xr4=