Coverage for manila/tests/share/drivers/quobyte/test_jsonrpc.py: 100%

93 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2026-02-18 22:19 +0000

1# Copyright (c) 2015 Quobyte, Inc. 

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 tempfile 

17import time 

18from unittest import mock 

19 

20import requests 

21from requests import auth 

22from requests import exceptions 

23 

24from manila import exception 

25from manila.share.drivers.quobyte import jsonrpc 

26from manila import test 

27 

28 

29class FakeResponse(object): 

30 def __init__(self, status, body): 

31 self.status_code = status 

32 self.reason = "HTTP reason" 

33 self.body = body 

34 self.text = str(body) 

35 

36 def json(self): 

37 return self.body 

38 

39 

40class QuobyteJsonRpcTestCase(test.TestCase): 

41 

42 def setUp(self): 

43 super(QuobyteJsonRpcTestCase, self).setUp() 

44 self.rpc = jsonrpc.JsonRpc(url="http://test", 

45 user_credentials=("me", "team")) 

46 self.mock_object(time, 'sleep') 

47 

48 @mock.patch.object(requests, 'post', 

49 return_value=FakeResponse(200, {"result": "yes"})) 

50 def test_request_generation_and_basic_auth(self, req_get_mock): 

51 self.rpc.call('method', {'param': 'value'}) 

52 

53 req_get_mock.assert_called_once_with( 

54 url='http://test', 

55 auth=auth.HTTPBasicAuth("me", "team"), 

56 json=mock.ANY, 

57 timeout=60) 

58 

59 def test_jsonrpc_init_with_ca(self): 

60 foofile = tempfile.TemporaryFile() 

61 fake_url = "https://foo.bar/" 

62 fake_credentials = ('fakeuser', 'fakepwd') 

63 fake_cert_file = tempfile.TemporaryFile() 

64 fake_key_file = tempfile.TemporaryFile() 

65 self.rpc = jsonrpc.JsonRpc(url=fake_url, 

66 user_credentials=fake_credentials, 

67 ca_file=foofile, 

68 key_file=fake_key_file, 

69 cert_file=fake_cert_file) 

70 

71 self.assertEqual("https", self.rpc._url_scheme) 

72 self.assertEqual(fake_url, self.rpc._url) 

73 self.assertEqual(foofile, self.rpc._ca_file) 

74 self.assertEqual(fake_cert_file, self.rpc._cert_file) 

75 self.assertEqual(fake_key_file, self.rpc._key_file) 

76 

77 @mock.patch.object(jsonrpc.LOG, "warning") 

78 def test_jsonrpc_init_without_ca(self, mock_warning): 

79 self.rpc = jsonrpc.JsonRpc("https://foo.bar/", 

80 ('fakeuser', 'fakepwd'), 

81 None) 

82 

83 mock_warning.assert_called_once_with( 

84 "Will not verify the server certificate of the API service" 

85 " because the CA certificate is not available.") 

86 

87 def test_jsonrpc_init_no_ssl(self): 

88 self.rpc = jsonrpc.JsonRpc("http://foo.bar/", 

89 ('fakeuser', 'fakepwd')) 

90 

91 self.assertEqual("http", self.rpc._url_scheme) 

92 

93 @mock.patch.object(requests, "post", 

94 return_value=FakeResponse( 

95 200, {"result": "Sweet gorilla of Manila"})) 

96 def test_successful_call(self, mock_req_get): 

97 result = self.rpc.call('method', {'param': 'value'}) 

98 

99 mock_req_get.assert_called_once_with( 

100 url=self.rpc._url, 

101 json=mock.ANY, # not checking here as of undefined order in dict 

102 auth=self.rpc._credentials, 

103 timeout=60) 

104 self.assertEqual("Sweet gorilla of Manila", result) 

105 

106 @mock.patch.object(requests, "post", 

107 return_value=FakeResponse( 

108 200, {"result": "Sweet gorilla of Manila"})) 

109 def test_https_call_with_cert(self, mock_req_get): 

110 fake_cert_file = tempfile.TemporaryFile() 

111 fake_key_file = tempfile.TemporaryFile() 

112 self.rpc = jsonrpc.JsonRpc(url="https://test", 

113 user_credentials=("me", "team"), 

114 cert_file=fake_cert_file, 

115 key_file=fake_key_file) 

116 

117 result = self.rpc.call('method', {'param': 'value'}) 

118 

119 mock_req_get.assert_called_once_with( 

120 url=self.rpc._url, 

121 json=mock.ANY, # not checking here as of undefined order in dict 

122 auth=self.rpc._credentials, 

123 verify=False, 

124 cert=(fake_cert_file, fake_key_file), 

125 timeout=60) 

