Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow building and testing the "go-jsonnet" project with Bazel #281

Merged
merged 11 commits into from
Jun 14, 2019

Conversation

seh
Copy link
Contributor

@seh seh commented May 26, 2019

In order to more easily facilitate use of the Go port of the jsonnet tool—instead of the C++ port—from consuming projects like rules_jsonnet, allow this project to be built with Bazel.

There are a few concessions introduced here:

  • Generate the standard library AST into a dedicated package (astgen)
    Doing so breaks a circular dependency otherwise caused by generating this source file into the ast package.
  • Export all the fields in the struct types exported from the ast package
    Writing the dumped struct initializers into the astgen package requires being able to mention the struct fields defined in the ast package from a separate package (astgen).
  • Install the standard library AST into the ast package explicitly
    The AST generated in the astgen package is made available to programs that import it, but it doesn't automatically set this AST as the one used by the ast package. Doing so is possible in an init function in the generated in the astgen package, but setting it up automatically there felt too mysterious. Instead, do it explicitly where necessary: in the jsonnet tool and in the test package that uses it.
  • Make fewer assumptions about the right file paths needed by the dumpstdlibast program
    When running the program with Bazel, both its input file path and its output file path differ from the seemingly more obvious paths used when invoking it outside of Bazel.
  • Make fewer assumptions about the include file paths used in the c-bindings program
    When building with Bazel, the include file paths are different from the paths used when building outside of Bazel. Use the cgo directives to accommodate both environments.

@seh seh force-pushed the build-with-bazel branch from 56d6471 to 542296f Compare May 26, 2019 21:16
@seh
Copy link
Contributor Author

seh commented May 26, 2019

I see that a few tests failed in the Travis CI build, but they pass for me locally:

% go test ./...
ok  	github.com/google/go-jsonnet	0.296s
?   	github.com/google/go-jsonnet/ast	[no test files]
?   	github.com/google/go-jsonnet/astgen	[no test files]
?   	github.com/google/go-jsonnet/c-bindings	[no test files]
?   	github.com/google/go-jsonnet/cmd/dumpstdlibast	[no test files]
ok  	github.com/google/go-jsonnet/cmd/jsonnet	(cached)
ok  	github.com/google/go-jsonnet/dump	(cached)
?   	github.com/google/go-jsonnet/linter	[no test files]
?   	github.com/google/go-jsonnet/linter/jsonnet-lint	[no test files]
ok  	github.com/google/go-jsonnet/parser	(cached)

% bazel test //...
INFO: Analyzed 19 targets (2 packages loaded, 16 targets configured).
INFO: Found 15 targets and 4 test targets...
INFO: Elapsed time: 2.286s, Critical Path: 1.82s
INFO: 29 processes: 29 darwin-sandbox.
INFO: Build completed successfully, 33 total actions
//:go_default_test                                              (cached) PASSED in 0.6s
//cmd/jsonnet:go_default_test                                            PASSED in 0.1s
//dump:go_default_test                                                   PASSED in 0.1s
//parser:go_default_test                                                 PASSED in 0.1s

Executed 3 out of 4 tests: 4 tests pass.
There were tests whose specified size is too big. Use the --test_verbose_timeout_warnings command line option to see which oneINFO: Build completed successfully, 33 total actions

What's different about the Travis CI testing environment?

@seh seh force-pushed the build-with-bazel branch from 542296f to 34cad63 Compare May 26, 2019 21:44
@seh
Copy link
Contributor Author

seh commented May 26, 2019

I fixed the c-bindings tests; they were missing the standard library AST being in place.

The problem with the file paths in the normal Jsonnet tests may be due to a difference between macOS and Linux. I'll probably have to wait until Tuesday to explore the differences on another computer.

