Statistics
| Branch: | Tag: | Revision:

root / lib / rapi / testutils.py @ f90a1ab5

History | View | Annotate | Download (4 kB)

1 a85f23fa Michael Hanselmann
#
2 a85f23fa Michael Hanselmann
#
3 a85f23fa Michael Hanselmann
4 a85f23fa Michael Hanselmann
# Copyright (C) 2012 Google Inc.
5 a85f23fa Michael Hanselmann
#
6 a85f23fa Michael Hanselmann
# This program is free software; you can redistribute it and/or modify
7 a85f23fa Michael Hanselmann
# it under the terms of the GNU General Public License as published by
8 a85f23fa Michael Hanselmann
# the Free Software Foundation; either version 2 of the License, or
9 a85f23fa Michael Hanselmann
# (at your option) any later version.
10 a85f23fa Michael Hanselmann
#
11 a85f23fa Michael Hanselmann
# This program is distributed in the hope that it will be useful, but
12 a85f23fa Michael Hanselmann
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a85f23fa Michael Hanselmann
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 a85f23fa Michael Hanselmann
# General Public License for more details.
15 a85f23fa Michael Hanselmann
#
16 a85f23fa Michael Hanselmann
# You should have received a copy of the GNU General Public License
17 a85f23fa Michael Hanselmann
# along with this program; if not, write to the Free Software
18 a85f23fa Michael Hanselmann
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a85f23fa Michael Hanselmann
# 02110-1301, USA.
20 a85f23fa Michael Hanselmann
21 a85f23fa Michael Hanselmann
22 a85f23fa Michael Hanselmann
"""Remote API test utilities.
23 a85f23fa Michael Hanselmann

24 a85f23fa Michael Hanselmann
"""
25 a85f23fa Michael Hanselmann
26 a85f23fa Michael Hanselmann
import logging
27 f90a1ab5 René Nussbaumer
import re
28 f90a1ab5 René Nussbaumer
import pycurl
29 a85f23fa Michael Hanselmann
30 a85f23fa Michael Hanselmann
from ganeti import errors
31 a85f23fa Michael Hanselmann
from ganeti import opcodes
32 a85f23fa Michael Hanselmann
33 a85f23fa Michael Hanselmann
34 f90a1ab5 René Nussbaumer
_URI_RE = re.compile(r"https://(?P<host>.*):(?P<port>\d+)(?P<path>/.*)")
35 f90a1ab5 René Nussbaumer
36 f90a1ab5 René Nussbaumer
37 a85f23fa Michael Hanselmann
class VerificationError(Exception):
38 a85f23fa Michael Hanselmann
  """Dedicated error class for test utilities.
39 a85f23fa Michael Hanselmann

40 a85f23fa Michael Hanselmann
  This class is used to hide all of Ganeti's internal exception, so that
41 a85f23fa Michael Hanselmann
  external users of these utilities don't have to integrate Ganeti's exception
42 a85f23fa Michael Hanselmann
  hierarchy.
43 a85f23fa Michael Hanselmann

44 a85f23fa Michael Hanselmann
  """
45 a85f23fa Michael Hanselmann
46 a85f23fa Michael Hanselmann
47 a85f23fa Michael Hanselmann
def _GetOpById(op_id):
48 a85f23fa Michael Hanselmann
  """Tries to get an opcode class based on its C{OP_ID}.
49 a85f23fa Michael Hanselmann

50 a85f23fa Michael Hanselmann
  """
51 a85f23fa Michael Hanselmann
  try:
52 a85f23fa Michael Hanselmann
    return opcodes.OP_MAPPING[op_id]
53 a85f23fa Michael Hanselmann
  except KeyError:
54 a85f23fa Michael Hanselmann
    raise VerificationError("Unknown opcode ID '%s'" % op_id)
