Exemple #1
0
 def test_throttle_multiple(self):
     """Sleep if the limit is exceeded by multiple calls"""
     limiter = RateLimit(4, 4)
     cap = ConsumedCapacity("foobar", Capacity(3, 0))
     with self.inject_capacity(cap, limiter) as sleep:
         list(self.dynamo.query("foobar", "id = :id", id="a"))
         list(self.dynamo.query("foobar", "id = :id", id="a"))
     sleep.assert_called_with(2)
Exemple #2
0
 def test_throttle_table(self):
     """ Sleep if table limit is exceeded """
     limiter = RateLimit(3, 3, table_caps={
         'foobar': Capacity(0, 4),
     })
     cap = ConsumedCapacity('foobar', Capacity(8, 0), Capacity(0, 8))
     with self.inject_capacity(cap, limiter) as sleep:
         list(self.dynamo.query2('foobar', 'id = :id', id='a'))
     sleep.assert_called_with(2)
Exemple #3
0
 def test_throttle_callback(self):
     """Callback is called when a query is throttled"""
     callback = MagicMock()
     callback.return_value = True
     limiter = RateLimit(3, 3, callback=callback)
     cap = ConsumedCapacity("foobar", Capacity(3, 0))
     with self.inject_capacity(cap, limiter) as sleep:
         list(self.dynamo.query("foobar", "id = :id", id="a"))
     sleep.assert_not_called()
     self.assertTrue(callback.called)
Exemple #4
0
 def test_global_default(self):
     """ Global index limit will fall back to table default limit """
     limiter = RateLimit(default_read=4, default_write=4)
     cap = ConsumedCapacity('foobar',
                            Capacity(8, 0),
                            global_index_capacity={
                                'baz': Capacity(8, 0),
                            })
     with self.inject_capacity(cap, limiter) as sleep:
         list(self.dynamo.query2('foobar', 'id = :id', id='a'))
     sleep.assert_called_with(2)
Exemple #5
0
 def test_global_default_table(self):
     """ Global index limit defaults to table limit if not present """
     limiter = RateLimit(table_caps={
         'foobar': Capacity(4, 0),
     })
     cap = ConsumedCapacity('foobar',
                            Capacity(8, 0),
                            global_index_capacity={
                                'baz': Capacity(8, 0),
                            })
     with self.inject_capacity(cap, limiter) as sleep:
         list(self.dynamo.query2('foobar', 'id = :id', id='a'))
     sleep.assert_called_with(2)
Exemple #6
0
 def test_global_index_by_name(self):
     """ Global index limit can be specified as tablename:index_name """
     limiter = RateLimit(table_caps={
         'foobar:baz': Capacity(4, 0),
     })
     cap = ConsumedCapacity('foobar',
                            Capacity(8, 0),
                            global_index_capacity={
                                'baz': Capacity(8, 0),
                            })
     with self.inject_capacity(cap, limiter) as sleep:
         list(self.dynamo.query2('foobar', 'id = :id', id='a'))
     sleep.assert_called_with(2)
Exemple #7
0
 def test_global_index(self):
     """ Sleep when global index limit is exceeded """
     limiter = RateLimit(table_caps={'foobar': {
         'baz': Capacity(4, 0),
     }})
     cap = ConsumedCapacity('foobar',
                            Capacity(8, 0),
                            global_index_capacity={
                                'baz': Capacity(8, 0),
                            })
     with self.inject_capacity(cap, limiter) as sleep:
         list(self.dynamo.query2('foobar', 'id = :id', id='a'))
     sleep.assert_called_with(2)
Exemple #8
0
 def test_local_index(self):
     """ Local index capacities count towards the table limit """
     limiter = RateLimit(table_caps={
         'foobar': Capacity(4, 0),
     })
     cap = ConsumedCapacity('foobar',
                            Capacity(8, 0),
                            local_index_capacity={
                                'local': Capacity(4, 0),
                            })
     with self.inject_capacity(cap, limiter) as sleep:
         list(self.dynamo.query2('foobar', 'id = :id', id='a'))
     sleep.assert_called_with(1)
Exemple #9
0
 def test_throttle_table(self):
     """Sleep if table limit is exceeded"""
     limiter = RateLimit(
         3,
         3,
         table_caps={
             "foobar": Capacity(0, 4),
         },
     )
     cap = ConsumedCapacity("foobar", Capacity(8, 0), Capacity(0, 8))
     with self.inject_capacity(cap, limiter) as sleep:
         list(self.dynamo.query("foobar", "id = :id", id="a"))
     sleep.assert_called_with(2)
Exemple #10
0
 def test_global_default(self):
     """Global index limit will fall back to table default limit"""
     limiter = RateLimit(default_read=4, default_write=4)
     cap = ConsumedCapacity(
         "foobar",
         Capacity(8, 0),
         global_index_capacity={
             "baz": Capacity(8, 0),
         },
     )
     with self.inject_capacity(cap, limiter) as sleep:
         list(self.dynamo.query("foobar", "id = :id", id="a"))
     sleep.assert_called_with(2)
