1# 2# Copyright 2015 Google Inc. 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain 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, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16"""Tests for util.py.""" 17import unittest2 18 19from apitools.base.protorpclite import messages 20from apitools.base.py import encoding 21from apitools.base.py import exceptions 22from apitools.base.py import util 23 24 25class MockedMethodConfig(object): 26 27 def __init__(self, relative_path, path_params): 28 self.relative_path = relative_path 29 self.path_params = path_params 30 31 32class MessageWithRemappings(messages.Message): 33 34 class AnEnum(messages.Enum): 35 value_one = 1 36 value_two = 2 37 38 str_field = messages.StringField(1) 39 enum_field = messages.EnumField('AnEnum', 2) 40 41 42encoding.AddCustomJsonFieldMapping( 43 MessageWithRemappings, 'str_field', 'path_field') 44encoding.AddCustomJsonEnumMapping( 45 MessageWithRemappings.AnEnum, 'value_one', 'ONE') 46 47 48class UtilTest(unittest2.TestCase): 49 50 def testExpand(self): 51 method_config_xy = MockedMethodConfig(relative_path='{x}/y/{z}', 52 path_params=['x', 'z']) 53 self.assertEquals( 54 util.ExpandRelativePath(method_config_xy, {'x': '1', 'z': '2'}), 55 '1/y/2') 56 self.assertEquals( 57 util.ExpandRelativePath( 58 method_config_xy, 59 {'x': '1', 'z': '2'}, 60 relative_path='{x}/y/{z}/q'), 61 '1/y/2/q') 62 63 def testReservedExpansion(self): 64 method_config_reserved = MockedMethodConfig(relative_path='{+x}/baz', 65 path_params=['x']) 66 self.assertEquals('foo/:bar:/baz', util.ExpandRelativePath( 67 method_config_reserved, {'x': 'foo/:bar:'})) 68 method_config_no_reserved = MockedMethodConfig(relative_path='{x}/baz', 69 path_params=['x']) 70 self.assertEquals('foo%2F%3Abar%3A/baz', util.ExpandRelativePath( 71 method_config_no_reserved, {'x': 'foo/:bar:'})) 72 73 def testCalculateWaitForRetry(self): 74 try0 = util.CalculateWaitForRetry(0) 75 self.assertTrue(try0 >= 1.0) 76 self.assertTrue(try0 <= 1.5) 77 try1 = util.CalculateWaitForRetry(1) 78 self.assertTrue(try1 >= 1.0) 79 self.assertTrue(try1 <= 3.0) 80 try2 = util.CalculateWaitForRetry(2) 81 self.assertTrue(try2 >= 2.0) 82 self.assertTrue(try2 <= 6.0) 83 try3 = util.CalculateWaitForRetry(3) 84 self.assertTrue(try3 >= 4.0) 85 self.assertTrue(try3 <= 12.0) 86 try4 = util.CalculateWaitForRetry(4) 87 self.assertTrue(try4 >= 8.0) 88 self.assertTrue(try4 <= 24.0) 89 90 self.assertAlmostEqual(10, util.CalculateWaitForRetry(5, max_wait=10)) 91 92 def testTypecheck(self): 93 94 class Class1(object): 95 pass 96 97 class Class2(object): 98 pass 99 100 class Class3(object): 101 pass 102 103 instance_of_class1 = Class1() 104 105 self.assertEquals( 106 instance_of_class1, util.Typecheck(instance_of_class1, Class1)) 107 108 self.assertEquals( 109 instance_of_class1, 110 util.Typecheck(instance_of_class1, ((Class1, Class2), Class3))) 111 112 self.assertEquals( 113 instance_of_class1, 114 util.Typecheck(instance_of_class1, (Class1, (Class2, Class3)))) 115 116 self.assertEquals( 117 instance_of_class1, 118 util.Typecheck(instance_of_class1, Class1, 'message')) 119 120 self.assertEquals( 121 instance_of_class1, 122 util.Typecheck( 123 instance_of_class1, ((Class1, Class2), Class3), 'message')) 124 125 self.assertEquals( 126 instance_of_class1, 127 util.Typecheck( 128 instance_of_class1, (Class1, (Class2, Class3)), 'message')) 129 130 with self.assertRaises(exceptions.TypecheckError): 131 util.Typecheck(instance_of_class1, Class2) 132 133 with self.assertRaises(exceptions.TypecheckError): 134 util.Typecheck(instance_of_class1, (Class2, Class3)) 135 136 with self.assertRaises(exceptions.TypecheckError): 137 util.Typecheck(instance_of_class1, Class2, 'message') 138 139 with self.assertRaises(exceptions.TypecheckError): 140 util.Typecheck(instance_of_class1, (Class2, Class3), 'message') 141 142 def testAcceptableMimeType(self): 143 valid_pairs = ( 144 ('*', 'text/plain'), 145 ('*/*', 'text/plain'), 146 ('text/*', 'text/plain'), 147 ('*/plain', 'text/plain'), 148 ('text/plain', 'text/plain'), 149 ) 150 151 for accept, mime_type in valid_pairs: 152 self.assertTrue(util.AcceptableMimeType([accept], mime_type)) 153 154 invalid_pairs = ( 155 ('text/*', 'application/json'), 156 ('text/plain', 'application/json'), 157 ) 158 159 for accept, mime_type in invalid_pairs: 160 self.assertFalse(util.AcceptableMimeType([accept], mime_type)) 161 162 self.assertTrue(util.AcceptableMimeType(['application/json', '*/*'], 163 'text/plain')) 164 self.assertFalse(util.AcceptableMimeType(['application/json', 'img/*'], 165 'text/plain')) 166 167 def testMalformedMimeType(self): 168 self.assertRaises( 169 exceptions.InvalidUserInputError, 170 util.AcceptableMimeType, ['*/*'], 'abcd') 171 172 def testUnsupportedMimeType(self): 173 self.assertRaises( 174 exceptions.GeneratedClientError, 175 util.AcceptableMimeType, ['text/html;q=0.9'], 'text/html') 176 177 def testMapRequestParams(self): 178 params = { 179 'str_field': 'foo', 180 'enum_field': MessageWithRemappings.AnEnum.value_one, 181 } 182 remapped_params = { 183 'path_field': 'foo', 184 'enum_field': 'ONE', 185 } 186 self.assertEqual(remapped_params, 187 util.MapRequestParams(params, MessageWithRemappings)) 188 189 params['enum_field'] = MessageWithRemappings.AnEnum.value_two 190 remapped_params['enum_field'] = 'value_two' 191 self.assertEqual(remapped_params, 192 util.MapRequestParams(params, MessageWithRemappings)) 193 194 def testMapParamNames(self): 195 params = ['path_field', 'enum_field'] 196 remapped_params = ['str_field', 'enum_field'] 197 self.assertEqual(remapped_params, 198 util.MapParamNames(params, MessageWithRemappings)) 199