55 a85f23fa Michael Hanselmann
56 a85f23fa Michael Hanselmann
57 a85f23fa Michael Hanselmann
def _HideInternalErrors(fn):
58 a85f23fa Michael Hanselmann
  """Hides Ganeti-internal exceptions, see L{VerificationError}.
59 a85f23fa Michael Hanselmann

60 a85f23fa Michael Hanselmann
  """
61 a85f23fa Michael Hanselmann
  def wrapper(*args, **kwargs):
62 a85f23fa Michael Hanselmann
    try:
63 a85f23fa Michael Hanselmann
      return fn(*args, **kwargs)
64 a85f23fa Michael Hanselmann
    except errors.GenericError, err:
65 a85f23fa Michael Hanselmann
      raise VerificationError("Unhandled Ganeti error: %s" % err)
66 a85f23fa Michael Hanselmann
67 a85f23fa Michael Hanselmann
  return wrapper
68 a85f23fa Michael Hanselmann
69 a85f23fa Michael Hanselmann
70 a85f23fa Michael Hanselmann
@_HideInternalErrors
71 a85f23fa Michael Hanselmann
def VerifyOpInput(op_id, data):
72 a85f23fa Michael Hanselmann
  """Verifies opcode parameters according to their definition.
73 a85f23fa Michael Hanselmann

74 a85f23fa Michael Hanselmann
  @type op_id: string
75 a85f23fa Michael Hanselmann
  @param op_id: Opcode ID (C{OP_ID} attribute), e.g. C{OP_CLUSTER_VERIFY}
76 a85f23fa Michael Hanselmann
  @type data: dict
77 a85f23fa Michael Hanselmann
  @param data: Opcode parameter values
78 a85f23fa Michael Hanselmann
  @raise VerificationError: Parameter verification failed
79 a85f23fa Michael Hanselmann

80 a85f23fa Michael Hanselmann
  """
81 a85f23fa Michael Hanselmann
  op_cls = _GetOpById(op_id)
82 a85f23fa Michael Hanselmann
83 a85f23fa Michael Hanselmann
  try:
84 a85f23fa Michael Hanselmann
    op = op_cls(**data) # pylint: disable=W0142
85 a85f23fa Michael Hanselmann
  except TypeError, err:
86 a85f23fa Michael Hanselmann
    raise VerificationError("Unable to create opcode instance: %s" % err)
87 a85f23fa Michael Hanselmann
88 a85f23fa Michael Hanselmann
  try:
89 a85f23fa Michael Hanselmann
    op.Validate(False)
90 a85f23fa Michael Hanselmann
  except errors.OpPrereqError, err:
91 a85f23fa Michael Hanselmann
    raise VerificationError("Parameter validation for opcode '%s' failed: %s" %
92 a85f23fa Michael Hanselmann
                            (op_id, err))
93 a85f23fa Michael Hanselmann
94 a85f23fa Michael Hanselmann
95 a85f23fa Michael Hanselmann
@_HideInternalErrors
96 a85f23fa Michael Hanselmann
def VerifyOpResult(op_id, result):
97 a85f23fa Michael Hanselmann
  """Verifies opcode results used in tests (e.g. in a mock).
98 a85f23fa Michael Hanselmann

99 a85f23fa Michael Hanselmann
  @type op_id: string
100 a85f23fa Michael Hanselmann
  @param op_id: Opcode ID (C{OP_ID} attribute), e.g. C{OP_CLUSTER_VERIFY}
101 a85f23fa Michael Hanselmann
  @param result: Mocked opcode result
102 a85f23fa Michael Hanselmann
  @raise VerificationError: Return value verification failed
103 a85f23fa Michael Hanselmann

104 a85f23fa Michael Hanselmann
  """
105 a85f23fa Michael Hanselmann
  resultcheck_fn = _GetOpById(op_id).OP_RESULT
106 a85f23fa Michael Hanselmann
107 a85f23fa Michael Hanselmann
  if not resultcheck_fn:
108 a85f23fa Michael Hanselmann
    logging.warning("Opcode '%s' has no result type definition", op_id)