Exemple #11
0
 def _parse_throttle(self, tablename, throttle):
     """ Parse a 'throttle' statement and return a RateLimit """
     amount = []
     desc = self.describe(tablename)
     throughputs = [desc.read_throughput, desc.write_throughput]
     for value, throughput in zip(throttle[1:], throughputs):
         if value == "*":
             amount.append(0)
         elif value[-1] == "%":
             amount.append(throughput * float(value[:-1]) / 100.0)
         else:
             amount.append(float(value))
     cap = Capacity(*amount)  # pylint: disable=E1120
     return RateLimit(total=cap, callback=self._on_throttle)
Exemple #12
0
 def test_global_default_table(self):
     """Global index limit defaults to table limit if not present"""
     limiter = RateLimit(table_caps={
         "foobar": Capacity(4, 0),
     })
     cap = ConsumedCapacity(
         "foobar",
         Capacity(8, 0),
         global_index_capacity={
             "baz": Capacity(8, 0),
         },
     )
     with self.inject_capacity(cap, limiter) as sleep:
         list(self.dynamo.query("foobar", "id = :id", id="a"))
     sleep.assert_called_with(2)
Exemple #13
0
 def test_global_index_by_name(self):
     """Global index limit can be specified as tablename:index_name"""
     limiter = RateLimit(table_caps={
         "foobar:baz": Capacity(4, 0),
     })
     cap = ConsumedCapacity(
         "foobar",
         Capacity(8, 0),
         global_index_capacity={
             "baz": Capacity(8, 0),
         },
     )
     with self.inject_capacity(cap, limiter) as sleep:
         list(self.dynamo.query("foobar", "id = :id", id="a"))
     sleep.assert_called_with(2)
Exemple #14
0
 def test_global_index(self):
     """Sleep when global index limit is exceeded"""
     limiter = RateLimit(table_caps={"foobar": {
         "baz": Capacity(4, 0),
     }})
     cap = ConsumedCapacity(
         "foobar",
         Capacity(8, 0),
         global_index_capacity={
             "baz": Capacity(8, 0),
         },
     )
     with self.inject_capacity(cap, limiter) as sleep:
         list(self.dynamo.query("foobar", "id = :id", id="a"))
     sleep.assert_called_with(2)
Exemple #15
0
 def test_local_index(self):
     """Local index capacities count towards the table limit"""
     limiter = RateLimit(table_caps={
         "foobar": Capacity(4, 0),
     })
     cap = ConsumedCapacity(
         "foobar",
         Capacity(8, 0),
         local_index_capacity={
             "local": Capacity(4, 0),
         },
     )
     with self.inject_capacity(cap, limiter) as sleep:
         list(self.dynamo.query("foobar", "id = :id", id="a"))
     sleep.assert_called_with(1)
Exemple #16
0
 def _parse_throttle(self, tablename: str, throttle: Any) -> RateLimit:
     """Parse a 'throttle' statement and return a RateLimit"""
     amount: List[float] = []
     desc = self.describe(tablename)
     if desc.throughput is None:
         throughputs = (0, 0)
     else:
         throughputs = (desc.throughput.read, desc.throughput.write)
     for value, throughput in zip(throttle[1:], throughputs):
         if value == "*":
             amount.append(0)
         elif value[-1] == "%":
             amount.append(throughput * float(value[:-1]) / 100.0)
         else:
             amount.append(float(value))
     cap = Capacity(*amount)  # pylint: disable=E1120
     return RateLimit(total=cap, callback=self._on_throttle)
Exemple #17
0
 def get_limiter(self, table_descriptions):
     """ Construct a RateLimit object from the throttle declarations """
     table_caps = {}
     for table in table_descriptions:
         limit = self.tables.get(table.name) or self.default
         # Add the table limit
         if limit:
             table_caps[table.name] = {
                 'read':
                 self._compute_limit(limit['read'], table.read_throughput),
                 'write':
                 self._compute_limit(limit['write'],
                                     table.write_throughput),
             }
         if table.name not in self.indexes:
             continue
         # Add the global index limits
         for index in six.itervalues(table.global_indexes):
             limit = (self.indexes[table.name].get(index.name)
                      or self.default)
             if limit:
                 cap = table_caps.setdefault(table.name, {})
                 cap[index.name] = {
                     'read':
                     self._compute_limit(limit['read'],
                                         index.read_throughput),
                     'write':
                     self._compute_limit(limit['write'],
                                         index.write_throughput),
                 }
     kwargs = {
         'table_caps': table_caps,
     }
     if self.total:
         kwargs['total_read'] = float(self.total['read'])
         kwargs['total_write'] = float(self.total['write'])
     return RateLimit(**kwargs)