Trying to write a test for a goal_rule, the rule u...
# plugins
p
Trying to write a test for a goal_rule, the rule uses the workspace.write_digest(...) api, I want to be able to pass a tmpdir to it so the test writes the files the rule generate to a know temporary location (tmpdir is a fixture provided by pytest). However, it seems that Workspace.write_digest expects a relative path, which makes sense in non-test scenarios, but probably a bad idea to write stuff to places under the chroot when running a test. I have looked at https://www.pantsbuild.org/v2.2/docs/rules-api-testing#testing-goal_rules but I haven't found any docs/tips about having workspace.write_digest() run and asserting on the result of that. Any ideas/workarounds ?
e
Are you using RuleRunner for this? If so it already creates a tmpdir build root so all writes will be relative to that tmpdir build root and not the real build root.
👍 1
p
yes. just like the docs suggest: https://www.pantsbuild.org/v2.2/docs/rules-api-testing#how-to-mock-some-common-types (I am using it to create the workspace that gets passed to
run_rule_with_mocks
That's one example of doing this in a test and not polluting and real build root.
p
ah! got it, so grab
rule_runner.build_root
in order to assert that stuff has been written to the correct location. and that location is already a temporary location so I don't have to worry about cleaning it up, right ?
h
Exactly
p
so the rule uses
digest = await Get(Digest, CreateDigest([FileContent(path=fn, content=bytes_data])))
to get/create the digest that will be passed to the
workspace.write_digest()
api. However, when calling run_rule_with_mocks I am passing a MockGet that looks like this:
MockGet(output_type=Digest, input_type=CreateDigest, mock=lambda fc: EMPTY_DIGEST)
which means that the an empty digest is returned and nothing gets written, how do I create an actual digest ? Since in this case I want an actual digest or digest like object to be created.
h
(I think) you can use
rule_runner.request(Digest, [CreateDigest([FileContent(..)]))
to get a
Digest
object, then use that in your
MockGet
I think that should work. Although, what’s the motivation for using
run_rule_with_mocks
? Often
rule_runner.run_goal_rule
is better and more integration-y.
p
I am setting up my rule runner this way:
runner = RuleRunner(rules=[QueryRule(Digest, [CreateDigest])])
however I still get an error... what am I doing wrong?
h
Your rule registration is correct, but you’re probably not calling
rule_runner.request()
the right way - are you saying
rule_runner.request(Digest, [FileContent()]
by chance, without the wrapping
CreateDigest()
?
p
Copy code
def mock_create_digest(fc):
            return runner.request(Digest, fc)
this is the function (mock) I pass to MockGet:
MockGet(output_type=Digest, input_type=CreateDigest, mock=mock_create_digest)
h
yeah change that to
runner.request(Digest, [CreateDigest([fc])])
p
yup. that was it. doing.
runner.request(Digest, [fc])
fixed i.t
h
hm really? I wouldn’t expect there to be a rule to go from
FileContent -> Digest
. It should need the wrapping
CreateDigest()