| // Copyright 2024 The Bazel 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 "src/tools/singlejar/log4j2_plugin_dat_combiner.h" |
| |
| #include <fstream> |
| #include <string> |
| |
| #include "googletest/include/gtest/gtest.h" |
| #include "src/tools/singlejar/input_jar.h" |
| #include "src/tools/singlejar/test_util.h" |
| #include "rules_cc/cc/runfiles/runfiles.h" |
| |
| namespace { |
| |
| using rules_cc::cc::runfiles::Runfiles; |
| |
| // A test fixture is used because test case setup is needed. |
| class Log4J2PluginDatCombinerTest : public ::testing::Test { |
| public: |
| void SetUp() override { runfiles.reset(Runfiles::CreateForTest()); } |
| |
| protected: |
| static void SetUpTestCase() { ASSERT_EQ(0, chdir(getenv("TEST_TMPDIR"))); } |
| |
| static void TearDownTestCase() {} |
| |
| std::unique_ptr<Runfiles> runfiles; |
| }; |
| |
| // Test Log4J2PluginDatCombiner |
| TEST_F(Log4J2PluginDatCombinerTest, Log4J2PluginDatCombinerSimple) { |
| const std::string plugins_cache_path = |
| "META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat"; |
| Log4J2PluginDatCombiner combiner(plugins_cache_path, false); |
| |
| InputJar input_jar1; |
| ASSERT_TRUE(input_jar1.Open( |
| runfiles |
| ->Rlocation( |
| "io_bazel/src/tools/singlejar/data/log4j2_plugins_set_1.jar") |
| .c_str())); |
| |
| const LH *lh; |
| const CDH *cdh; |
| while ((cdh = input_jar1.NextEntry(&lh))) { |
| if (cdh->file_name_is(plugins_cache_path.c_str())) { |
| ASSERT_TRUE(combiner.Merge(cdh, lh)); |
| } |
| } |
| |
| InputJar input_jar2; |
| ASSERT_TRUE(input_jar2.Open( |
| runfiles |
| ->Rlocation( |
| "io_bazel/src/tools/singlejar/data/log4j2_plugins_set_2.jar") |
| .c_str())); |
| while ((cdh = input_jar2.NextEntry(&lh))) { |
| if (cdh->file_name_is(plugins_cache_path.c_str())) { |
| ASSERT_TRUE(combiner.Merge(cdh, lh)); |
| } |
| } |
| |
| LH *entry = reinterpret_cast<LH *>(combiner.OutputEntry(true)); |
| EXPECT_TRUE(entry->is()); |
| EXPECT_EQ(20, entry->version()); |
| EXPECT_EQ(Z_DEFLATED, entry->compression_method()); |
| uint64_t original_size = entry->uncompressed_file_size(); |
| uint64_t compressed_size = entry->compressed_file_size(); |
| |
| std::ifstream expected_file( |
| runfiles->Rlocation( |
| "io_bazel/src/tools/singlejar/data/log4j2_plugins_set_result.dat"), |
| std::ios::binary); |
| ASSERT_TRUE(expected_file.is_open()); |
| |
| expected_file.seekg(0, std::ios::end); |
| std::streampos expected_size = expected_file.tellg(); |
| expected_file.seekg(0, std::ios::beg); |
| ASSERT_GT(expected_size, 0); |
| char *expected_content = new char[expected_size]; |
| expected_file.read(expected_content, expected_size); |
| ASSERT_TRUE(expected_file.good()); |
| expected_file.close(); |
| |
| EXPECT_EQ(expected_size, original_size); |
| EXPECT_LE(compressed_size, original_size); |
| EXPECT_TRUE(entry->file_name_is(plugins_cache_path.c_str())); |
| Inflater inflater; |
| inflater.DataToInflate(entry->data(), compressed_size); |
| uint8_t buffer[256]; |
| ASSERT_EQ(Z_STREAM_END, inflater.Inflate((buffer), sizeof(buffer))); |
| ASSERT_EQ( |
| memcmp(reinterpret_cast<char *>(buffer), expected_content, expected_size), |
| 0) |
| << "Byte arrays are not equal"; |
| free(reinterpret_cast<void *>(entry)); |
| } |
| |
| TEST_F(Log4J2PluginDatCombinerTest, Log4J2PluginDatCombinerDuplicate) { |
| const std::string plugins_cache_path = |
| "META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat"; |
| Log4J2PluginDatCombiner combiner(plugins_cache_path, true); |
| |
| InputJar input_jar1; |
| ASSERT_TRUE(input_jar1.Open( |
| runfiles |
| ->Rlocation( |
| "io_bazel/src/tools/singlejar/data/log4j2_plugins_set_1.jar") |
| .c_str())); |
| |
| const LH *lh; |
| const CDH *cdh; |
| while ((cdh = input_jar1.NextEntry(&lh))) { |
| if (cdh->file_name_is(plugins_cache_path.c_str())) { |
| ASSERT_TRUE(combiner.Merge(cdh, lh)); |
| } |
| } |
| |
| InputJar input_jar2; |
| // We reuse log4j2_plugins_set_1.jar on purpose to cause a duplicate. |
| ASSERT_TRUE(input_jar2.Open( |
| runfiles |
| ->Rlocation( |
| "io_bazel/src/tools/singlejar/data/log4j2_plugins_set_1.jar") |
| .c_str())); |
| while ((cdh = input_jar2.NextEntry(&lh))) { |
| if (cdh->file_name_is(plugins_cache_path.c_str())) { |
| ASSERT_DEATH(combiner.Merge(cdh, lh), "present in multiple jars"); |
| } |
| } |
| } |
| |
| } // anonymous namespace |