1212# See the License for the specific language governing permissions and
1313# limitations under the License.
1414
15+ import datetime
1516import unittest
1617
18+ import mock
19+
20+
21+ def _create_signing_credentials ():
22+ import google .auth .credentials
23+
24+ class _SigningCredentials (
25+ google .auth .credentials .Credentials ,
26+ google .auth .credentials .Signing ):
27+ pass
28+
29+ credentials = mock .Mock (spec = _SigningCredentials )
30+
31+ return credentials
32+
1733
1834class Test_Bucket (unittest .TestCase ):
1935
@@ -782,7 +798,6 @@ def test_storage_class_setter_DURABLE_REDUCED_AVAILABILITY(self):
782798 self .assertTrue ('storageClass' in bucket ._changes )
783799
784800 def test_time_created (self ):
785- import datetime
786801 from google .cloud ._helpers import _RFC3339_MICROS
787802 from google .cloud ._helpers import UTC
788803
@@ -903,7 +918,6 @@ def test_make_public_w_future_reload_default(self):
903918 self ._make_public_w_future_helper (default_object_acl_loaded = False )
904919
905920 def test_make_public_recursive (self ):
906- import mock
907921 from google .cloud .storage .acl import _ACLEntity
908922
909923 _saved = []
@@ -1068,6 +1082,82 @@ def dummy_response():
10681082 self .assertEqual (page2 .num_items , 0 )
10691083 self .assertEqual (iterator .prefixes , set (['foo' , 'bar' ]))
10701084
1085+ def _test_generate_upload_policy_helper (self , ** kwargs ):
1086+ import base64
1087+ import json
1088+
1089+ credentials = _create_signing_credentials ()
1090+ credentials .signer_email = mock .sentinel .signer_email
1091+ credentials .sign_bytes .return_value = b'DEADBEEF'
1092+ connection = _Connection ()
1093+ connection .credentials = credentials
1094+ client = _Client (connection )
1095+ name = 'name'
1096+ bucket = self ._make_one (client = client , name = name )
1097+
1098+ conditions = [
1099+ ['starts-with' , '$key' , '' ]]
1100+
1101+ policy_fields = bucket .generate_upload_policy (conditions , ** kwargs )
1102+
1103+ self .assertEqual (policy_fields ['bucket' ], bucket .name )
1104+ self .assertEqual (
1105+ policy_fields ['GoogleAccessId' ], mock .sentinel .signer_email )
1106+ self .assertEqual (
1107+ policy_fields ['signature' ],
1108+ base64 .b64encode (b'DEADBEEF' ).decode ('utf-8' ))
1109+
1110+ policy = json .loads (
1111+ base64 .b64decode (policy_fields ['policy' ]).decode ('utf-8' ))
1112+
1113+ policy_conditions = policy ['conditions' ]
1114+ expected_conditions = [{'bucket' : bucket .name }] + conditions
1115+ for expected_condition in expected_conditions :
1116+ for condition in policy_conditions :
1117+ if condition == expected_condition :
1118+ break
1119+ else : # pragma: NO COVER
1120+ self .fail ('Condition {} not found in {}' .format (
1121+ expected_condition , policy_conditions ))
1122+
1123+ return policy_fields , policy
1124+
1125+ @mock .patch (
1126+ 'google.cloud.storage.bucket._NOW' ,
1127+ return_value = datetime .datetime (1990 , 1 , 1 ))
1128+ def test_generate_upload_policy (self , now ):
1129+ from google .cloud ._helpers import _datetime_to_rfc3339
1130+
1131+ _ , policy = self ._test_generate_upload_policy_helper ()
1132+
1133+ self .assertEqual (
1134+ policy ['expiration' ],
1135+ _datetime_to_rfc3339 (
1136+ now () + datetime .timedelta (hours = 1 )))
1137+
1138+ def test_generate_upload_policy_args (self ):
1139+ from google .cloud ._helpers import _datetime_to_rfc3339
1140+
1141+ expiration = datetime .datetime (1990 , 5 , 29 )
1142+
1143+ _ , policy = self ._test_generate_upload_policy_helper (
1144+ expiration = expiration )
1145+
1146+ self .assertEqual (
1147+ policy ['expiration' ],
1148+ _datetime_to_rfc3339 (expiration ))
1149+
1150+ def test_generate_upload_policy_bad_credentials (self ):
1151+ credentials = object ()
1152+ connection = _Connection ()
1153+ connection .credentials = credentials
1154+ client = _Client (connection )
1155+ name = 'name'
1156+ bucket = self ._make_one (client = client , name = name )
1157+
1158+ with self .assertRaises (AttributeError ):
1159+ bucket .generate_upload_policy ([])
1160+
10711161
10721162class _Connection (object ):
10731163 _delete_bucket = False
@@ -1076,6 +1166,7 @@ def __init__(self, *responses):
10761166 self ._responses = responses
10771167 self ._requested = []
10781168 self ._deleted_buckets = []
1169+ self .credentials = None
10791170
10801171 @staticmethod
10811172 def _is_bucket_path (path ):
@@ -1108,4 +1199,5 @@ class _Client(object):
11081199
11091200 def __init__ (self , connection , project = None ):
11101201 self ._connection = connection
1202+ self ._base_connection = connection
11111203 self .project = project
0 commit comments