/* * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ #include "precompiled.hpp" #include "jvm.h" #include "logTestUtils.inline.hpp" #include "logging/logFileOutput.hpp" #include "memory/resourceArea.hpp" #include "runtime/os.hpp" #include "unittest.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" static const char* name = "file=testlog.pid%p.%t.log"; // Test parsing a bunch of valid file output options TEST_VM(LogFileOutput, parse_valid) { const char* valid_options[] = { "", "filecount=10", "filesize=512", "filecount=11,filesize=256", "filesize=256,filecount=11", "filesize=0", "filecount=1", "filesize=1m", "filesize=1M", "filesize=1k", "filesize=1G" }; // Override LogOutput's vm_start time to get predictable file name LogFileOutput::set_file_name_parameters(0); char expected_filename[1 * K]; int ret = jio_snprintf(expected_filename, sizeof(expected_filename), "testlog.pid%d.1970-01-01_01-00-00.log", os::current_process_id()); ASSERT_GT(ret, 0) << "Buffer too small"; for (size_t i = 0; i < ARRAY_SIZE(valid_options); i++) { ResourceMark rm; stringStream ss; { LogFileOutput fo(name); EXPECT_STREQ(name, fo.name()); EXPECT_TRUE(fo.initialize(valid_options[i], &ss)) << "Did not accept valid option(s) '" << valid_options[i] << "': " << ss.as_string(); } remove(expected_filename); } } // Test parsing a bunch of invalid file output options TEST_VM(LogFileOutput, parse_invalid) { const char* invalid_options[] = { "invalidopt", "filecount=", "filesize=,filecount=10", "fileco=10", "ilesize=512", "filecount=11,,filesize=256", ",filesize=256,filecount=11", "filesize=256,filecount=11,", "filesize=-1", "filecount=0.1", "filecount=-2", "filecount=2.0", "filecount= 2", "filesize=2 ", "filecount=ab", "filesize=0xz", "filecount=1MB", "filesize=99bytes", "filesize=9999999999999999999999999" "filecount=9999999999999999999999999" }; for (size_t i = 0; i < ARRAY_SIZE(invalid_options); i++) { ResourceMark rm; stringStream ss; LogFileOutput fo(name); EXPECT_FALSE(fo.initialize(invalid_options[i], &ss)) << "Accepted invalid option(s) '" << invalid_options[i] << "': " << ss.as_string(); } } // Test for overflows with filesize TEST_VM(LogFileOutput, filesize_overflow) { char buf[256]; int ret = jio_snprintf(buf, sizeof(buf), "filesize=" SIZE_FORMAT "K", SIZE_MAX); ASSERT_GT(ret, 0) << "Buffer too small"; ResourceMark rm; stringStream ss; LogFileOutput fo(name); EXPECT_FALSE(fo.initialize(buf, &ss)) << "Accepted filesize that overflows"; } TEST_VM(LogFileOutput, startup_rotation) { const size_t rotations = 5; const char* filename = "start-rotate-test"; char* rotated_file[rotations]; ResourceMark rm; for (size_t i = 0; i < rotations; i++) { size_t len = strlen(filename) + 3; rotated_file[i] = NEW_RESOURCE_ARRAY(char, len); int ret = jio_snprintf(rotated_file[i], len, "%s." SIZE_FORMAT, filename, i); ASSERT_NE(-1, ret); delete_file(rotated_file[i]); } delete_file(filename); init_log_file(filename); ASSERT_TRUE(file_exists(filename)) << "configured logging to file '" << filename << "' but file was not found"; // Initialize the same file a bunch more times to trigger rotations for (size_t i = 0; i < rotations; i++) { init_log_file(filename); EXPECT_TRUE(file_exists(rotated_file[i])); } // Remove a file and expect its slot to be re-used delete_file(rotated_file[1]); init_log_file(filename); EXPECT_TRUE(file_exists(rotated_file[1])); // Clean up after test delete_file(filename); for (size_t i = 0; i < rotations; i++) { delete_file(rotated_file[i]); } } TEST_VM(LogFileOutput, startup_truncation) { const char* filename = "start-truncate-test"; const char* archived_filename = "start-truncate-test.0"; delete_file(filename); delete_file(archived_filename); // Use the same log file twice and expect it to be overwritten/truncated init_log_file(filename, "filecount=0"); ASSERT_TRUE(file_exists(filename)) << "configured logging to file '" << filename << "' but file was not found"; init_log_file(filename, "filecount=0"); ASSERT_TRUE(file_exists(filename)) << "configured logging to file '" << filename << "' but file was not found"; EXPECT_FALSE(file_exists(archived_filename)) << "existing log file was not properly truncated when filecount was 0"; // Verify that the file was really truncated and not just appended EXPECT_TRUE(file_contains_substring(filename, LOG_TEST_STRING_LITERAL)); const char* repeated[] = { LOG_TEST_STRING_LITERAL, LOG_TEST_STRING_LITERAL }; EXPECT_FALSE(file_contains_substrings_in_order(filename, repeated)) << "log file " << filename << " appended rather than truncated"; delete_file(filename); delete_file(archived_filename); } TEST_VM(LogFileOutput, invalid_file) { ResourceMark rm; stringStream ss; // Attempt to log to a directory (existing log not a regular file) create_directory("tmplogdir"); LogFileOutput bad_file("file=tmplogdir"); EXPECT_FALSE(bad_file.initialize("", &ss)) << "file was initialized when there was an existing directory with the same name"; EXPECT_TRUE(string_contains_substring(ss.as_string(), "tmplogdir is not a regular file")) << "missing expected error message, received msg: %s" << ss.as_string(); delete_empty_directory("tmplogdir"); }