Skip to content

Commit 26be1c8

Browse files
committed
Adding gcloud.bigtable package.
Initial commit just adds the basic import time check for gRPC and testing for all possible install states. It also adds a shadowed _testing/grpc that we can use to mock the installed library for tests.
1 parent a019614 commit 26be1c8

File tree

11 files changed

+272
-0
lines changed

11 files changed

+272
-0
lines changed

_testing/grpc/__init__.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright 2015 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.

_testing/grpc/_adapter/__init__.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright 2015 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.

_testing/grpc/_adapter/_c.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright 2015 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright 2015 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright 2015 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright 2015 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright 2015 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright 2015 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.

gcloud/bigtable/__init__.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Copyright 2015 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Google Cloud Bigtable API package."""
16+
17+
try:
18+
from grpc._adapter import _c
19+
except ImportError as exc:
20+
if 'libgrpc.so' in str(exc):
21+
raise ImportError('gRPC libraries could not be located. Please see '
22+
'instructions to locate these files. You\'ll want '
23+
'to set your LD_LIBRARY_PATH variable to help '
24+
'Python locate the libraries.')
25+
else:
26+
raise

gcloud/bigtable/test___init__.py

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
# Copyright 2015 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
16+
import unittest2
17+
18+
19+
class TestGRPCImportFailure(unittest2.TestCase):
20+
21+
_MODULES_TO_EDIT = ('gcloud.bigtable', 'grpc',
22+
'grpc._adapter', 'grpc._adapter._c')
23+
24+
@classmethod
25+
def setUpClass(cls):
26+
import imp
27+
import gcloud
28+
29+
# imp.find_module does not handle hierarchical module names, so
30+
# we look for bigtable inside `gcloud.__path__`.
31+
cls._load_module_args = (('gcloud.bigtable',) +
32+
imp.find_module('bigtable', gcloud.__path__))
33+
34+
@classmethod
35+
def tearDownClass(cls):
36+
del cls._load_module_args
37+
38+
def _module_patch_helper(self, function_to_test):
39+
import sys
40+
41+
removed_mods = {}
42+
for mod_name in self._MODULES_TO_EDIT:
43+
removed_mods[mod_name] = sys.modules.get(mod_name)
44+
45+
try:
46+
sys.modules.pop('gcloud.bigtable', None)
47+
# Test method should re-import gcloud.bigtable
48+
function_to_test()
49+
finally:
50+
for mod_name, value in removed_mods.items():
51+
sys.modules[mod_name] = value
52+
53+
def test_success(self):
54+
import imp
55+
import sys
56+
import types
57+
58+
TEST_CASE = self
59+
60+
def function_to_test():
61+
c_mod = types.ModuleType('grpc._adapter._c')
62+
sys.modules['grpc._adapter._c'] = c_mod
63+
64+
adapter_mod = types.ModuleType('grpc._adapter')
65+
adapter_mod._c = c_mod
66+
sys.modules['grpc._adapter'] = adapter_mod
67+
68+
grpc_mod = types.ModuleType('grpc')
69+
grpc_mod._adapter = adapter_mod
70+
sys.modules['grpc'] = grpc_mod
71+
72+
# Re-import gcloud.bigtable and check our custom _c module.
73+
gcloud_bigtable = imp.load_module(*TEST_CASE._load_module_args)
74+
TEST_CASE.assertTrue(gcloud_bigtable._c is c_mod)
75+
76+
self._module_patch_helper(function_to_test)
77+
78+
@staticmethod
79+
def _create_fake_grpc_adapter_package(contents):
80+
import os
81+
import tempfile
82+
83+
temp_dir = tempfile.mkdtemp()
84+
85+
curr_dir = os.path.join(temp_dir, 'grpc')
86+
os.mkdir(curr_dir)
87+
with open(os.path.join(curr_dir, '__init__.py'), 'wb') as file_obj:
88+
file_obj.write(b'')
89+
90+
curr_dir = os.path.join(curr_dir, '_adapter')
91+
os.mkdir(curr_dir)
92+
with open(os.path.join(curr_dir, '__init__.py'), 'wb') as file_obj:
93+
file_obj.write(b'')
94+
95+
filename = os.path.join(curr_dir, '_c.py')
96+
with open(filename, 'wb') as file_obj:
97+
file_obj.write(contents)
98+
99+
return temp_dir
100+
101+
def _import_fail_helper(self, orig_exc_message):
102+
import imp
103+
import sys
104+
105+
# Be sure the message contains libgrpc.so
106+
c_module_contents = 'raise ImportError(%r)\n' % (orig_exc_message,)
107+
c_module_contents = c_module_contents.encode('ascii')
108+
temp_dir = self._create_fake_grpc_adapter_package(c_module_contents)
109+
110+
TEST_CASE = self
111+
112+
def function_to_test():
113+
sys.path.insert(0, temp_dir)
114+
try:
115+
sys.modules.pop('grpc')
116+
sys.modules.pop('grpc._adapter')
117+
sys.modules.pop('grpc._adapter._c')
118+
119+
try:
120+
imp.load_module(*TEST_CASE._load_module_args)
121+
except ImportError as exc:
122+
if 'libgrpc.so' in orig_exc_message:
123+
TEST_CASE.assertNotEqual(str(exc), orig_exc_message)
124+
else:
125+
TEST_CASE.assertEqual(str(exc), orig_exc_message)
126+
finally:
127+
sys.path.remove(temp_dir)
128+
129+
self._module_patch_helper(function_to_test)
130+
131+
def test_system_library_cause(self):
132+
# Be sure the message contains libgrpc.so
133+
orig_exc_message = 'bad libgrpc.so'
134+
self._import_fail_helper(orig_exc_message)
135+
136+
def test_non_system_library_cause(self):
137+
# Be sure the message does not contain libgrpc.so
138+
orig_exc_message = 'Other cause of error'
139+
self._import_fail_helper(orig_exc_message)

0 commit comments

Comments
 (0)