main_test.go Outdated
@@ -402,22 +412,42 @@ func expandEscapedFilenames(t *testing.T) error {
return string([]byte{byte(code)})
})
if file != input {
if err := os.Link(input, file); err != nil {
link := filepath.Join(dstDir, file[9:]) // Strip "testdata/" prefix.
Copy link
Collaborator

@sbarzowski sbarzowski May 28, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part was already quite hacky and now it seems way too complicated for what it does (we are testing imports with weird filenames, which we can't even keep in the repo, because that causes trouble on Windows). Perhaps we can make it simpler by always making a symbolic link or even a copy of the file instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Funny, I did start writing a version of this that copies the files, and bumped into that unusual lack of a "copy file" procedure in the Go standard library. I went off reading about the various ways to copy files, shook my head, then went back to making the links work.

Since these files are all rather small, copying the files "the easy way" (ioutil.ReadFile to ioutil.WriteFile) should work well enough.

That wasn't the only challenge, though. The golden output files with error messages inside contain an expected file path. Making the actual output match that closely enough required yet more munging.

@sbarzowski
Copy link
Collaborator

Thank you!

I haven't read it very carefully yet, but so far it looks good to me.

The problem with the file paths in the normal Jsonnet tests may be due to a difference between macOS and Linux. I'll probably have to wait until Tuesday to explore the differences on another computer.

What is the problem?

@seh
Copy link
Contributor Author

seh commented May 28, 2019

What is the problem?

It looks to me like the tests running on Linux can't find the symbolic links created for the import_various_literals_escaped.jsonnet and importstr_various_literals_escaped.jsonnet files. It's hard to decipher the error messages as they show up in the Travis CI view, because they're color-coded diffs that are only easy enough to tease apart when you have a very clear idea of what each side says.

I hope to experiment with this more this afternoon, with access to a computer running Linux.

@seh
Copy link
Contributor Author

seh commented May 28, 2019

I spent a while on a computer running Linux trying different approaches to getting the tests that involve linked files to work. I'm down to this problem: In import_various_literals_escaped.jsonnet, there are four import statements. The third one is supposed to fail, given the content of the corresponding %22.golden file:

testdata/":2:1 Unexpected end of file.

However, since the linked ".jsonnet file is sitting in a different directory, the error message printed by the interpreter contains that absolute path:

/tmp/".jsonnet:2:1 Unexpected end of file.

In other cases I've been able to adjust the "name" of the test case to get this file path mentioned in the error message to match the path in the "golden" file, but those cases are where the error message is mentioning the top-level file path. Here, the error message is mentioning an imported path, not the top-level path.

I could scrub the resulting error message, mapping the temporary test directory to the relative testdata path if the test fails with an error and the output has the temporary test directory path as its prefix. That seems rather hacky. Can you think of any other approaches to try?

Do we need these escaped file names because the repository can't even be checked out on a computer running Windows? I see that we skip linking these files when running on Windows, and don't try to read the percent-named files. We could avoid a lot of trouble here if we could get away with at least storing the files with the intended names in the repository.

@sbarzowski
Copy link
Collaborator

The third one is supposed to fail, given the content of the corresponding %22.golden file:
No, it's not supposed to fail, something went wrong and nobody noticed.

It happened in this change.
c345915

Testing this stuff is a massive time sink. Maybe at this point we should just get rid of it. Later perhaps we can add a unit test or something. It someone has a " in the filename and something breaks that's kinda on them. I mean we could just delete lines 4-5 here: https://github.com/google/go-jsonnet/blob/v0.12.1/testdata/import_various_literals_escaped.jsonnet#L4 and then expandEscapedFilenames wouldn't be necessary.

What do you think?

@seh
Copy link
Contributor Author

seh commented May 29, 2019

First, I appreciate you recognizing the difficulty of making these tests work. I still haven't figured out why they work on macOS, but don't work on Linux. Knowing what I know now, I'd expect them to fail in both environments.

I think it may be possible to test these special cases, but not as we're doing it now with these encoded file names. Instead we may be able to dedicate a separate test function for them, where we're not reading Jsonnet/golden file pairs from the repository, but where we instead write out Jsonnet code defined in the program source to the oddly-named files and compare the evaluation result to "golden" expectations also defined in the program source. That would avoid the current awkward need to leave some existing files in place, but write either links or copies into a different directory, which makes the paths that appear in the evaluation errors more difficult to predict.

It would help if you could clarify your note that the expected failure in the %22.golden file may be wrong. Does the content of that file need to change? Was its change in c345915 a mistake?

@sbarzowski
Copy link
Collaborator

sbarzowski commented May 29, 2019

Ah, actually it wasn't c345915. I don't know what I saw yesterday, but right now it seems like this test was slightly broken from the beginning. It was never intended to fail with "unexpected end of file".

I agree that what you described would be a better approach to testing these things.

For now I've just fixed the error in #283, so that there is no stack trace and no problematic paths in the output. That should solve our problem here.

@seh seh force-pushed the build-with-bazel branch from 34cad63 to 1032ce4 Compare June 1, 2019 19:07
@coveralls
Copy link

coveralls commented Jun 1, 2019

Coverage Status

Coverage increased (+4.0%) to 77.371% when pulling 0674949 on seh:build-with-bazel into 1c89ed8 on google:master.

@seh seh force-pushed the build-with-bazel branch from 1032ce4 to 7bf5c5e Compare June 1, 2019 19:17
@seh
Copy link
Contributor Author

seh commented Jun 1, 2019

@sbarzowski, please take another look. I separated the unit test cases for the special filenames (".jsonnet and '.jsonnet) into a dedicated test (called TestEvalUnusualFilenames, but I'm amenable to other suggestions) that writes these files into a scratch directory, changes the working directory to that scratch directory, and runs a few round-trip evaluation tests there.

Travis CI appears to be happy with it, and as far as I can prove here, it builds with both go build and bazel build, and the tests run successfully with both go test and bazel test.

@seh
Copy link
Contributor Author

seh commented Jun 1, 2019

One annoyance: If you use go build to build the c-bindings/c-bindings program, cgo generates the c-bindings/libgojsonnet.h file in that directory. If you then run bazel run //:gazelle, Gazelle will add this libgojsonnet.h file to the "go_default_library" target's "srcs" list in the c-bindings/BUILD.bazel file, because Gazelle found that file now sitting in that directory.

Say that you commit that change to the BUILD.bazel file. It now references a generated file—one nominated in c-bindings/.gitignore—that won't be there in a fresh checkout. The next time you run bazel build //c-bindings, it will fail, because the BUILD.bazel file says that c-bindings/libgojsonnet.h is a required dependency, but it doesn't exist; it won't exist in that directory until we run go build again.

I looked for a way to tell Gazelle to not add a particular file to the "srcs" attribute there. The best we could do is to annotate the entire "srcs" list with a # keep comment, which will prevent Gazelle from changing it all in the future. That trades the annoyance of Gazelle adding this entry for us then taking full responsibility for keeping the "srcs" attribute up to date. For now I chose to accept the annoyance.

main_test.go Show resolved Hide resolved
for _, f := range []string{"true"} {
for _, ext := range []string{".jsonnet"} {
name := f + ext
copySmallFile(t, filepath.Join(dir, name), filepath.Join("testdata", name))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that I considered trying to run these evaluation tests using just in-memory content, avoiding the filesystem, but two things motivated doing it with files instead:

  • We can reuse the runTest function, which assumes that it will use files as input.
  • We'd have to rig up our own Importer to handle the test cases where the top-level input file imports another one of these files.
    Writing just the true.jsonnet file probably would have been sufficient to cover this need, but the first motivation argued against duplicating or factoring the common parts from the runTests function.

Let me know if you'd prefer that we just process in-memory content here.

@seh seh force-pushed the build-with-bazel branch from 7bf5c5e to 6d03e0c Compare June 2, 2019 13:40
@seh seh mentioned this pull request Jun 3, 2019
@seh seh force-pushed the build-with-bazel branch from 6d03e0c to 12ce4b2 Compare June 3, 2019 19:08
@sbarzowski
Copy link
Collaborator

I like the changes.

I tried on my machine and it seems to be working nicely. Though at some point, when I used bazel-compiled Jsonnet with cpp-jsonnet tests, I had two bizarre test failures which disappeared when I tried to debug them and I was unable to reproduce them from a clean state, so probably it was something with my setup.

Later we'll need to test bazel-built Jsonnet in CI, but I feel like this change is already big enough.

@sparkprime Do you want to take a look, or should I just merge this?

@seh
Copy link
Contributor Author

seh commented Jun 10, 2019

@sparkprime, do you have any feedback? Can we proceed with merging?

Steve Harris added 5 commits June 10, 2019 16:10
Export all fields in struct types in the "ast" package to allow
generating program source to reconstruct their complete values in a
separate package.
@seh seh force-pushed the build-with-bazel branch from 12ce4b2 to 0674949 Compare June 10, 2019 20:15
@sparkprime
Copy link
Contributor

I had a quick read and LGTM. Thanks for all the unrelated yak shaving you did here!

@sbarzowski sbarzowski merged commit 7614fd5 into google:master Jun 14, 2019
@sbarzowski
Copy link
Collaborator

Hmmm... it looks unrelated to this change, but after merging this we got a failure when running CI on master on Go tip. It fails when running go get for a dependency, before we even run any of our code. I retriggered the TravisCI job and it failed again. It happens only on Go tip (latest release works fine) and it probably has something to do with some changes related to $GOPATH and modules.

@seh
Copy link
Contributor Author

seh commented Jun 15, 2019

gocov isn't mentioned in the go.mod or go.sum file, but I see that we pull it with go get here in .travis.yml.

Searching for that error message leads only back to the source file that emits it. I don't find other people complaining about it (yet).

@seh
Copy link
Contributor Author

seh commented Jun 15, 2019

I'm unable to reproduce the error locally on macOS using Go version 1.12.6.

@seh
Copy link
Contributor Author

seh commented Jun 15, 2019

Given that gimme is using the current tip version, I wonder if golang/go@4c2ffd2 may be related. It's the only recent commit I see there that sounds like it could be involved.

@seh
Copy link
Contributor Author

seh commented Jul 1, 2019

See bazel-contrib/rules_jsonnet#113 for a proposed use of these Bazel targets.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants