4 # Copyright (C) 2013 Google Inc.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 """Support for mocking the opcode processor"""
27 from ganeti import constants
28 from ganeti import mcpu
31 class LogRecordingCallback(mcpu.OpExecCbBase):
32 """Helper class for log output recording.
35 def __init__(self, processor):
36 self.processor = processor
38 def Feedback(self, *args):
42 log_type = constants.ELOG_MESSAGE
45 (log_type, log_msg) = args
47 self.processor.log_entries.append((log_type, log_msg))
49 def SubmitManyJobs(self, jobs):
51 for idx, _ in enumerate(jobs):
52 results.append((True, idx))
56 class ProcessorMock(mcpu.Processor):
57 """Mocked opcode processor for tests.
59 This class actually performs much more than a mock, as it drives the
60 execution of LU's. But it also provides access to the log output of the LU
61 the result of the execution.
63 See L{ExecOpCodeAndRecordOutput} for the main method of this class.
67 def __init__(self, context):
68 super(ProcessorMock, self).__init__(context, 1, True)
70 self._lu_test_func = None
72 def ExecOpCodeAndRecordOutput(self, op):
73 """Executes the given opcode and records the output for further inspection.
75 @param op: the opcode to execute.
76 @return: see L{mcpu.Processor.ExecOpCode}
79 return self.ExecOpCode(op, LogRecordingCallback(self))
81 def _ExecLU(self, lu):
82 if not self._lu_test_func:
83 return super(ProcessorMock, self)._ExecLU(lu)
85 # required by a lot LU's, and usually passed in Exec
86 lu._feedback_fn = self.Log
87 return self._lu_test_func(lu)
89 def _CheckLUResult(self, op, result):
90 if not self._lu_test_func:
91 return super(ProcessorMock, self)._CheckLUResult(op, result)
95 def RunWithLockedLU(self, op, func):
96 """Takes the given opcode, creates a LU and runs func with it.
98 @param op: the opcode to get the LU for.
99 @param func: the function to run with the created and locked LU.
100 @return: the result of func.
103 self._lu_test_func = func
105 return self.ExecOpCodeAndRecordOutput(op)
107 self._lu_test_func = None
109 def GetLogEntries(self):
110 """Return the list of recorded log entries.
112 @rtype: list of (string, string) tuples
113 @return: the list of recorded log entries
116 return self.log_entries
118 def GetLogMessages(self):
119 """Return the list of recorded log messages.
121 @rtype: list of string
122 @return: the list of recorded log messages
125 return [msg for _, msg in self.log_entries]
127 def GetLogEntriesString(self):
128 """Return a string with all log entries separated by a newline.
131 return "\n".join("%s: %s" % (log_type, msg)
132 for log_type, msg in self.GetLogEntries())
134 def GetLogMessagesString(self):
135 """Return a string with all log messages separated by a newline.
138 return "\n".join("%s" % msg for _, msg in self.GetLogEntries())
140 def assertLogContainsEntry(self, expected_type, expected_msg):
141 """Asserts that the log contains the exact given entry.
143 @type expected_type: string
144 @param expected_type: the expected type
145 @type expected_msg: string
146 @param expected_msg: the expected message
149 for log_type, msg in self.log_entries:
150 if log_type == expected_type and msg == expected_msg:
153 raise AssertionError(
154 "Could not find '%s' (type '%s') in LU log messages. Log is:\n%s" %
155 (expected_msg, expected_type, self.GetLogEntriesString()))
157 def assertLogContainsMessage(self, expected_msg):
158 """Asserts that the log contains the exact given message.
160 @type expected_msg: string
161 @param expected_msg: the expected message
164 for msg in self.GetLogMessages():
165 if msg == expected_msg:
168 raise AssertionError(
169 "Could not find '%s' in LU log messages. Log is:\n%s" %
170 (expected_msg, self.GetLogMessagesString()))
172 def assertLogContainsRegex(self, expected_regex):
173 """Asserts that the log contains a message which matches the regex.
175 @type expected_regex: string
176 @param expected_regex: regular expression to match messages with.
179 for msg in self.GetLogMessages():
180 if re.search(expected_regex, msg) is not None:
183 raise AssertionError(
184 "Could not find '%s' in LU log messages. Log is:\n%s" %
185 (expected_regex, self.GetLogMessagesString())
188 def assertLogContainsInLine(self, expected):
189 """Asserts that the log contains a message which contains a string.
191 @type expected: string
192 @param expected: string to search in messages.
195 self.assertLogContainsRegex(re.escape(expected))
197 def assertLogDoesNotContainRegex(self, expected_regex):
198 """Asserts that the log does not contain a message which matches the regex.
200 @type expected_regex: string
201 @param expected_regex: regular expression to match messages with.
204 for msg in self.GetLogMessages():
205 if re.search(expected_regex, msg) is not None:
206 raise AssertionError(
207 "Found '%s' in LU log messages. Log is:\n%s" %
208 (expected_regex, self.GetLogMessagesString())
211 def assertLogIsEmpty(self):
212 """Asserts that the log does not contain any message.
215 if len(self.GetLogMessages()) > 0:
216 raise AssertionError("Log is not empty. Log is:\n%s" %
217 self.GetLogMessagesString())
219 def ClearLogMessages(self):
220 """Clears all recorded log messages.
222 This is useful if you use L{GetLockedLU} and want to test multiple calls
226 self.log_entries = []