diff options
author | Dan Willemsen <dwillemsen@google.com> | 2019-04-12 11:11:38 -0700 |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2019-11-21 14:47:46 -0800 |
commit | 0ce5d05f76989c4cc699e0dd6cd1f906a9e0f16d (patch) | |
tree | e0cc48f7aafafdb8ccda16d55e124800da9e1f16 /android/rule_builder_test.go | |
parent | 51510a887743de47acc6f0e52ddc1e527d5bf3ab (diff) | |
download | android_build_soong-0ce5d05f76989c4cc699e0dd6cd1f906a9e0f16d.tar.gz android_build_soong-0ce5d05f76989c4cc699e0dd6cd1f906a9e0f16d.tar.bz2 android_build_soong-0ce5d05f76989c4cc699e0dd6cd1f906a9e0f16d.zip |
Support RuleBuilder.Sbox to wrap commands in sbox
This essentially allows you to declare that everything in a directory
will be created by the rule, and we'll ensure that your command actually
writes out all of the claimed outputs, and remove any other files that
previously existed in that directory.
Bug: 144948629
Test: built-in tests
Change-Id: I990dce2b3a0d89ebd2736ac1a0cadfb5864c6e73
Merged-In: I990dce2b3a0d89ebd2736ac1a0cadfb5864c6e73
(cherry picked from commit 633c50229544db07f48e75833cab655a294f677d)
Diffstat (limited to 'android/rule_builder_test.go')
-rw-r--r-- | android/rule_builder_test.go | 237 |
1 files changed, 165 insertions, 72 deletions
diff --git a/android/rule_builder_test.go b/android/rule_builder_test.go index 7bad0258..df0f2564 100644 --- a/android/rule_builder_test.go +++ b/android/rule_builder_test.go @@ -22,6 +22,10 @@ import ( "reflect" "strings" "testing" + + "github.com/google/blueprint" + + "android/soong/shared" ) func pathContext() PathContext { @@ -234,8 +238,6 @@ func ExampleRuleBuilderCommand_FlagWithList() { } func TestRuleBuilder(t *testing.T) { - rule := NewRuleBuilder() - fs := map[string][]byte{ "dep_fixer": nil, "input": nil, @@ -249,73 +251,114 @@ func TestRuleBuilder(t *testing.T) { ctx := PathContextForTesting(TestConfig("out", nil), fs) - cmd := rule.Command(). - DepFile(PathForOutput(ctx, "DepFile")). - Flag("Flag"). - FlagWithArg("FlagWithArg=", "arg"). - FlagWithDepFile("FlagWithDepFile=", PathForOutput(ctx, "depfile")). - FlagWithInput("FlagWithInput=", PathForSource(ctx, "input")). - FlagWithOutput("FlagWithOutput=", PathForOutput(ctx, "output")). - Implicit(PathForSource(ctx, "Implicit")). - ImplicitDepFile(PathForOutput(ctx, "ImplicitDepFile")). - ImplicitOutput(PathForOutput(ctx, "ImplicitOutput")). - Input(PathForSource(ctx, "Input")). - Output(PathForOutput(ctx, "Output")). - Text("Text"). - Tool(PathForSource(ctx, "Tool")) - - rule.Command(). - Text("command2"). - DepFile(PathForOutput(ctx, "depfile2")). - Input(PathForSource(ctx, "input2")). - Output(PathForOutput(ctx, "output2")). - Tool(PathForSource(ctx, "tool2")) - - // Test updates to the first command after the second command has been started - cmd.Text("after command2") - // Test updating a command when the previous update did not replace the cmd variable - cmd.Text("old cmd") - - // Test a command that uses the output of a previous command as an input - rule.Command(). - Text("command3"). - Input(PathForSource(ctx, "input3")). - Input(PathForOutput(ctx, "output2")). - Output(PathForOutput(ctx, "output3")) - - wantCommands := []string{ - "out/DepFile Flag FlagWithArg=arg FlagWithDepFile=out/depfile FlagWithInput=input FlagWithOutput=out/output Input out/Output Text Tool after command2 old cmd", - "command2 out/depfile2 input2 out/output2 tool2", - "command3 input3 out/output2 out/output3", + addCommands := func(rule *RuleBuilder) { + cmd := rule.Command(). + DepFile(PathForOutput(ctx, "DepFile")). + Flag("Flag"). + FlagWithArg("FlagWithArg=", "arg"). + FlagWithDepFile("FlagWithDepFile=", PathForOutput(ctx, "depfile")). + FlagWithInput("FlagWithInput=", PathForSource(ctx, "input")). + FlagWithOutput("FlagWithOutput=", PathForOutput(ctx, "output")). + Implicit(PathForSource(ctx, "Implicit")). + ImplicitDepFile(PathForOutput(ctx, "ImplicitDepFile")). + ImplicitOutput(PathForOutput(ctx, "ImplicitOutput")). + Input(PathForSource(ctx, "Input")). + Output(PathForOutput(ctx, "Output")). + Text("Text"). + Tool(PathForSource(ctx, "Tool")) + + rule.Command(). + Text("command2"). + DepFile(PathForOutput(ctx, "depfile2")). + Input(PathForSource(ctx, "input2")). + Output(PathForOutput(ctx, "output2")). + Tool(PathForSource(ctx, "tool2")) + + // Test updates to the first command after the second command has been started + cmd.Text("after command2") + // Test updating a command when the previous update did not replace the cmd variable + cmd.Text("old cmd") + + // Test a command that uses the output of a previous command as an input + rule.Command(). + Text("command3"). + Input(PathForSource(ctx, "input3")). + Input(PathForOutput(ctx, "output2")). + Output(PathForOutput(ctx, "output3")) } - wantDepMergerCommand := "out/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer out/DepFile out/depfile out/ImplicitDepFile out/depfile2" - wantInputs := PathsForSource(ctx, []string{"Implicit", "Input", "input", "input2", "input3"}) wantOutputs := PathsForOutput(ctx, []string{"ImplicitOutput", "Output", "output", "output2", "output3"}) wantDepFiles := PathsForOutput(ctx, []string{"DepFile", "depfile", "ImplicitDepFile", "depfile2"}) wantTools := PathsForSource(ctx, []string{"Tool", "tool2"}) - if g, w := rule.Commands(), wantCommands; !reflect.DeepEqual(g, w) { - t.Errorf("\nwant rule.Commands() = %#v\n got %#v", w, g) - } + t.Run("normal", func(t *testing.T) { + rule := NewRuleBuilder() + addCommands(rule) - if g, w := rule.depFileMergerCmd(ctx, rule.DepFiles()).String(), wantDepMergerCommand; g != w { - t.Errorf("\nwant rule.depFileMergerCmd() = %#v\n got %#v", w, g) - } + wantCommands := []string{ + "out/DepFile Flag FlagWithArg=arg FlagWithDepFile=out/depfile FlagWithInput=input FlagWithOutput=out/output Input out/Output Text Tool after command2 old cmd", + "command2 out/depfile2 input2 out/output2 tool2", + "command3 input3 out/output2 out/output3", + } - if g, w := rule.Inputs(), wantInputs; !reflect.DeepEqual(w, g) { - t.Errorf("\nwant rule.Inputs() = %#v\n got %#v", w, g) - } - if g, w := rule.Outputs(), wantOutputs; !reflect.DeepEqual(w, g) { - t.Errorf("\nwant rule.Outputs() = %#v\n got %#v", w, g) - } - if g, w := rule.DepFiles(), wantDepFiles; !reflect.DeepEqual(w, g) { - t.Errorf("\nwant rule.DepFiles() = %#v\n got %#v", w, g) - } - if g, w := rule.Tools(), wantTools; !reflect.DeepEqual(w, g) { - t.Errorf("\nwant rule.Tools() = %#v\n got %#v", w, g) - } + wantDepMergerCommand := "out/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer out/DepFile out/depfile out/ImplicitDepFile out/depfile2" + + if g, w := rule.Commands(), wantCommands; !reflect.DeepEqual(g, w) { + t.Errorf("\nwant rule.Commands() = %#v\n got %#v", w, g) + } + + if g, w := rule.Inputs(), wantInputs; !reflect.DeepEqual(w, g) { + t.Errorf("\nwant rule.Inputs() = %#v\n got %#v", w, g) + } + if g, w := rule.Outputs(), wantOutputs; !reflect.DeepEqual(w, g) { + t.Errorf("\nwant rule.Outputs() = %#v\n got %#v", w, g) + } + if g, w := rule.DepFiles(), wantDepFiles; !reflect.DeepEqual(w, g) { + t.Errorf("\nwant rule.DepFiles() = %#v\n got %#v", w, g) + } + if g, w := rule.Tools(), wantTools; !reflect.DeepEqual(w, g) { + t.Errorf("\nwant rule.Tools() = %#v\n got %#v", w, g) + } + + if g, w := rule.depFileMergerCmd(ctx, rule.DepFiles()).String(), wantDepMergerCommand; g != w { + t.Errorf("\nwant rule.depFileMergerCmd() = %#v\n got %#v", w, g) + } + }) + + t.Run("sbox", func(t *testing.T) { + rule := NewRuleBuilder().Sbox(PathForOutput(ctx)) + addCommands(rule) + + wantCommands := []string{ + "__SBOX_OUT_DIR__/DepFile Flag FlagWithArg=arg FlagWithDepFile=__SBOX_OUT_DIR__/depfile FlagWithInput=input FlagWithOutput=__SBOX_OUT_DIR__/output Input __SBOX_OUT_DIR__/Output Text Tool after command2 old cmd", + "command2 __SBOX_OUT_DIR__/depfile2 input2 __SBOX_OUT_DIR__/output2 tool2", + "command3 input3 __SBOX_OUT_DIR__/output2 __SBOX_OUT_DIR__/output3", + } + + wantDepMergerCommand := "out/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer __SBOX_OUT_DIR__/DepFile __SBOX_OUT_DIR__/depfile __SBOX_OUT_DIR__/ImplicitDepFile __SBOX_OUT_DIR__/depfile2" + + if g, w := rule.Commands(), wantCommands; !reflect.DeepEqual(g, w) { + t.Errorf("\nwant rule.Commands() = %#v\n got %#v", w, g) + } + + if g, w := rule.Inputs(), wantInputs; !reflect.DeepEqual(w, g) { + t.Errorf("\nwant rule.Inputs() = %#v\n got %#v", w, g) + } + if g, w := rule.Outputs(), wantOutputs; !reflect.DeepEqual(w, g) { + t.Errorf("\nwant rule.Outputs() = %#v\n got %#v", w, g) + } + if g, w := rule.DepFiles(), wantDepFiles; !reflect.DeepEqual(w, g) { + t.Errorf("\nwant rule.DepFiles() = %#v\n got %#v", w, g) + } + if g, w := rule.Tools(), wantTools; !reflect.DeepEqual(w, g) { + t.Errorf("\nwant rule.Tools() = %#v\n got %#v", w, g) + } + + if g, w := rule.depFileMergerCmd(ctx, rule.DepFiles()).String(), wantDepMergerCommand; g != w { + t.Errorf("\nwant rule.depFileMergerCmd() = %#v\n got %#v", w, g) + } + }) } func testRuleBuilderFactory() Module { @@ -329,14 +372,19 @@ type testRuleBuilderModule struct { ModuleBase properties struct { Src string + + Restat bool + Sbox bool } } func (t *testRuleBuilderModule) GenerateAndroidBuildActions(ctx ModuleContext) { in := PathForSource(ctx, t.properties.Src) out := PathForModuleOut(ctx, ctx.ModuleName()) + outDep := PathForModuleOut(ctx, ctx.ModuleName()+".d") + outDir := PathForModuleOut(ctx) - testRuleBuilder_Build(ctx, in, out) + testRuleBuilder_Build(ctx, in, out, outDep, outDir, t.properties.Restat, t.properties.Sbox) } type testRuleBuilderSingleton struct{} @@ -348,15 +396,23 @@ func testRuleBuilderSingletonFactory() Singleton { func (t *testRuleBuilderSingleton) GenerateBuildActions(ctx SingletonContext) { in := PathForSource(ctx, "bar") out := PathForOutput(ctx, "baz") - testRuleBuilder_Build(ctx, in, out) + outDep := PathForOutput(ctx, "baz.d") + outDir := PathForOutput(ctx) + testRuleBuilder_Build(ctx, in, out, outDep, outDir, true, false) } -func testRuleBuilder_Build(ctx BuilderContext, in Path, out WritablePath) { +func testRuleBuilder_Build(ctx BuilderContext, in Path, out, outDep, outDir WritablePath, restat, sbox bool) { rule := NewRuleBuilder() - rule.Command().Tool(PathForSource(ctx, "cp")).Input(in).Output(out) + if sbox { + rule.Sbox(outDir) + } + + rule.Command().Tool(PathForSource(ctx, "cp")).Input(in).Output(out).ImplicitDepFile(outDep) - rule.Restat() + if restat { + rule.Restat() + } rule.Build(pctx, ctx, "rule", "desc") } @@ -372,6 +428,12 @@ func TestRuleBuilder_Build(t *testing.T) { rule_builder_test { name: "foo", src: "bar", + restat: true, + } + rule_builder_test { + name: "foo_sbox", + src: "bar", + sbox: true, } ` @@ -391,9 +453,18 @@ func TestRuleBuilder_Build(t *testing.T) { _, errs = ctx.PrepareBuildActions(config) FailIfErrored(t, errs) - check := func(t *testing.T, params TestingBuildParams, wantOutput string) { - if len(params.RuleParams.CommandDeps) != 1 || params.RuleParams.CommandDeps[0] != "cp" { - t.Errorf("want RuleParams.CommandDeps = [%q], got %q", "cp", params.RuleParams.CommandDeps) + check := func(t *testing.T, params TestingBuildParams, wantCommand, wantOutput, wantDepfile string, wantRestat bool, extraCmdDeps []string) { + if params.RuleParams.Command != wantCommand { + t.Errorf("\nwant RuleParams.Command = %q\n got %q", wantCommand, params.RuleParams.Command) + } + + wantDeps := append([]string{"cp"}, extraCmdDeps...) + if !reflect.DeepEqual(params.RuleParams.CommandDeps, wantDeps) { + t.Errorf("\nwant RuleParams.CommandDeps = %q\n got %q", wantDeps, params.RuleParams.CommandDeps) + } + + if params.RuleParams.Restat != wantRestat { + t.Errorf("want RuleParams.Restat = %v, got %v", wantRestat, params.RuleParams.Restat) } if len(params.Implicits) != 1 || params.Implicits[0].String() != "bar" { @@ -404,17 +475,39 @@ func TestRuleBuilder_Build(t *testing.T) { t.Errorf("want Output = %q, got %q", wantOutput, params.Output) } - if !params.RuleParams.Restat { - t.Errorf("want RuleParams.Restat = true, got %v", params.RuleParams.Restat) + if len(params.ImplicitOutputs) != 0 { + t.Errorf("want ImplicitOutputs = [], got %q", params.ImplicitOutputs.Strings()) + } + + if params.Depfile.String() != wantDepfile { + t.Errorf("want Depfile = %q, got %q", wantDepfile, params.Depfile) + } + + if params.Deps != blueprint.DepsGCC { + t.Errorf("want Deps = %q, got %q", blueprint.DepsGCC, params.Deps) } } t.Run("module", func(t *testing.T) { + outFile := filepath.Join(buildDir, ".intermediates", "foo", "foo") check(t, ctx.ModuleForTests("foo", "").Rule("rule"), - filepath.Join(buildDir, ".intermediates", "foo", "foo")) + "cp bar "+outFile, + outFile, outFile+".d", true, nil) + }) + t.Run("sbox", func(t *testing.T) { + outDir := filepath.Join(buildDir, ".intermediates", "foo_sbox") + outFile := filepath.Join(outDir, "foo_sbox") + sbox := filepath.Join(buildDir, "host", config.PrebuiltOS(), "bin/sbox") + sandboxPath := shared.TempDirForOutDir(buildDir) + + cmd := sbox + ` -c 'cp bar __SBOX_OUT_DIR__/foo_sbox' --sandbox-path ` + sandboxPath + " --output-root " + outDir + " __SBOX_OUT_DIR__/foo_sbox __SBOX_OUT_DIR__/foo_sbox.d" + + check(t, ctx.ModuleForTests("foo_sbox", "").Rule("rule"), + cmd, outFile, outFile+".d", false, []string{sbox}) }) t.Run("singleton", func(t *testing.T) { + outFile := filepath.Join(buildDir, "baz") check(t, ctx.SingletonForTests("rule_builder_test").Rule("rule"), - filepath.Join(buildDir, "baz")) + "cp bar "+outFile, outFile, outFile+".d", true, nil) }) } |