109 a85f23fa Michael Hanselmann
  elif not resultcheck_fn(result):
110 a85f23fa Michael Hanselmann
    raise VerificationError("Given result does not match result description"
111 a85f23fa Michael Hanselmann
                            " for opcode '%s': %s" % (op_id, resultcheck_fn))
112 f90a1ab5 René Nussbaumer
113 f90a1ab5 René Nussbaumer
114 f90a1ab5 René Nussbaumer
def _GetPathFromUri(uri):
115 f90a1ab5 René Nussbaumer
  """Gets the path and query from a URI.
116 f90a1ab5 René Nussbaumer

117 f90a1ab5 René Nussbaumer
  """
118 f90a1ab5 René Nussbaumer
  match = _URI_RE.match(uri)
119 f90a1ab5 René Nussbaumer
  if match:
120 f90a1ab5 René Nussbaumer
    return match.groupdict()["path"]
121 f90a1ab5 René Nussbaumer
  else:
122 f90a1ab5 René Nussbaumer
    return None
123 f90a1ab5 René Nussbaumer
124 f90a1ab5 René Nussbaumer
125 f90a1ab5 René Nussbaumer
class FakeCurl:
126 f90a1ab5 René Nussbaumer
  """Fake cURL object.
127 f90a1ab5 René Nussbaumer

128 f90a1ab5 René Nussbaumer
  """
129 f90a1ab5 René Nussbaumer
  def __init__(self, handler):
130 f90a1ab5 René Nussbaumer
    """Initialize this class
131 f90a1ab5 René Nussbaumer

132 f90a1ab5 René Nussbaumer
    @param handler: Request handler instance
133 f90a1ab5 René Nussbaumer

134 f90a1ab5 René Nussbaumer
    """
135 f90a1ab5 René Nussbaumer
    self._handler = handler
136 f90a1ab5 René Nussbaumer
    self._opts = {}
137 f90a1ab5 René Nussbaumer
    self._info = {}
138 f90a1ab5 René Nussbaumer
139 f90a1ab5 René Nussbaumer
  def setopt(self, opt, value):
140 f90a1ab5 René Nussbaumer
    self._opts[opt] = value
141 f90a1ab5 René Nussbaumer
142 f90a1ab5 René Nussbaumer
  def getopt(self, opt):
143 f90a1ab5 René Nussbaumer
    return self._opts.get(opt)
144 f90a1ab5 René Nussbaumer
145 f90a1ab5 René Nussbaumer
  def unsetopt(self, opt):
146 f90a1ab5 René Nussbaumer
    self._opts.pop(opt, None)
147 f90a1ab5 René Nussbaumer
148 f90a1ab5 René Nussbaumer
  def getinfo(self, info):
149 f90a1ab5 René Nussbaumer
    return self._info[info]
150 f90a1ab5 René Nussbaumer
151 f90a1ab5 René Nussbaumer
  def perform(self):
152 f90a1ab5 René Nussbaumer
    method = self._opts[pycurl.CUSTOMREQUEST]
153 f90a1ab5 René Nussbaumer
    url = self._opts[pycurl.URL]
154 f90a1ab5 René Nussbaumer
    request_body = self._opts[pycurl.POSTFIELDS]
155 f90a1ab5 René Nussbaumer
    writefn = self._opts[pycurl.WRITEFUNCTION]
156 f90a1ab5 René Nussbaumer
157 f90a1ab5 René Nussbaumer
    path = _GetPathFromUri(url)
158 f90a1ab5 René Nussbaumer
    (code, resp_body) = self._handler.FetchResponse(path, method, request_body)
159 f90a1ab5 René Nussbaumer
160 f90a1ab5 René Nussbaumer
    self._info[pycurl.RESPONSE_CODE] = code
161 f90a1ab5 René Nussbaumer
    if resp_body is not None:
162 f90a1ab5 René Nussbaumer
      writefn(resp_body)