Statistics
| Branch: | Tag: | Revision:

root / test / py / cmdlib / testsupport / processor_mock.py @ f3cb57d5

History | View | Annotate | Download (6.4 kB)

1
#
2
#
3

    
4
# Copyright (C) 2013 Google Inc.
5
#
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.
10
#
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.
15
#
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
19
# 02110-1301, USA.
20

    
21

    
22
"""Support for mocking the opcode processor"""
23

    
24

    
25
import re
26

    
27
from ganeti import constants
28
from ganeti import mcpu
29

    
30

    
31
class LogRecordingCallback(mcpu.OpExecCbBase):
32
  """Helper class for log output recording.
33

34
  """
35
  def __init__(self, processor):
36
    self.processor = processor
37

    
38
  def Feedback(self, *args):
39
    assert len(args) < 3
40

    
41
    if len(args) == 1:
42
      log_type = constants.ELOG_MESSAGE
43
      log_msg = args[0]
44
    else:
45
      (log_type, log_msg) = args
46

    
47
    self.processor.log_entries.append((log_type, log_msg))
48

    
49
  def SubmitManyJobs(self, jobs):
50
    results = []
51
    for idx, _ in enumerate(jobs):
52
      results.append((True, idx))
53
    return results
54

    
55

    
56
class ProcessorMock(mcpu.Processor):
57
  """Mocked opcode processor for tests.
58

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.
62

63
  See L{ExecOpCodeAndRecordOutput} for the main method of this class.
64

65
  """
66

    
67
  def __init__(self, context):
68
    super(ProcessorMock, self).__init__(context, 1, True)
69
    self.log_entries = []
70
    self._lu_test_func = None
71

    
72
  def ExecOpCodeAndRecordOutput(self, op):
73
    """Executes the given opcode and records the output for further inspection.
74

75
    @param op: the opcode to execute.
76
    @return: see L{mcpu.Processor.ExecOpCode}
77

78
    """
79
    return self.ExecOpCode(op, LogRecordingCallback(self))
80

    
81
  def _ExecLU(self, lu):
82
    # pylint: disable=W0212
83
    if not self._lu_test_func:
84
      return super(ProcessorMock, self)._ExecLU(lu)
85
    else:
86
      # required by a lot LU's, and usually passed in Exec
87
      lu._feedback_fn = self.Log
88
      return self._lu_test_func(lu)
89

    
90
  def _CheckLUResult(self, op, result):
91
    # pylint: disable=W0212
92
    if not self._lu_test_func:
93
      return super(ProcessorMock, self)._CheckLUResult(op, result)
94
    else:
95
      pass
96

    
97
  def RunWithLockedLU(self, op, func):
98
    """Takes the given opcode, creates a LU and runs func with it.
99

100
    @param op: the opcode to get the LU for.
101
    @param func: the function to run with the created and locked LU.
102
    @return: the result of func.
103

104
    """
105
    self._lu_test_func = func
106
    try:
107
      return self.ExecOpCodeAndRecordOutput(op)
108
    finally:
109
      self._lu_test_func = None
110

    
111
  def GetLogEntries(self):
112
    """Return the list of recorded log entries.
113

114
    @rtype: list of (string, string) tuples
115
    @return: the list of recorded log entries
116

117
    """
118
    return self.log_entries
119

    
120
  def GetLogMessages(self):
121
    """Return the list of recorded log messages.
122

123
    @rtype: list of string
124
    @return: the list of recorded log messages
125

126
    """
127
    return [msg for _, msg in self.log_entries]
128

    
129
  def GetLogEntriesString(self):
130
    """Return a string with all log entries separated by a newline.
131

132
    """
133
    return "\n".join("%s: %s" % (log_type, msg)
134
                     for log_type, msg in self.GetLogEntries())
135

    
136
  def GetLogMessagesString(self):
137
    """Return a string with all log messages separated by a newline.
138

139
    """
140
    return "\n".join("%s" % msg for _, msg in self.GetLogEntries())
141

    
142
  def assertLogContainsEntry(self, expected_type, expected_msg):
143
    """Asserts that the log contains the exact given entry.
144

145
    @type expected_type: string
146
    @param expected_type: the expected type
147
    @type expected_msg: string
148
    @param expected_msg: the expected message
149

150
    """
151
    for log_type, msg in self.log_entries:
152
      if log_type == expected_type and msg == expected_msg:
153
        return
154

    
155
    raise AssertionError(
156
      "Could not find '%s' (type '%s') in LU log messages. Log is:\n%s" %
157
      (expected_msg, expected_type, self.GetLogEntriesString()))
158

    
159
  def assertLogContainsMessage(self, expected_msg):
160
    """Asserts that the log contains the exact given message.
161

162
    @type expected_msg: string
163
    @param expected_msg: the expected message
164

165
    """
166
    for msg in self.GetLogMessages():
167
      if msg == expected_msg:
168
        return
169

    
170
    raise AssertionError(
171
      "Could not find '%s' in LU log messages. Log is:\n%s" %
172
      (expected_msg, self.GetLogMessagesString()))
173

    
174
  def assertLogContainsRegex(self, expected_regex):
175
    """Asserts that the log contains a message which matches the regex.
176

177
    @type expected_regex: string
178
    @param expected_regex: regular expression to match messages with.
179

180
    """
181
    for msg in self.GetLogMessages():
182
      if re.search(expected_regex, msg) is not None:
183
        return
184

    
185
    raise AssertionError(
186
      "Could not find '%s' in LU log messages. Log is:\n%s" %
187
      (expected_regex, self.GetLogMessagesString())
188
    )
189

    
190
  def assertLogContainsInLine(self, expected):
191
    """Asserts that the log contains a message which contains a string.
192

193
    @type expected: string
194
    @param expected: string to search in messages.
195

196
    """
197
    self.assertLogContainsRegex(re.escape(expected))
198

    
199
  def assertLogDoesNotContainRegex(self, expected_regex):
200
    """Asserts that the log does not contain a message which matches the regex.
201

202
    @type expected_regex: string
203
    @param expected_regex: regular expression to match messages with.
204

205
    """
206
    for msg in self.GetLogMessages():
207
      if re.search(expected_regex, msg) is not None:
208
        raise AssertionError(
209
          "Found '%s' in LU log messages. Log is:\n%s" %
210
          (expected_regex, self.GetLogMessagesString())
211
        )
212

    
213
  def assertLogIsEmpty(self):
214
    """Asserts that the log does not contain any message.
215

216
    """
217
    if len(self.GetLogMessages()) > 0:
218
      raise AssertionError("Log is not empty. Log is:\n%s" %
219
                           self.GetLogMessagesString())
220

    
221
  def ClearLogMessages(self):
222
    """Clears all recorded log messages.
223

224
    This is useful if you use L{GetLockedLU} and want to test multiple calls
225
    on it.
226

227
    """
228
    self.log_entries = []