inplace_generator_unittest.cc revision 5c6c65570013bbdbd67f9bf6391dd295ef5b5ee6
1// Copyright 2015 The Chromium OS Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "update_engine/payload_generator/inplace_generator.h" 6 7#include <set> 8#include <sstream> 9#include <string> 10#include <utility> 11#include <vector> 12 13#include <base/logging.h> 14#include <base/strings/string_util.h> 15#include <gtest/gtest.h> 16 17#include "update_engine/extent_ranges.h" 18#include "update_engine/payload_generator/cycle_breaker.h" 19#include "update_engine/payload_generator/delta_diff_generator.h" 20#include "update_engine/payload_generator/graph_types.h" 21#include "update_engine/payload_generator/graph_utils.h" 22#include "update_engine/test_utils.h" 23#include "update_engine/utils.h" 24 25using std::set; 26using std::string; 27using std::stringstream; 28using std::vector; 29 30namespace chromeos_update_engine { 31 32typedef DeltaDiffGenerator::Block Block; 33 34namespace { 35 36#define OP_BSDIFF DeltaArchiveManifest_InstallOperation_Type_BSDIFF 37#define OP_MOVE DeltaArchiveManifest_InstallOperation_Type_MOVE 38#define OP_REPLACE DeltaArchiveManifest_InstallOperation_Type_REPLACE 39#define OP_REPLACE_BZ DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ 40 41void GenVertex(Vertex* out, 42 const vector<Extent>& src_extents, 43 const vector<Extent>& dst_extents, 44 const string& path, 45 DeltaArchiveManifest_InstallOperation_Type type) { 46 out->op.set_type(type); 47 out->file_name = path; 48 DeltaDiffGenerator::StoreExtents(src_extents, out->op.mutable_src_extents()); 49 DeltaDiffGenerator::StoreExtents(dst_extents, out->op.mutable_dst_extents()); 50} 51 52vector<Extent> VectOfExt(uint64_t start_block, uint64_t num_blocks) { 53 return vector<Extent>(1, ExtentForRange(start_block, num_blocks)); 54} 55 56EdgeProperties EdgeWithReadDep(const vector<Extent>& extents) { 57 EdgeProperties ret; 58 ret.extents = extents; 59 return ret; 60} 61 62EdgeProperties EdgeWithWriteDep(const vector<Extent>& extents) { 63 EdgeProperties ret; 64 ret.write_extents = extents; 65 return ret; 66} 67 68template<typename T> 69void DumpVect(const vector<T>& vect) { 70 stringstream ss(stringstream::out); 71 for (typename vector<T>::const_iterator it = vect.begin(), e = vect.end(); 72 it != e; ++it) { 73 ss << *it << ", "; 74 } 75 LOG(INFO) << "{" << ss.str() << "}"; 76} 77 78void AppendExtent(vector<Extent>* vect, uint64_t start, uint64_t length) { 79 vect->resize(vect->size() + 1); 80 vect->back().set_start_block(start); 81 vect->back().set_num_blocks(length); 82} 83 84void OpAppendExtent(DeltaArchiveManifest_InstallOperation* op, 85 uint64_t start, 86 uint64_t length) { 87 Extent* extent = op->add_src_extents(); 88 extent->set_start_block(start); 89 extent->set_num_blocks(length); 90} 91 92} // namespace 93 94class InplaceGeneratorTest : public ::testing::Test { 95}; 96 97TEST_F(InplaceGeneratorTest, SubstituteBlocksTest) { 98 vector<Extent> remove_blocks; 99 AppendExtent(&remove_blocks, 3, 3); 100 AppendExtent(&remove_blocks, 7, 1); 101 vector<Extent> replace_blocks; 102 AppendExtent(&replace_blocks, 10, 2); 103 AppendExtent(&replace_blocks, 13, 2); 104 Vertex vertex; 105 DeltaArchiveManifest_InstallOperation& op = vertex.op; 106 OpAppendExtent(&op, 4, 3); 107 OpAppendExtent(&op, kSparseHole, 4); // Sparse hole in file 108 OpAppendExtent(&op, 3, 1); 109 OpAppendExtent(&op, 7, 3); 110 111 InplaceGenerator::SubstituteBlocks(&vertex, remove_blocks, replace_blocks); 112 113 EXPECT_EQ(7, op.src_extents_size()); 114 EXPECT_EQ(11, op.src_extents(0).start_block()); 115 EXPECT_EQ(1, op.src_extents(0).num_blocks()); 116 EXPECT_EQ(13, op.src_extents(1).start_block()); 117 EXPECT_EQ(1, op.src_extents(1).num_blocks()); 118 EXPECT_EQ(6, op.src_extents(2).start_block()); 119 EXPECT_EQ(1, op.src_extents(2).num_blocks()); 120 EXPECT_EQ(kSparseHole, op.src_extents(3).start_block()); 121 EXPECT_EQ(4, op.src_extents(3).num_blocks()); 122 EXPECT_EQ(10, op.src_extents(4).start_block()); 123 EXPECT_EQ(1, op.src_extents(4).num_blocks()); 124 EXPECT_EQ(14, op.src_extents(5).start_block()); 125 EXPECT_EQ(1, op.src_extents(5).num_blocks()); 126 EXPECT_EQ(8, op.src_extents(6).start_block()); 127 EXPECT_EQ(2, op.src_extents(6).num_blocks()); 128} 129 130TEST_F(InplaceGeneratorTest, CutEdgesTest) { 131 Graph graph; 132 vector<Block> blocks(9); 133 134 // Create nodes in graph 135 { 136 graph.resize(graph.size() + 1); 137 graph.back().op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE); 138 // Reads from blocks 3, 5, 7 139 vector<Extent> extents; 140 AppendBlockToExtents(&extents, 3); 141 AppendBlockToExtents(&extents, 5); 142 AppendBlockToExtents(&extents, 7); 143 DeltaDiffGenerator::StoreExtents(extents, 144 graph.back().op.mutable_src_extents()); 145 blocks[3].reader = graph.size() - 1; 146 blocks[5].reader = graph.size() - 1; 147 blocks[7].reader = graph.size() - 1; 148 149 // Writes to blocks 1, 2, 4 150 extents.clear(); 151 AppendBlockToExtents(&extents, 1); 152 AppendBlockToExtents(&extents, 2); 153 AppendBlockToExtents(&extents, 4); 154 DeltaDiffGenerator::StoreExtents(extents, 155 graph.back().op.mutable_dst_extents()); 156 blocks[1].writer = graph.size() - 1; 157 blocks[2].writer = graph.size() - 1; 158 blocks[4].writer = graph.size() - 1; 159 } 160 { 161 graph.resize(graph.size() + 1); 162 graph.back().op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE); 163 // Reads from blocks 1, 2, 4 164 vector<Extent> extents; 165 AppendBlockToExtents(&extents, 1); 166 AppendBlockToExtents(&extents, 2); 167 AppendBlockToExtents(&extents, 4); 168 DeltaDiffGenerator::StoreExtents(extents, 169 graph.back().op.mutable_src_extents()); 170 blocks[1].reader = graph.size() - 1; 171 blocks[2].reader = graph.size() - 1; 172 blocks[4].reader = graph.size() - 1; 173 174 // Writes to blocks 3, 5, 6 175 extents.clear(); 176 AppendBlockToExtents(&extents, 3); 177 AppendBlockToExtents(&extents, 5); 178 AppendBlockToExtents(&extents, 6); 179 DeltaDiffGenerator::StoreExtents(extents, 180 graph.back().op.mutable_dst_extents()); 181 blocks[3].writer = graph.size() - 1; 182 blocks[5].writer = graph.size() - 1; 183 blocks[6].writer = graph.size() - 1; 184 } 185 186 // Create edges 187 InplaceGenerator::CreateEdges(&graph, blocks); 188 189 // Find cycles 190 CycleBreaker cycle_breaker; 191 set<Edge> cut_edges; 192 cycle_breaker.BreakCycles(graph, &cut_edges); 193 194 EXPECT_EQ(1, cut_edges.size()); 195 EXPECT_TRUE(cut_edges.end() != cut_edges.find( 196 std::pair<Vertex::Index, Vertex::Index>(1, 0))); 197 198 vector<CutEdgeVertexes> cuts; 199 EXPECT_TRUE(InplaceGenerator::CutEdges(&graph, cut_edges, &cuts)); 200 201 EXPECT_EQ(3, graph.size()); 202 203 // Check new node in graph: 204 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_MOVE, 205 graph.back().op.type()); 206 EXPECT_EQ(2, graph.back().op.src_extents_size()); 207 EXPECT_EQ(1, graph.back().op.dst_extents_size()); 208 EXPECT_EQ(kTempBlockStart, graph.back().op.dst_extents(0).start_block()); 209 EXPECT_EQ(2, graph.back().op.dst_extents(0).num_blocks()); 210 EXPECT_TRUE(graph.back().out_edges.empty()); 211 212 // Check that old node reads from new blocks 213 EXPECT_EQ(2, graph[0].op.src_extents_size()); 214 EXPECT_EQ(kTempBlockStart, graph[0].op.src_extents(0).start_block()); 215 EXPECT_EQ(2, graph[0].op.src_extents(0).num_blocks()); 216 EXPECT_EQ(7, graph[0].op.src_extents(1).start_block()); 217 EXPECT_EQ(1, graph[0].op.src_extents(1).num_blocks()); 218 219 // And that the old dst extents haven't changed 220 EXPECT_EQ(2, graph[0].op.dst_extents_size()); 221 EXPECT_EQ(1, graph[0].op.dst_extents(0).start_block()); 222 EXPECT_EQ(2, graph[0].op.dst_extents(0).num_blocks()); 223 EXPECT_EQ(4, graph[0].op.dst_extents(1).start_block()); 224 EXPECT_EQ(1, graph[0].op.dst_extents(1).num_blocks()); 225 226 // Ensure it only depends on the next node and the new temp node 227 EXPECT_EQ(2, graph[0].out_edges.size()); 228 EXPECT_TRUE(graph[0].out_edges.end() != graph[0].out_edges.find(1)); 229 EXPECT_TRUE(graph[0].out_edges.end() != graph[0].out_edges.find(graph.size() - 230 1)); 231 232 // Check second node has unchanged extents 233 EXPECT_EQ(2, graph[1].op.src_extents_size()); 234 EXPECT_EQ(1, graph[1].op.src_extents(0).start_block()); 235 EXPECT_EQ(2, graph[1].op.src_extents(0).num_blocks()); 236 EXPECT_EQ(4, graph[1].op.src_extents(1).start_block()); 237 EXPECT_EQ(1, graph[1].op.src_extents(1).num_blocks()); 238 239 EXPECT_EQ(2, graph[1].op.dst_extents_size()); 240 EXPECT_EQ(3, graph[1].op.dst_extents(0).start_block()); 241 EXPECT_EQ(1, graph[1].op.dst_extents(0).num_blocks()); 242 EXPECT_EQ(5, graph[1].op.dst_extents(1).start_block()); 243 EXPECT_EQ(2, graph[1].op.dst_extents(1).num_blocks()); 244 245 // Ensure it only depends on the next node 246 EXPECT_EQ(1, graph[1].out_edges.size()); 247 EXPECT_TRUE(graph[1].out_edges.end() != graph[1].out_edges.find(2)); 248} 249 250TEST_F(InplaceGeneratorTest, RunAsRootAssignTempBlocksReuseTest) { 251 // AssignTempBlocks(Graph* graph, 252 // const string& new_root, 253 // int data_fd, 254 // off_t* data_file_size, 255 // vector<Vertex::Index>* op_indexes, 256 // vector<vector<Vertex::Index>::size_type>* reverse_op_indexes, 257 // const vector<CutEdgeVertexes>& cuts 258 Graph graph(9); 259 260 const vector<Extent> empt; 261 uint64_t tmp = kTempBlockStart; 262 const string kFilename = "/foo"; 263 264 vector<CutEdgeVertexes> cuts; 265 cuts.resize(3); 266 267 // Simple broken loop: 268 GenVertex(&graph[0], VectOfExt(0, 1), VectOfExt(1, 1), "", OP_MOVE); 269 GenVertex(&graph[1], VectOfExt(tmp, 1), VectOfExt(0, 1), "", OP_MOVE); 270 GenVertex(&graph[2], VectOfExt(1, 1), VectOfExt(tmp, 1), "", OP_MOVE); 271 // Corresponding edges: 272 graph[0].out_edges[2] = EdgeWithReadDep(VectOfExt(1, 1)); 273 graph[1].out_edges[2] = EdgeWithWriteDep(VectOfExt(tmp, 1)); 274 graph[1].out_edges[0] = EdgeWithReadDep(VectOfExt(0, 1)); 275 // Store the cut: 276 cuts[0].old_dst = 1; 277 cuts[0].old_src = 0; 278 cuts[0].new_vertex = 2; 279 cuts[0].tmp_extents = VectOfExt(tmp, 1); 280 tmp++; 281 282 // Slightly more complex pair of loops: 283 GenVertex(&graph[3], VectOfExt(4, 2), VectOfExt(2, 2), "", OP_MOVE); 284 GenVertex(&graph[4], VectOfExt(6, 1), VectOfExt(7, 1), "", OP_MOVE); 285 GenVertex(&graph[5], VectOfExt(tmp, 3), VectOfExt(4, 3), kFilename, OP_MOVE); 286 GenVertex(&graph[6], VectOfExt(2, 2), VectOfExt(tmp, 2), "", OP_MOVE); 287 GenVertex(&graph[7], VectOfExt(7, 1), VectOfExt(tmp + 2, 1), "", OP_MOVE); 288 // Corresponding edges: 289 graph[3].out_edges[6] = EdgeWithReadDep(VectOfExt(2, 2)); 290 graph[4].out_edges[7] = EdgeWithReadDep(VectOfExt(7, 1)); 291 graph[5].out_edges[6] = EdgeWithWriteDep(VectOfExt(tmp, 2)); 292 graph[5].out_edges[7] = EdgeWithWriteDep(VectOfExt(tmp + 2, 1)); 293 graph[5].out_edges[3] = EdgeWithReadDep(VectOfExt(4, 2)); 294 graph[5].out_edges[4] = EdgeWithReadDep(VectOfExt(6, 1)); 295 // Store the cuts: 296 cuts[1].old_dst = 5; 297 cuts[1].old_src = 3; 298 cuts[1].new_vertex = 6; 299 cuts[1].tmp_extents = VectOfExt(tmp, 2); 300 cuts[2].old_dst = 5; 301 cuts[2].old_src = 4; 302 cuts[2].new_vertex = 7; 303 cuts[2].tmp_extents = VectOfExt(tmp + 2, 1); 304 305 // Supplier of temp block: 306 GenVertex(&graph[8], empt, VectOfExt(8, 1), "", OP_REPLACE); 307 308 // Specify the final order: 309 vector<Vertex::Index> op_indexes; 310 op_indexes.push_back(2); 311 op_indexes.push_back(0); 312 op_indexes.push_back(1); 313 op_indexes.push_back(6); 314 op_indexes.push_back(3); 315 op_indexes.push_back(7); 316 op_indexes.push_back(4); 317 op_indexes.push_back(5); 318 op_indexes.push_back(8); 319 320 vector<vector<Vertex::Index>::size_type> reverse_op_indexes; 321 InplaceGenerator::GenerateReverseTopoOrderMap(op_indexes, 322 &reverse_op_indexes); 323 324 // Prepare the filesystem with the minimum required for this to work 325 string temp_dir; 326 EXPECT_TRUE(utils::MakeTempDirectory("AssignTempBlocksReuseTest.XXXXXX", 327 &temp_dir)); 328 ScopedDirRemover temp_dir_remover(temp_dir); 329 330 chromeos::Blob temp_data(kBlockSize * 3); 331 test_utils::FillWithData(&temp_data); 332 EXPECT_TRUE(test_utils::WriteFileVector(temp_dir + kFilename, temp_data)); 333 ScopedPathUnlinker filename_unlinker(temp_dir + kFilename); 334 335 int fd; 336 EXPECT_TRUE(utils::MakeTempFile("AssignTempBlocksReuseTest.XXXXXX", 337 nullptr, 338 &fd)); 339 ScopedFdCloser fd_closer(&fd); 340 off_t data_file_size = 0; 341 342 EXPECT_TRUE(InplaceGenerator::AssignTempBlocks(&graph, 343 temp_dir, 344 "/dev/zero", 345 fd, 346 &data_file_size, 347 &op_indexes, 348 &reverse_op_indexes, 349 cuts)); 350 EXPECT_FALSE(graph[6].valid); 351 EXPECT_FALSE(graph[7].valid); 352 EXPECT_EQ(1, graph[1].op.src_extents_size()); 353 EXPECT_EQ(2, graph[1].op.src_extents(0).start_block()); 354 EXPECT_EQ(1, graph[1].op.src_extents(0).num_blocks()); 355 EXPECT_EQ(OP_REPLACE_BZ, graph[5].op.type()); 356} 357 358TEST_F(InplaceGeneratorTest, MoveFullOpsToBackTest) { 359 Graph graph(4); 360 graph[0].file_name = "A"; 361 graph[0].op.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE); 362 graph[1].file_name = "B"; 363 graph[1].op.set_type(DeltaArchiveManifest_InstallOperation_Type_BSDIFF); 364 graph[2].file_name = "C"; 365 graph[2].op.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ); 366 graph[3].file_name = "D"; 367 graph[3].op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE); 368 369 vector<Vertex::Index> vect(graph.size()); 370 371 for (vector<Vertex::Index>::size_type i = 0; i < vect.size(); ++i) { 372 vect[i] = i; 373 } 374 InplaceGenerator::MoveFullOpsToBack(&graph, &vect); 375 EXPECT_EQ(vect.size(), graph.size()); 376 EXPECT_EQ(graph[vect[0]].file_name, "B"); 377 EXPECT_EQ(graph[vect[1]].file_name, "D"); 378 EXPECT_EQ(graph[vect[2]].file_name, "A"); 379 EXPECT_EQ(graph[vect[3]].file_name, "C"); 380} 381 382TEST_F(InplaceGeneratorTest, RunAsRootAssignTempBlocksTest) { 383 Graph graph(9); 384 const vector<Extent> empt; // empty 385 const string kFilename = "/foo"; 386 387 // Some scratch space: 388 GenVertex(&graph[0], empt, VectOfExt(200, 1), "", OP_REPLACE); 389 GenVertex(&graph[1], empt, VectOfExt(210, 10), "", OP_REPLACE); 390 GenVertex(&graph[2], empt, VectOfExt(220, 1), "", OP_REPLACE); 391 392 // A cycle that requires 10 blocks to break: 393 GenVertex(&graph[3], VectOfExt(10, 11), VectOfExt(0, 9), "", OP_BSDIFF); 394 graph[3].out_edges[4] = EdgeWithReadDep(VectOfExt(0, 9)); 395 GenVertex(&graph[4], VectOfExt(0, 9), VectOfExt(10, 11), "", OP_BSDIFF); 396 graph[4].out_edges[3] = EdgeWithReadDep(VectOfExt(10, 11)); 397 398 // A cycle that requires 9 blocks to break: 399 GenVertex(&graph[5], VectOfExt(40, 11), VectOfExt(30, 10), "", OP_BSDIFF); 400 graph[5].out_edges[6] = EdgeWithReadDep(VectOfExt(30, 10)); 401 GenVertex(&graph[6], VectOfExt(30, 10), VectOfExt(40, 11), "", OP_BSDIFF); 402 graph[6].out_edges[5] = EdgeWithReadDep(VectOfExt(40, 11)); 403 404 // A cycle that requires 40 blocks to break (which is too many): 405 GenVertex(&graph[7], 406 VectOfExt(120, 50), 407 VectOfExt(60, 40), 408 "", 409 OP_BSDIFF); 410 graph[7].out_edges[8] = EdgeWithReadDep(VectOfExt(60, 40)); 411 GenVertex(&graph[8], 412 VectOfExt(60, 40), 413 VectOfExt(120, 50), 414 kFilename, 415 OP_BSDIFF); 416 graph[8].out_edges[7] = EdgeWithReadDep(VectOfExt(120, 50)); 417 418 graph_utils::DumpGraph(graph); 419 420 vector<Vertex::Index> final_order; 421 422 423 // Prepare the filesystem with the minimum required for this to work 424 string temp_dir; 425 EXPECT_TRUE(utils::MakeTempDirectory("AssignTempBlocksTest.XXXXXX", 426 &temp_dir)); 427 ScopedDirRemover temp_dir_remover(temp_dir); 428 429 chromeos::Blob temp_data(kBlockSize * 50); 430 test_utils::FillWithData(&temp_data); 431 EXPECT_TRUE(test_utils::WriteFileVector(temp_dir + kFilename, temp_data)); 432 ScopedPathUnlinker filename_unlinker(temp_dir + kFilename); 433 434 int fd; 435 EXPECT_TRUE(utils::MakeTempFile("AssignTempBlocksTestData.XXXXXX", 436 nullptr, 437 &fd)); 438 ScopedFdCloser fd_closer(&fd); 439 off_t data_file_size = 0; 440 441 EXPECT_TRUE(InplaceGenerator::ConvertGraphToDag(&graph, 442 temp_dir, 443 "/dev/zero", 444 fd, 445 &data_file_size, 446 &final_order, 447 Vertex::kInvalidIndex)); 448 449 450 Graph expected_graph(12); 451 GenVertex(&expected_graph[0], empt, VectOfExt(200, 1), "", OP_REPLACE); 452 GenVertex(&expected_graph[1], empt, VectOfExt(210, 10), "", OP_REPLACE); 453 GenVertex(&expected_graph[2], empt, VectOfExt(220, 1), "", OP_REPLACE); 454 GenVertex(&expected_graph[3], 455 VectOfExt(10, 11), 456 VectOfExt(0, 9), 457 "", 458 OP_BSDIFF); 459 expected_graph[3].out_edges[9] = EdgeWithReadDep(VectOfExt(0, 9)); 460 GenVertex(&expected_graph[4], 461 VectOfExt(60, 9), 462 VectOfExt(10, 11), 463 "", 464 OP_BSDIFF); 465 expected_graph[4].out_edges[3] = EdgeWithReadDep(VectOfExt(10, 11)); 466 expected_graph[4].out_edges[9] = EdgeWithWriteDep(VectOfExt(60, 9)); 467 GenVertex(&expected_graph[5], 468 VectOfExt(40, 11), 469 VectOfExt(30, 10), 470 "", 471 OP_BSDIFF); 472 expected_graph[5].out_edges[10] = EdgeWithReadDep(VectOfExt(30, 10)); 473 474 GenVertex(&expected_graph[6], 475 VectOfExt(60, 10), 476 VectOfExt(40, 11), 477 "", 478 OP_BSDIFF); 479 expected_graph[6].out_edges[5] = EdgeWithReadDep(VectOfExt(40, 11)); 480 expected_graph[6].out_edges[10] = EdgeWithWriteDep(VectOfExt(60, 10)); 481 482 GenVertex(&expected_graph[7], 483 VectOfExt(120, 50), 484 VectOfExt(60, 40), 485 "", 486 OP_BSDIFF); 487 expected_graph[7].out_edges[6] = EdgeWithReadDep(VectOfExt(60, 10)); 488 489 GenVertex(&expected_graph[8], empt, VectOfExt(0, 50), "/foo", OP_REPLACE_BZ); 490 expected_graph[8].out_edges[7] = EdgeWithReadDep(VectOfExt(120, 50)); 491 492 GenVertex(&expected_graph[9], 493 VectOfExt(0, 9), 494 VectOfExt(60, 9), 495 "", 496 OP_MOVE); 497 498 GenVertex(&expected_graph[10], 499 VectOfExt(30, 10), 500 VectOfExt(60, 10), 501 "", 502 OP_MOVE); 503 expected_graph[10].out_edges[4] = EdgeWithReadDep(VectOfExt(60, 9)); 504 505 EXPECT_EQ(12, graph.size()); 506 EXPECT_FALSE(graph.back().valid); 507 for (Graph::size_type i = 0; i < graph.size() - 1; i++) { 508 EXPECT_TRUE(graph[i].out_edges == expected_graph[i].out_edges); 509 if (i == 8) { 510 // special case 511 } else { 512 // EXPECT_TRUE(graph[i] == expected_graph[i]) << "i = " << i; 513 } 514 } 515} 516 517TEST_F(InplaceGeneratorTest, CreateScratchNodeTest) { 518 Vertex vertex; 519 InplaceGenerator::CreateScratchNode(12, 34, &vertex); 520 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ, 521 vertex.op.type()); 522 EXPECT_EQ(0, vertex.op.data_offset()); 523 EXPECT_EQ(0, vertex.op.data_length()); 524 EXPECT_EQ(1, vertex.op.dst_extents_size()); 525 EXPECT_EQ(12, vertex.op.dst_extents(0).start_block()); 526 EXPECT_EQ(34, vertex.op.dst_extents(0).num_blocks()); 527} 528 529} // namespace chromeos_update_engine 530