Files
wehub-resource-sync 8a852e4b4e
cffconvert / validate (push) Has been skipped
License Check / license-check (push) Failing after 2s
chore: import upstream snapshot with attribution
2026-07-13 12:14:16 +08:00

318 lines
12 KiB
C++

/* Copyright 2023 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/tools/proto_splitter/merge.h"
#include <array>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "xla/tsl/lib/core/status_test_util.h"
#include "xla/tsl/platform/env.h"
#include "tensorflow/core/framework/graph.pb.h"
#include "tensorflow/core/platform/path.h"
#include "tensorflow/core/platform/test.h"
#include "tensorflow/core/protobuf/saved_model.pb.h"
#include "tensorflow/tools/proto_splitter/cc/test_util.h"
#include "tensorflow/tools/proto_splitter/cc/util.h"
#include "tensorflow/tools/proto_splitter/chunk.pb.h"
#include "tensorflow/tools/proto_splitter/testdata/test_message.pb.h"
#include "tsl/platform/env.h"
#include "tsl/platform/protobuf.h"
#include "tsl/platform/statusor.h"
namespace tensorflow::tools::proto_splitter {
namespace {
inline constexpr std::array kDFSplitTreeChunks = {
"val: \"0\"", "val: \"010\"", "val: \"01020\"",
"val: \"0102030\"", "val: \"0102031\"", "val: \"0102032\"",
"val: \"01021\"", "val: \"0102130\"", "val: \"0102131\"",
"val: \"0102132\""};
inline constexpr std::array kBFSplitTreeChunks = {
"val: \"0\"", "val: \"010\"", "val: \"01020\"",
"val: \"01021\"", "val: \"0102030\"", "val: \"0102031\"",
"val: \"0102032\"", "val: \"0102130\"", "val: \"0102131\"",
"val: \"0102132\""};
TEST(MergeTest, TestReadRiegeliTreeDepthFirst) {
// TODO(b/282779639): Use test data.
const std::string cpb_path =
io::JoinPath(testing::TensorFlowSrcRoot(),
"tools/proto_splitter/testdata", "df-split-tree");
::tensorflow::proto_splitter_testdata::StringNode merged_tree;
TF_ASSERT_OK(Merger::Read(cpb_path, &merged_tree));
const std::string pbtxt_path =
io::JoinPath(testing::TensorFlowSrcRoot(),
"tools/proto_splitter/testdata", "split-tree");
::tensorflow::proto_splitter_testdata::StringNode test_proto;
TF_ASSERT_OK(tsl::ReadTextProto(
tsl::Env::Default(), absl::StrCat(pbtxt_path, ".pbtxt"), &test_proto));
ASSERT_THAT(merged_tree, EqualsProto(test_proto));
}
TEST(MergeTest, TestReadRiegeliTreeBreadthFirst) {
const std::string cpb_path =
io::JoinPath(testing::TensorFlowSrcRoot(),
"tools/proto_splitter/testdata", "bf-split-tree");
::tensorflow::proto_splitter_testdata::StringNode merged_tree;
TF_ASSERT_OK(Merger::Read(cpb_path, &merged_tree));
const std::string pbtxt_path =
io::JoinPath(testing::TensorFlowSrcRoot(),
"tools/proto_splitter/testdata", "split-tree");
::tensorflow::proto_splitter_testdata::StringNode test_proto;
TF_ASSERT_OK(tsl::ReadTextProto(
tsl::Env::Default(), absl::StrCat(pbtxt_path, ".pbtxt"), &test_proto));
ASSERT_THAT(merged_tree, EqualsProto(test_proto));
}
TEST(MergeTest, TestMergeTreeChunksDepthFirst) {
const std::string path =
io::JoinPath(testing::TensorFlowSrcRoot(),
"tools/proto_splitter/testdata", "df-split-tree");
std::vector<std::unique_ptr<::tsl::protobuf::Message>> chunks;
for (const auto& chunk : kDFSplitTreeChunks) {
::tensorflow::proto_splitter_testdata::StringNode string_node;
::tsl::protobuf::TextFormat::ParseFromString(chunk, &string_node);
std::unique_ptr<::tsl::protobuf::Message> node =
std::make_unique<::tensorflow::proto_splitter_testdata::StringNode>(
string_node);
chunks.push_back(std::move(node));
}
std::string split_tree_metadata;
TF_ASSERT_OK(tsl::ReadFileToString(
tsl::Env::Default(), absl::StrCat(path, ".pbtxt"), &split_tree_metadata));
::tensorflow::proto_splitter::ChunkedMessage chunked_message;
::tsl::protobuf::TextFormat::ParseFromString(split_tree_metadata,
&chunked_message);
::tensorflow::proto_splitter_testdata::StringNode merged_tree;
TF_ASSERT_OK(Merger::Merge(chunks, chunked_message, &merged_tree));
const std::string pbtxt_path =
io::JoinPath(testing::TensorFlowSrcRoot(),
"tools/proto_splitter/testdata", "split-tree");
::tensorflow::proto_splitter_testdata::StringNode test_proto;
TF_ASSERT_OK(tsl::ReadTextProto(
tsl::Env::Default(), absl::StrCat(pbtxt_path, ".pbtxt"), &test_proto));
ASSERT_THAT(merged_tree, EqualsProto(test_proto));
}
TEST(MergeTest, TestMergeTreeChunksBreadthFirst) {
const std::string path =
io::JoinPath(testing::TensorFlowSrcRoot(),
"tools/proto_splitter/testdata", "bf-split-tree");
std::vector<std::unique_ptr<::tsl::protobuf::Message>> chunks;
for (const auto& chunk : kBFSplitTreeChunks) {
::tensorflow::proto_splitter_testdata::StringNode string_node;
::tsl::protobuf::TextFormat::ParseFromString(chunk, &string_node);
std::unique_ptr<::tsl::protobuf::Message> node =
std::make_unique<::tensorflow::proto_splitter_testdata::StringNode>(
string_node);
chunks.push_back(std::move(node));
}
std::string split_tree_metadata;
TF_ASSERT_OK(tsl::ReadFileToString(
tsl::Env::Default(), absl::StrCat(path, ".pbtxt"), &split_tree_metadata));
::tensorflow::proto_splitter::ChunkedMessage chunked_message;
::tsl::protobuf::TextFormat::ParseFromString(split_tree_metadata,
&chunked_message);
::tensorflow::proto_splitter_testdata::StringNode merged_tree;
TF_ASSERT_OK(Merger::Merge(chunks, chunked_message, &merged_tree));
const std::string pbtxt_path =
io::JoinPath(testing::TensorFlowSrcRoot(),
"tools/proto_splitter/testdata", "split-tree");
::tensorflow::proto_splitter_testdata::StringNode test_proto;
TF_ASSERT_OK(tsl::ReadTextProto(
tsl::Env::Default(), absl::StrCat(pbtxt_path, ".pbtxt"), &test_proto));
ASSERT_THAT(merged_tree, EqualsProto(test_proto));
}
TEST(MergeTest, TestReadGraphDefLotsNodes) {
const std::string path =
io::JoinPath(testing::TensorFlowSrcRoot(),
"tools/proto_splitter/testdata", "split-lots-nodes");
GraphDef merged_graph_def;
TF_ASSERT_OK(Merger::Read(path, &merged_graph_def));
GraphDef test_graph_def;
TF_ASSERT_OK(tsl::ReadTextProto(
tsl::Env::Default(), absl::StrCat(path, ".pbtxt"), &test_graph_def));
ASSERT_THAT(merged_graph_def, EqualsProto(test_graph_def));
}
TEST(MergeTest, TestReadGraphDefLargeNodes) {
const std::string path =
io::JoinPath(testing::TensorFlowSrcRoot(),
"tools/proto_splitter/testdata", "split-large-nodes");
GraphDef merged_graph_def;
TF_ASSERT_OK(Merger::Read(path, &merged_graph_def));
GraphDef test_graph_def;
TF_ASSERT_OK(tsl::ReadTextProto(
tsl::Env::Default(), absl::StrCat(path, ".pbtxt"), &test_graph_def));
ASSERT_THAT(merged_graph_def, EqualsProto(test_graph_def));
}
TEST(MergeTest, TestReadGraphDefLargeConstant) {
const std::string path =
io::JoinPath(testing::TensorFlowSrcRoot(),
"tools/proto_splitter/testdata", "split-large-constant");
GraphDef merged_graph_def;
TF_ASSERT_OK(Merger::Read(path, &merged_graph_def));
GraphDef test_graph_def;
TF_ASSERT_OK(tsl::ReadTextProto(
tsl::Env::Default(), absl::StrCat(path, ".pbtxt"), &test_graph_def));
ASSERT_THAT(merged_graph_def, EqualsProto(test_graph_def));
}
TEST(MergeTest, TestReadManyField) {
const std::string path =
io::JoinPath(testing::TensorFlowSrcRoot(),
"tools/proto_splitter/testdata", "many-field");
::tensorflow::proto_splitter_testdata::ManyFields merged_many_field;
TF_ASSERT_OK(Merger::Read(path, &merged_many_field));
::tensorflow::proto_splitter_testdata::ManyFields test_many_field;
TF_ASSERT_OK(tsl::ReadTextProto(
tsl::Env::Default(), absl::StrCat(path, ".pbtxt"), &test_many_field));
ASSERT_THAT(merged_many_field, EqualsProto(test_many_field));
}
TEST(MergeTest, TestReadSavedModel) {
const std::string path =
io::JoinPath(testing::TensorFlowSrcRoot(),
"tools/proto_splitter/testdata", "split-standard");
SavedModel merged_saved_model;
TF_ASSERT_OK(Merger::Read(path, &merged_saved_model));
SavedModel test_saved_model;
TF_ASSERT_OK(tsl::ReadTextProto(
tsl::Env::Default(), absl::StrCat(path, ".pbtxt"), &test_saved_model));
ASSERT_THAT(merged_saved_model, EqualsProto(test_saved_model));
}
TEST(MergeTest, TestReadChunkedModel) {
const std::string path =
io::JoinPath(testing::TensorFlowSrcRoot(), "cc/saved_model/testdata",
"chunked_saved_model/chunked_model/saved_model");
SavedModel merged_saved_model;
TF_ASSERT_OK(Merger::Read(path, &merged_saved_model));
SavedModel test_saved_model;
TF_ASSERT_OK(tsl::ReadTextProto(
tsl::Env::Default(), absl::StrCat(path, ".pbtxt"), &test_saved_model));
ASSERT_THAT(merged_saved_model, EqualsProto(test_saved_model));
}
TEST(MergeTest, TestReadPartial) {
const std::string path =
io::JoinPath(testing::TensorFlowSrcRoot(),
"tools/proto_splitter/testdata", "many-field");
TF_ASSERT_OK_AND_ASSIGN(auto reader, tools::proto_splitter::GetRiegeliReader(
absl::StrCat(path, ".cpb")));
auto read_metadata = GetChunkMetadata(reader);
if (!read_metadata.ok()) {
reader.Close();
TF_ASSERT_OK(read_metadata.status());
}
::tensorflow::proto_splitter::ChunkMetadata chunk_metadata =
read_metadata.value();
::tensorflow::proto_splitter::ChunkMetadata partial_chunk_metadata;
partial_chunk_metadata.mutable_chunks()->CopyFrom(chunk_metadata.chunks());
partial_chunk_metadata.mutable_message()->set_chunk_index(
chunk_metadata.message().chunk_index());
proto_splitter_testdata::ManyFields merged_many_fields;
TF_ASSERT_OK(
Merger::ReadPartial(path, partial_chunk_metadata, &merged_many_fields));
ASSERT_THAT(merged_many_fields, EqualsProto(R"pb(
map_field_int64 { key: -1345 value: "map_value_-1345" }
)pb"));
}
TEST(MergeTest, TestReadChunkedFromString) {
const std::string path =
io::JoinPath(testing::TensorFlowSrcRoot(), "cc/saved_model/testdata",
"chunked_saved_model/chunked_model/saved_model");
std::string data;
TF_ASSERT_OK(tsl::ReadFileToString(tsl::Env::Default(),
absl::StrCat(path, ".cpb"), &data));
SavedModel merged_saved_model;
TF_ASSERT_OK(Merger::ReadChunkedFromString(data, &merged_saved_model));
SavedModel test_saved_model;
TF_ASSERT_OK(tsl::ReadTextProto(
tsl::Env::Default(), absl::StrCat(path, ".pbtxt"), &test_saved_model));
ASSERT_THAT(merged_saved_model, EqualsProto(test_saved_model));
}
TEST(MergeTest, TestProcessFieldReturnsErrorOnInvalidFieldNumber) {
::tensorflow::proto_splitter::ChunkedMessage chunked_message;
auto* chunk_field = chunked_message.add_chunked_fields();
auto* tag = chunk_field->add_field_tag();
tag->set_field(99999);
chunk_field->mutable_message()->set_chunk_index(0);
std::vector<std::unique_ptr<tsl::protobuf::Message>> chunks;
chunks.push_back(
std::make_unique<::tensorflow::proto_splitter_testdata::ManyFields>());
::tensorflow::proto_splitter_testdata::ManyFields merged;
absl::Status status = Merger::Merge(chunks, chunked_message, &merged);
EXPECT_FALSE(status.ok());
EXPECT_EQ(status.code(), absl::StatusCode::kFailedPrecondition);
EXPECT_THAT(std::string(status.message()),
::testing::HasSubstr("not found in message descriptor"));
}
} // namespace
} // namespace tensorflow::tools::proto_splitter