diff options
author | Colin Cross <ccross@android.com> | 2017-05-19 04:29:45 (GMT) |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2017-05-22 18:29:06 (GMT) |
commit | a127dda3ee92916ef459b3da7aa9f2920ff1a5ab (patch) | |
tree | 0b5524287de8ab1bb9ca33efb7c5329baed740e7 /src | |
parent | 036003d20e80cbb044a3f0f0b41e2fdefcde66af (diff) | |
download | Ninja-a127dda3ee92916ef459b3da7aa9f2920ff1a5ab.zip Ninja-a127dda3ee92916ef459b3da7aa9f2920ff1a5ab.tar.gz Ninja-a127dda3ee92916ef459b3da7aa9f2920ff1a5ab.tar.bz2 |
Add a test that fails if a rule updates it output file but fails
https://groups.google.com/forum/#!msg/ninja-build/YQuGNrECI-4/ti-lAs9SPv8J
discusses a case where an rule updates its output file and then
fails. The next run of ninja considers the ouptut file clean
and doesn't rebuild it. Add a test for this case, which currently
fails.
Diffstat (limited to 'src')
-rw-r--r-- | src/build.cc | 7 | ||||
-rw-r--r-- | src/build.h | 3 | ||||
-rw-r--r-- | src/build_test.cc | 51 |
3 files changed, 59 insertions, 2 deletions
diff --git a/src/build.cc b/src/build.cc index a0c7ec8..44d0663 100644 --- a/src/build.cc +++ b/src/build.cc @@ -275,6 +275,13 @@ void BuildStatus::PrintStatus(Edge* edge, EdgeStatus status) { Plan::Plan() : command_edges_(0), wanted_edges_(0) {} +void Plan::Reset() { + command_edges_ = 0; + wanted_edges_ = 0; + ready_.clear(); + want_.clear(); +} + bool Plan::AddTarget(Node* node, string* err) { vector<Node*> stack; return AddSubTarget(node, &stack, err); diff --git a/src/build.h b/src/build.h index 66ce607..f97d67e 100644 --- a/src/build.h +++ b/src/build.h @@ -71,6 +71,9 @@ struct Plan { /// Number of edges with commands to run. int command_edge_count() const { return command_edges_; } + /// Reset state. Clears want and ready sets. + void Reset(); + private: bool AddSubTarget(Node* node, vector<Node*>* stack, string* err); bool CheckDependencyCycle(Node* node, const vector<Node*>& stack, diff --git a/src/build_test.cc b/src/build_test.cc index 640e1b0..d617143 100644 --- a/src/build_test.cc +++ b/src/build_test.cc @@ -608,7 +608,8 @@ bool FakeCommandRunner::StartCommand(Edge* edge) { edge->rule().name() == "cat_rsp_out" || edge->rule().name() == "cc" || edge->rule().name() == "touch" || - edge->rule().name() == "touch-interrupt") { + edge->rule().name() == "touch-interrupt" || + edge->rule().name() == "touch-fail-tick2") { for (vector<Node*>::iterator out = edge->outputs_.begin(); out != edge->outputs_.end(); ++out) { fs_->Create((*out)->path(), ""); @@ -649,7 +650,8 @@ bool FakeCommandRunner::WaitForCommand(Result* result) { return true; } - if (edge->rule().name() == "fail") + if (edge->rule().name() == "fail" || + (edge->rule().name() == "touch-fail-tick2" && fs_->now_ == 2)) result->status = ExitFailure; else result->status = ExitSuccess; @@ -1258,6 +1260,51 @@ TEST_F(BuildWithLogTest, NotInLogButOnDisk) { EXPECT_TRUE(builder_.AlreadyUpToDate()); } +TEST_F(BuildWithLogTest, RebuildAfterFailure) { + ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, +"rule touch-fail-tick2\n" +" command = touch-fail-tick2\n" +"build out1: touch-fail-tick2 in\n")); + + string err; + + fs_.Create("in", ""); + + // Run once successfully to get out1 in the log + EXPECT_TRUE(builder_.AddTarget("out1", &err)); + EXPECT_TRUE(builder_.Build(&err)); + EXPECT_EQ("", err); + EXPECT_EQ(1u, command_runner_.commands_ran_.size()); + + command_runner_.commands_ran_.clear(); + state_.Reset(); + builder_.Cleanup(); + builder_.plan_.Reset(); + + fs_.Tick(); + fs_.Create("in", ""); + + // Run again with a failure that updates the output file timestamp + EXPECT_TRUE(builder_.AddTarget("out1", &err)); + EXPECT_FALSE(builder_.Build(&err)); + EXPECT_EQ("subcommand failed", err); + EXPECT_EQ(1u, command_runner_.commands_ran_.size()); + + command_runner_.commands_ran_.clear(); + state_.Reset(); + builder_.Cleanup(); + builder_.plan_.Reset(); + + fs_.Tick(); + + // Run again, should rerun even though the output file is up to date on disk + EXPECT_TRUE(builder_.AddTarget("out1", &err)); + EXPECT_FALSE(builder_.AlreadyUpToDate()); + EXPECT_TRUE(builder_.Build(&err)); + EXPECT_EQ(1u, command_runner_.commands_ran_.size()); + EXPECT_EQ("", err); +} + TEST_F(BuildWithLogTest, RestatTest) { ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, "rule true\n" |