1 /* Copyright (c) 2015, 2021, Oracle and/or its affiliates.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License, version 2.0,
5  as published by the Free Software Foundation.
6 
7  This program is also distributed with certain software (including
8  but not limited to OpenSSL) that is licensed under separate terms,
9  as designated in a particular file or component or in included license
10  documentation.  The authors of MySQL hereby grant you an additional
11  permission to link the program and your derivative works with the
12  separately licensed software that they have included with MySQL.
13 
14  This program is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  GNU General Public License, version 2.0, for more details.
18 
19  You should have received a copy of the GNU General Public License
20  along with this program; if not, write to the Free Software
21  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
22 
23 #include <gtest/gtest.h>
24 #include <gmock/gmock.h>
25 
26 #include "ngs/memory.h"
27 #include "ngs/ngs_error.h"
28 #include "mock/capabilities.h"
29 
30 
31 const int   NUMBER_OF_HANDLERS = 4;
32 const char* NAMES[NUMBER_OF_HANDLERS] = {
33     "first",
34     "second",
35     "third",
36     "fourth"
37 };
38 
39 
40 using ::Mysqlx::Connection::Capabilities;
41 using ::Mysqlx::Connection::Capability;
42 using ::Mysqlx::Datatypes::Any;
43 
44 
45 namespace ngs
46 {
47 
48 namespace test
49 {
50 
51 
52 using namespace ::testing;
53 
54 
55 class CapabilitiesConfiguratorTestSuite : public Test
56 {
57 public:
58   typedef ngs::shared_ptr<StrictMock<Mock_capability_handler> > Mock_ptr;
59 
SetUp()60   void SetUp()
61   {
62     for(int i = 0; i < NUMBER_OF_HANDLERS; ++i)
63     {
64       mock_handlers.push_back(ngs::make_shared< StrictMock<Mock_capability_handler> >());
65     }
66 
67     std::vector<Capability_handler_ptr> handlers(mock_handlers.begin(), mock_handlers.end());
68 
69     std::for_each(mock_handlers.begin(), mock_handlers.end(), default_is_supported<false>);
70 
71     sut.reset(new Capabilities_configurator(handlers));
72   }
73 
74 
75   template<bool Result>
expect_is_supported(Mock_ptr mock)76   static void expect_is_supported(Mock_ptr mock)
77   {
78     EXPECT_CALL(*mock, is_supported()).WillOnce(Return(Result));
79   }
80 
81 
82   template<bool Result>
default_is_supported(Mock_ptr mock)83   static void default_is_supported(Mock_ptr mock)
84   {
85     EXPECT_CALL(*mock, is_supported()).WillRepeatedly(Return(Result));
86   }
87 
88 
expect_get_capability(Mock_ptr mock)89   static void expect_get_capability(Mock_ptr mock)
90   {
91     EXPECT_CALL(*mock, get_void(_));
92   }
93 
94 
expect_commit(Mock_ptr mock)95   static void expect_commit(Mock_ptr mock)
96   {
97     EXPECT_CALL(*mock, commit_void());
98   }
99 
100 
assert_get(std::vector<Mock_ptr> & supported_handlers)101   void assert_get(std::vector<Mock_ptr> &supported_handlers)
102   {
103     std::for_each(supported_handlers.begin(), supported_handlers.end(), expect_is_supported<true>);
104     std::for_each(supported_handlers.begin(), supported_handlers.end(), expect_get_name(NAMES));
105     std::for_each(supported_handlers.begin(), supported_handlers.end(), expect_get_capability);
106 
107     ngs::Memory_instrumented<Capabilities>::Unique_ptr cap(sut->get());
108     const Capabilities *null_cap = NULL;
109     ASSERT_NE(null_cap, cap.get());
110     ASSERT_EQ(static_cast<int>(supported_handlers.size()), cap->capabilities_size());
111 
112     for(std::size_t i = 0; i < supported_handlers.size();i ++)
113     {
114       ASSERT_EQ(NAMES[i], cap->capabilities(static_cast<int>(i)).name());
115     }
116   }
117 
118 
add_capability(Capabilities & caps,const std::size_t mock_index)119   Capability &add_capability(Capabilities & caps, const std::size_t mock_index)
120   {
121     Capability *cap = caps.add_capabilities();
122 
123     cap->set_name(NAMES[mock_index]);
124     cap->mutable_value()->mutable_scalar()->set_v_signed_int(mock_index);
125 
126     return *cap;
127   }
128 
129 
add_capability_and_expect_it(Capabilities & caps,const std::size_t mock_index,const bool set_result)130   Capability &add_capability_and_expect_it(Capabilities & caps, const std::size_t mock_index, const bool set_result)
131   {
132     Capability &cap = add_capability(caps, mock_index);
133 
134     EXPECT_CALL(*mock_handlers[mock_index], set(Ref(cap.value()))).WillOnce(Return(set_result));
135 
136     return cap;
137   }
138 
139 
140   struct expect_get_name
141   {
142     template<std::size_t ELEMENTS>
expect_get_namengs::test::CapabilitiesConfiguratorTestSuite::expect_get_name143     expect_get_name(const char* (&names)[ELEMENTS])
144     : m_names(names), m_elements(ELEMENTS), m_current(0)
145     {
146     }
147 
operator ()ngs::test::CapabilitiesConfiguratorTestSuite::expect_get_name148     void operator() (Mock_ptr mock)
149     {
150       EXPECT_CALL(*mock, name()).WillOnce(Return(get_next_name()));
151 
152     }
153 
get_next_namengs::test::CapabilitiesConfiguratorTestSuite::expect_get_name154     std::string get_next_name()
155     {
156       std::string result = m_names[m_current++];
157 
158        if (m_current >= m_elements)
159          m_current = 0;
160 
161        return result;
162     }
163 
164     const char**      m_names;
165     const std::size_t m_elements;
166     std::size_t       m_current;
167   };
168 
169 
170   struct default_get_name : expect_get_name
171   {
172     template<std::size_t ELEMENTS>
default_get_namengs::test::CapabilitiesConfiguratorTestSuite::default_get_name173     default_get_name(const char* (&names)[ELEMENTS]): expect_get_name(names)
174     {
175     }
176 
operator ()ngs::test::CapabilitiesConfiguratorTestSuite::default_get_name177     void operator() (Mock_ptr &mock)
178     {
179       EXPECT_CALL(*mock, name()).WillRepeatedly(Return(get_next_name()));
180     }
181   };
182 
183 
184   std::vector<Mock_ptr> mock_handlers;
185 
186   ngs::unique_ptr<Capabilities_configurator> sut;
187 };
188 
189 
TEST_F(CapabilitiesConfiguratorTestSuite,get_doesNothing_whenEmpty)190 TEST_F(CapabilitiesConfiguratorTestSuite, get_doesNothing_whenEmpty)
191 {
192   std::vector<Mock_ptr> empty;
193 
194   assert_get(empty);
195 }
196 
197 
TEST_F(CapabilitiesConfiguratorTestSuite,get_returnsAllCapabilities)198 TEST_F(CapabilitiesConfiguratorTestSuite, get_returnsAllCapabilities)
199 {
200   assert_get(mock_handlers);
201 }
202 
203 
TEST_F(CapabilitiesConfiguratorTestSuite,get_returnsOnlySupportedCaps)204 TEST_F(CapabilitiesConfiguratorTestSuite, get_returnsOnlySupportedCaps)
205 {
206   std::vector<Mock_ptr> supported_handlers;
207 
208   supported_handlers.push_back(mock_handlers[0]);
209   supported_handlers.push_back(mock_handlers[NUMBER_OF_HANDLERS-1]);
210 
211   assert_get(supported_handlers);
212 }
213 
214 
TEST_F(CapabilitiesConfiguratorTestSuite,prepareSet_errorErrorAndCommitDoesNothing_whenOneUnknownCapability)215 TEST_F(CapabilitiesConfiguratorTestSuite, prepareSet_errorErrorAndCommitDoesNothing_whenOneUnknownCapability)
216 {
217   ngs::unique_ptr<Capabilities> caps(new Capabilities());
218 
219   Capability * cap = caps->add_capabilities();
220 
221   cap->set_name("UNKNOWN");
222 
223   std::for_each(mock_handlers.begin(), mock_handlers.end(), default_get_name(NAMES));
224 
225   ASSERT_EQ(ER_X_CAPABILITY_NOT_FOUND, sut->prepare_set(*caps).error);
226 
227   sut->commit();
228 }
229 
230 
TEST_F(CapabilitiesConfiguratorTestSuite,prepareSet_success_whenAllRequestedCapsSucceded)231 TEST_F(CapabilitiesConfiguratorTestSuite, prepareSet_success_whenAllRequestedCapsSucceded)
232 {
233   ngs::unique_ptr<Capabilities> caps(new Capabilities());
234   std::vector<Mock_ptr>           supported_handlers;
235 
236   std::for_each(mock_handlers.begin(), mock_handlers.end(), default_get_name(NAMES));
237 
238   add_capability_and_expect_it(*caps, 0, true);
239   supported_handlers.push_back(mock_handlers[0]);
240 
241   add_capability_and_expect_it(*caps, NUMBER_OF_HANDLERS-1, true);
242   supported_handlers.push_back(mock_handlers[NUMBER_OF_HANDLERS-1]);
243 
244   ASSERT_FALSE(sut->prepare_set(*caps));
245 
246   std::for_each(supported_handlers.begin(), supported_handlers.end(), expect_commit);
247   sut->commit();
248 }
249 
TEST_F(CapabilitiesConfiguratorTestSuite,prepareSet_FailsAndCommitDoesNothing_whenAnyCapsFailsLast)250 TEST_F(CapabilitiesConfiguratorTestSuite, prepareSet_FailsAndCommitDoesNothing_whenAnyCapsFailsLast)
251 {
252   ngs::unique_ptr<Capabilities> caps(new Capabilities());
253   std::vector<Mock_ptr>           supported_handlers;
254 
255   std::for_each(mock_handlers.begin(), mock_handlers.end(), default_get_name(NAMES));
256 
257   add_capability_and_expect_it(*caps, 0, true);
258   supported_handlers.push_back(mock_handlers[0]);
259 
260   add_capability_and_expect_it(*caps, NUMBER_OF_HANDLERS-1, false);
261   supported_handlers.push_back(mock_handlers[NUMBER_OF_HANDLERS-1]);
262 
263   ASSERT_EQ(ER_X_CAPABILITIES_PREPARE_FAILED, sut->prepare_set(*caps).error);
264 
265   sut->commit();
266 }
267 
268 
TEST_F(CapabilitiesConfiguratorTestSuite,prepareSet_FailsAndCommitDoesNothing_whenAnyCapsFailsFirst)269 TEST_F(CapabilitiesConfiguratorTestSuite, prepareSet_FailsAndCommitDoesNothing_whenAnyCapsFailsFirst)
270 {
271   ngs::unique_ptr<Capabilities> caps(new Capabilities());
272   std::vector<Mock_ptr> supported_handlers;
273 
274   std::for_each(mock_handlers.begin(), mock_handlers.end(), default_get_name(NAMES));
275 
276   add_capability_and_expect_it(*caps, 0, false);
277   supported_handlers.push_back(mock_handlers[0]);
278 
279   add_capability(*caps, NUMBER_OF_HANDLERS-1);
280   supported_handlers.push_back(mock_handlers[NUMBER_OF_HANDLERS-1]);
281 
282   ASSERT_EQ(ER_X_CAPABILITIES_PREPARE_FAILED, sut->prepare_set(*caps).error);
283 
284   sut->commit();
285 }
286 
287 
288 } // namespace test
289 
290 } // namespace ngs
291