blob: b97dd8627a97c02b82c2baaf772174ff09734772 [file] [log] [blame]
Maru Newbyb096d9f2015-03-09 18:54:54 +00001# Copyright 2012 OpenStack Foundation
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
16import inspect
17import re
18
Ihar Hrachyshkac695f9f2015-02-26 23:26:41 +010019from oslo_log import log as logging
Maru Newbyb096d9f2015-03-09 18:54:54 +000020
21LOG = logging.getLogger(__name__)
22
23
24def singleton(cls):
25 """Simple wrapper for classes that should only have a single instance."""
26 instances = {}
27
28 def getinstance():
29 if cls not in instances:
30 instances[cls] = cls()
31 return instances[cls]
32 return getinstance
33
34
35def find_test_caller():
36 """Find the caller class and test name.
37
38 Because we know that the interesting things that call us are
39 test_* methods, and various kinds of setUp / tearDown, we
40 can look through the call stack to find appropriate methods,
41 and the class we were in when those were called.
42 """
43 caller_name = None
44 names = []
45 frame = inspect.currentframe()
46 is_cleanup = False
47 # Start climbing the ladder until we hit a good method
48 while True:
49 try:
50 frame = frame.f_back
51 name = frame.f_code.co_name
52 names.append(name)
53 if re.search("^(test_|setUp|tearDown)", name):
54 cname = ""
55 if 'self' in frame.f_locals:
56 cname = frame.f_locals['self'].__class__.__name__
57 if 'cls' in frame.f_locals:
58 cname = frame.f_locals['cls'].__name__
59 caller_name = cname + ":" + name
60 break
61 elif re.search("^_run_cleanup", name):
62 is_cleanup = True
63 elif name == 'main':
64 caller_name = 'main'
65 break
66 else:
67 cname = ""
68 if 'self' in frame.f_locals:
69 cname = frame.f_locals['self'].__class__.__name__
70 if 'cls' in frame.f_locals:
71 cname = frame.f_locals['cls'].__name__
72
73 # the fact that we are running cleanups is indicated pretty
74 # deep in the stack, so if we see that we want to just
75 # start looking for a real class name, and declare victory
76 # once we do.
77 if is_cleanup and cname:
78 if not re.search("^RunTest", cname):
79 caller_name = cname + ":_run_cleanups"
80 break
81 except Exception:
82 break
83 # prevents frame leaks
84 del frame
85 if caller_name is None:
86 LOG.debug("Sane call name not found in %s" % names)
87 return caller_name