1 | /* |
2 | * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. |
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 | * |
5 | * This code is free software; you can redistribute it and/or modify it |
6 | * under the terms of the GNU General Public License version 2 only, as |
7 | * published by the Free Software Foundation. |
8 | * |
9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
12 | * version 2 for more details (a copy is included in the LICENSE file that |
13 | * accompanied this code). |
14 | * |
15 | * You should have received a copy of the GNU General Public License version |
16 | * 2 along with this work; if not, write to the Free Software Foundation, |
17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
18 | * |
19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
20 | * or visit www.oracle.com if you need additional information or have any |
21 | * questions. |
22 | */ |
23 | |
24 | #include "precompiled.hpp" |
25 | #include "jvm.h" |
26 | #include "logTestUtils.inline.hpp" |
27 | #include "logging/logFileOutput.hpp" |
28 | #include "memory/resourceArea.hpp" |
29 | #include "runtime/os.hpp" |
30 | #include "unittest.hpp" |
31 | #include "utilities/globalDefinitions.hpp" |
32 | #include "utilities/ostream.hpp" |
33 | |
34 | static const char* name = prepend_prefix_temp_dir("file=" , "testlog.pid%p.%t.log" ); |
35 | |
36 | // Test parsing a bunch of valid file output options |
37 | TEST_VM(LogFileOutput, parse_valid) { |
38 | const char* valid_options[] = { |
39 | "" , "filecount=10" , "filesize=512" , |
40 | "filecount=11,filesize=256" , |
41 | "filesize=256,filecount=11" , |
42 | "filesize=0" , "filecount=1" , |
43 | "filesize=1m" , "filesize=1M" , |
44 | "filesize=1k" , "filesize=1G" |
45 | }; |
46 | |
47 | // Override LogOutput's vm_start time to get predictable file name |
48 | LogFileOutput::set_file_name_parameters(0); |
49 | |
50 | for (size_t i = 0; i < ARRAY_SIZE(valid_options); i++) { |
51 | ResourceMark rm; |
52 | stringStream ss; |
53 | { |
54 | LogFileOutput fo(name); |
55 | EXPECT_STREQ(name, fo.name()); |
56 | EXPECT_TRUE(fo.initialize(valid_options[i], &ss)) |
57 | << "Did not accept valid option(s) '" << valid_options[i] << "': " << ss.as_string(); |
58 | remove(fo.cur_log_file_name()); |
59 | } |
60 | } |
61 | } |
62 | |
63 | // Test parsing a bunch of invalid file output options |
64 | TEST_VM(LogFileOutput, parse_invalid) { |
65 | const char* invalid_options[] = { |
66 | "invalidopt" , "filecount=" , |
67 | "filesize=,filecount=10" , |
68 | "fileco=10" , "ilesize=512" , |
69 | "filecount=11,,filesize=256" , |
70 | ",filesize=256,filecount=11" , |
71 | "filesize=256,filecount=11," , |
72 | "filesize=-1" , "filecount=0.1" , |
73 | "filecount=-2" , "filecount=2.0" , |
74 | "filecount= 2" , "filesize=2 " , |
75 | "filecount=ab" , "filesize=0xz" , |
76 | "filecount=1MB" , "filesize=99bytes" , |
77 | "filesize=9999999999999999999999999" |
78 | "filecount=9999999999999999999999999" |
79 | }; |
80 | |
81 | for (size_t i = 0; i < ARRAY_SIZE(invalid_options); i++) { |
82 | ResourceMark rm; |
83 | stringStream ss; |
84 | LogFileOutput fo(name); |
85 | EXPECT_FALSE(fo.initialize(invalid_options[i], &ss)) |
86 | << "Accepted invalid option(s) '" << invalid_options[i] << "': " << ss.as_string(); |
87 | } |
88 | } |
89 | |
90 | // Test for overflows with filesize |
91 | TEST_VM(LogFileOutput, filesize_overflow) { |
92 | char buf[256]; |
93 | int ret = jio_snprintf(buf, sizeof(buf), "filesize=" SIZE_FORMAT "K" , SIZE_MAX); |
94 | ASSERT_GT(ret, 0) << "Buffer too small" ; |
95 | |
96 | ResourceMark rm; |
97 | stringStream ss; |
98 | LogFileOutput fo(name); |
99 | EXPECT_FALSE(fo.initialize(buf, &ss)) << "Accepted filesize that overflows" ; |
100 | } |
101 | |
102 | TEST_VM(LogFileOutput, startup_rotation) { |
103 | ResourceMark rm; |
104 | const size_t rotations = 5; |
105 | const char* filename = prepend_temp_dir("start-rotate-test" ); |
106 | char* rotated_file[rotations]; |
107 | |
108 | for (size_t i = 0; i < rotations; i++) { |
109 | size_t len = strlen(filename) + 3; |
110 | rotated_file[i] = NEW_RESOURCE_ARRAY(char, len); |
111 | int ret = jio_snprintf(rotated_file[i], len, "%s." SIZE_FORMAT, filename, i); |
112 | ASSERT_NE(-1, ret); |
113 | delete_file(rotated_file[i]); |
114 | } |
115 | |
116 | delete_file(filename); |
117 | init_log_file(filename); |
118 | ASSERT_TRUE(file_exists(filename)) |
119 | << "configured logging to file '" << filename << "' but file was not found" ; |
120 | |
121 | // Initialize the same file a bunch more times to trigger rotations |
122 | for (size_t i = 0; i < rotations; i++) { |
123 | init_log_file(filename); |
124 | EXPECT_TRUE(file_exists(rotated_file[i])); |
125 | } |
126 | |
127 | // Remove a file and expect its slot to be re-used |
128 | delete_file(rotated_file[1]); |
129 | init_log_file(filename); |
130 | EXPECT_TRUE(file_exists(rotated_file[1])); |
131 | |
132 | // Clean up after test |
133 | delete_file(filename); |
134 | for (size_t i = 0; i < rotations; i++) { |
135 | delete_file(rotated_file[i]); |
136 | } |
137 | } |
138 | |
139 | TEST_VM(LogFileOutput, startup_truncation) { |
140 | ResourceMark rm; |
141 | const char* filename = prepend_temp_dir("start-truncate-test" ); |
142 | const char* archived_filename = prepend_temp_dir("start-truncate-test.0" ); |
143 | |
144 | delete_file(filename); |
145 | delete_file(archived_filename); |
146 | |
147 | // Use the same log file twice and expect it to be overwritten/truncated |
148 | init_log_file(filename, "filecount=0" ); |
149 | ASSERT_TRUE(file_exists(filename)) |
150 | << "configured logging to file '" << filename << "' but file was not found" ; |
151 | |
152 | init_log_file(filename, "filecount=0" ); |
153 | ASSERT_TRUE(file_exists(filename)) |
154 | << "configured logging to file '" << filename << "' but file was not found" ; |
155 | EXPECT_FALSE(file_exists(archived_filename)) |
156 | << "existing log file was not properly truncated when filecount was 0" ; |
157 | |
158 | // Verify that the file was really truncated and not just appended |
159 | EXPECT_TRUE(file_contains_substring(filename, LOG_TEST_STRING_LITERAL)); |
160 | const char* repeated[] = { LOG_TEST_STRING_LITERAL, LOG_TEST_STRING_LITERAL }; |
161 | EXPECT_FALSE(file_contains_substrings_in_order(filename, repeated)) |
162 | << "log file " << filename << " appended rather than truncated" ; |
163 | |
164 | delete_file(filename); |
165 | delete_file(archived_filename); |
166 | } |
167 | |
168 | TEST_VM(LogFileOutput, invalid_file) { |
169 | ResourceMark rm; |
170 | stringStream ss; |
171 | |
172 | // Attempt to log to a directory (existing log not a regular file) |
173 | create_directory("tmplogdir" ); |
174 | LogFileOutput bad_file("file=tmplogdir" ); |
175 | EXPECT_FALSE(bad_file.initialize("" , &ss)) |
176 | << "file was initialized when there was an existing directory with the same name" ; |
177 | EXPECT_TRUE(string_contains_substring(ss.as_string(), "tmplogdir is not a regular file" )) |
178 | << "missing expected error message, received msg: %s" << ss.as_string(); |
179 | delete_empty_directory("tmplogdir" ); |
180 | } |
181 | |