]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | ||
4 | #include "test/librados_test_stub/TestClassHandler.h" | |
5 | #include "test/librados_test_stub/TestIoCtxImpl.h" | |
6 | #include <boost/algorithm/string/predicate.hpp> | |
7 | #include <dlfcn.h> | |
8 | #include <errno.h> | |
9 | #include <stdlib.h> | |
10 | #include <string.h> | |
11 | #include "common/debug.h" | |
11fdf7f2 | 12 | #include "include/ceph_assert.h" |
7c673cae FG |
13 | |
14 | #define dout_context g_ceph_context | |
15 | #define dout_subsys ceph_subsys_rados | |
16 | ||
17 | namespace librados { | |
18 | ||
19 | TestClassHandler::TestClassHandler() { | |
20 | } | |
21 | ||
22 | TestClassHandler::~TestClassHandler() { | |
23 | for (ClassHandles::iterator it = m_class_handles.begin(); | |
24 | it != m_class_handles.end(); ++it) { | |
25 | dlclose(*it); | |
26 | } | |
27 | } | |
28 | ||
29 | void TestClassHandler::open_class(const std::string& name, | |
30 | const std::string& path) { | |
31 | void *handle = dlopen(path.c_str(), RTLD_NOW); | |
32 | if (handle == NULL) { | |
11fdf7f2 TL |
33 | std::cerr << "Failed to load class: " << name << " (" << path << "): " |
34 | << dlerror() << std::endl; | |
7c673cae FG |
35 | return; |
36 | } | |
11fdf7f2 TL |
37 | |
38 | // clear any existing error | |
39 | dlerror(); | |
7c673cae FG |
40 | |
41 | // initialize | |
42 | void (*cls_init)() = reinterpret_cast<void (*)()>( | |
11fdf7f2 TL |
43 | dlsym(handle, "__cls_init")); |
44 | ||
45 | char* error = nullptr; | |
46 | if ((error = dlerror()) != nullptr) { | |
47 | std::cerr << "Error locating initializer: " << error << std::endl; | |
48 | } else if (cls_init) { | |
49 | m_class_handles.push_back(handle); | |
7c673cae | 50 | cls_init(); |
11fdf7f2 | 51 | return; |
7c673cae | 52 | } |
11fdf7f2 TL |
53 | |
54 | std::cerr << "Class: " << name << " (" << path << ") missing initializer" | |
55 | << std::endl; | |
56 | dlclose(handle); | |
7c673cae FG |
57 | } |
58 | ||
59 | void TestClassHandler::open_all_classes() { | |
11fdf7f2 | 60 | ceph_assert(m_class_handles.empty()); |
7c673cae FG |
61 | |
62 | const char* env = getenv("CEPH_LIB"); | |
11fdf7f2 | 63 | std::string CEPH_LIB(env ? env : "lib"); |
7c673cae FG |
64 | DIR *dir = ::opendir(CEPH_LIB.c_str()); |
65 | if (dir == NULL) { | |
11fdf7f2 | 66 | ceph_abort();; |
7c673cae FG |
67 | } |
68 | ||
11fdf7f2 | 69 | std::set<std::string> names; |
7c673cae FG |
70 | struct dirent *pde = nullptr; |
71 | while ((pde = ::readdir(dir))) { | |
72 | std::string name(pde->d_name); | |
73 | if (!boost::algorithm::starts_with(name, "libcls_") || | |
74 | !boost::algorithm::ends_with(name, ".so")) { | |
75 | continue; | |
76 | } | |
11fdf7f2 TL |
77 | names.insert(name); |
78 | } | |
79 | ||
80 | for (auto& name : names) { | |
7c673cae FG |
81 | std::string class_name = name.substr(7, name.size() - 10); |
82 | open_class(class_name, CEPH_LIB + "/" + name); | |
83 | } | |
84 | closedir(dir); | |
85 | } | |
86 | ||
87 | int TestClassHandler::create(const std::string &name, cls_handle_t *handle) { | |
88 | if (m_classes.find(name) != m_classes.end()) { | |
11fdf7f2 | 89 | std::cerr << "Class " << name << " already exists" << std::endl; |
7c673cae FG |
90 | return -EEXIST; |
91 | } | |
92 | ||
93 | SharedClass cls(new Class()); | |
94 | m_classes[name] = cls; | |
95 | *handle = reinterpret_cast<cls_handle_t>(cls.get()); | |
96 | return 0; | |
97 | } | |
98 | ||
99 | int TestClassHandler::create_method(cls_handle_t hclass, | |
100 | const char *name, | |
101 | cls_method_cxx_call_t class_call, | |
102 | cls_method_handle_t *handle) { | |
103 | Class *cls = reinterpret_cast<Class*>(hclass); | |
104 | if (cls->methods.find(name) != cls->methods.end()) { | |
11fdf7f2 TL |
105 | std::cerr << "Class method " << hclass << ":" << name << " already exists" |
106 | << std::endl; | |
7c673cae FG |
107 | return -EEXIST; |
108 | } | |
109 | ||
110 | SharedMethod method(new Method()); | |
111 | method->class_call = class_call; | |
112 | cls->methods[name] = method; | |
113 | return 0; | |
114 | } | |
115 | ||
116 | cls_method_cxx_call_t TestClassHandler::get_method(const std::string &cls, | |
117 | const std::string &method) { | |
118 | Classes::iterator c_it = m_classes.find(cls); | |
119 | if (c_it == m_classes.end()) { | |
11fdf7f2 | 120 | std::cerr << "Failed to located class " << cls << std::endl; |
7c673cae FG |
121 | return NULL; |
122 | } | |
123 | ||
124 | SharedClass scls = c_it->second; | |
125 | Methods::iterator m_it = scls->methods.find(method); | |
126 | if (m_it == scls->methods.end()) { | |
11fdf7f2 TL |
127 | std::cerr << "Failed to located class method" << cls << "." << method |
128 | << std::endl; | |
7c673cae FG |
129 | return NULL; |
130 | } | |
131 | return m_it->second->class_call; | |
132 | } | |
133 | ||
134 | TestClassHandler::SharedMethodContext TestClassHandler::get_method_context( | |
135 | TestIoCtxImpl *io_ctx_impl, const std::string &oid, | |
136 | const SnapContext &snapc) { | |
137 | SharedMethodContext ctx(new MethodContext()); | |
138 | ||
139 | // clone to ioctx to provide a firewall for gmock expectations | |
140 | ctx->io_ctx_impl = io_ctx_impl->clone(); | |
141 | ctx->oid = oid; | |
142 | ctx->snapc = snapc; | |
143 | return ctx; | |
144 | } | |
145 | ||
146 | int TestClassHandler::create_filter(cls_handle_t hclass, | |
147 | const std::string& name, | |
148 | cls_cxx_filter_factory_t fn) | |
149 | { | |
150 | Class *cls = reinterpret_cast<Class*>(hclass); | |
151 | if (cls->filters.find(name) != cls->filters.end()) { | |
152 | return -EEXIST; | |
153 | } | |
154 | cls->filters[name] = fn; | |
155 | return 0; | |
156 | } | |
157 | ||
158 | TestClassHandler::MethodContext::~MethodContext() { | |
159 | io_ctx_impl->put(); | |
160 | } | |
161 | ||
162 | } // namespace librados |