126 self.assertEqual("Sweet gorilla of Manila", result) 

127 

128 @mock.patch.object(requests, "post", 

129 return_value=FakeResponse( 

130 200, {"result": "Sweet gorilla of Manila"})) 

131 def test_https_call_verify(self, mock_req_get): 

132 fake_ca_file = tempfile.TemporaryFile() 

133 self.rpc = jsonrpc.JsonRpc(url="https://test", 

134 user_credentials=("me", "team"), 

135 ca_file=fake_ca_file) 

136 

137 result = self.rpc.call('method', {'param': 'value'}) 

138 

139 mock_req_get.assert_called_once_with( 

140 url=self.rpc._url, 

141 json=mock.ANY, # not checking here as of undefined order in dict 

142 auth=self.rpc._credentials, 

143 verify=fake_ca_file, 

144 timeout=60) 

145 self.assertEqual("Sweet gorilla of Manila", result) 

146 

147 @mock.patch.object(jsonrpc.JsonRpc, "_checked_for_application_error", 

148 return_value="Sweet gorilla of Manila") 

149 @mock.patch.object(requests, "post", 

150 return_value=FakeResponse( 

151 200, {"result": "Sweet gorilla of Manila"})) 

152 def test_https_call_verify_expected_error(self, mock_req_get, mock_check): 

153 fake_ca_file = tempfile.TemporaryFile() 

154 self.rpc = jsonrpc.JsonRpc(url="https://test", 

155 user_credentials=("me", "team"), 

156 ca_file=fake_ca_file) 

157 

158 result = self.rpc.call('method', {'param': 'value'}, 

159 expected_errors=[42]) 

160 

161 mock_req_get.assert_called_once_with( 

162 url=self.rpc._url, 

163 json=mock.ANY, # not checking here as of undefined order in dict 

164 auth=self.rpc._credentials, 

165 verify=fake_ca_file, 

166 timeout=60) 

167 mock_check.assert_called_once_with( 

168 {'result': 'Sweet gorilla of Manila'}, [42]) 

169 self.assertEqual("Sweet gorilla of Manila", result) 

170 

171 @mock.patch.object(requests, "post", side_effect=exceptions.HTTPError) 

172 def test_jsonrpc_call_http_exception(self, req_get_mock): 

173 self.assertRaises(exceptions.HTTPError, 

174 self.rpc.call, 

175 'method', {'param': 'value'}) 

176 req_get_mock.assert_called_once_with( 

177 url=self.rpc._url, 

178 json=mock.ANY, # not checking here as of undefined order in dict 

179 auth=self.rpc._credentials, 

180 timeout=60) 

181 

182 @mock.patch.object(requests, "post", 

183 return_value=FakeResponse( 

184 200, 

185 {"error": {"code": 28, "message": "text"}})) 

186 def test_application_error(self, req_get_mock): 

187 self.assertRaises(exception.QBRpcException, 

188 self.rpc.call, 'method', {'param': 'value'}) 

189 req_get_mock.assert_called_once_with( 

190 url=self.rpc._url, 

191 json=mock.ANY, # not checking here as of undefined order in dict 

192 auth=self.rpc._credentials, 

193 timeout=60) 

194 

195 def test_checked_for_application_error(self): 

196 resultdict = {"result": "Sweet gorilla of Manila"} 

197 self.assertEqual("Sweet gorilla of Manila", 

198 (self.rpc._checked_for_application_error( 

199 result=resultdict))) 

200 

201 def test_checked_for_application_error_enf(self): 

202 resultdict = {"result": "Sweet gorilla of Manila", 

203 "error": {"message": "No Gorilla", 

204 "code": jsonrpc.ERROR_ENTITY_NOT_FOUND}} 

205 self.assertIsNone( 

206 self.rpc._checked_for_application_error( 

207 result=resultdict, 

208 expected_errors=[jsonrpc.ERROR_ENTITY_NOT_FOUND])) 

209 

210 def test_checked_for_application_error_no_entry(self): 

211 resultdict = {"result": "Sweet gorilla of Manila", 

212 "error": {"message": "No Gorilla", 

213 "code": jsonrpc.ERROR_ENOENT}} 

214 self.assertIsNone( 

215 self.rpc._checked_for_application_error( 

216 result=resultdict, expected_errors=[jsonrpc.ERROR_ENOENT])) 

217 

218 def test_checked_for_application_error_exception(self): 

219 self.assertRaises(exception.QBRpcException, 

220 self.rpc._checked_for_application_error, 

221 {"result": "Sweet gorilla of Manila", 

222 "error": {"message": "No Gorilla", 

223 "code": 666 

224 } 

225 } 

226 )