trove-integration/tests/integration/tests/dns/concurrency.py

110 lines
3.8 KiB
Python

# Copyright 2011 OpenStack LLC.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""
This test recreates an issue we had with eventlet. In the logs, we'd see that
the JSON response was malformed; instead of JSON, it contained the following
string:
Second simultaneous read on fileno 5 detected. Unless you really know what
you're doing, make sure that only one greenthread can read any particular
socket. Consider using a pools.Pool. If you do know what you're doing and want
to disable this error, call
eventlet.debug.hub_multiple_reader_prevention(False)
It is perhaps the most helpful error message ever created.
The root issue was that a subclass of httplib2.Http was created at program
started and used in all threads.
Using the old (broken) RsDNS client code this test recreates the greatest error
message ever.
"""
try:
import eventlet
CAN_USE_EVENTLET = True
except ImportError:
CAN_USE_EVENTLET = False
import uuid
from proboscis import before_class
from proboscis import test
from proboscis.asserts import assert_true
from tests.util import should_run_rsdns_tests
from tests import WHITE_BOX
if WHITE_BOX:
from trove.dns.rsdns.driver import RsDnsInstanceEntryFactory
from nova import flags
from nova import utils
FLAGS = flags.FLAGS
@test(groups=["rsdns.eventlet"], enabled=CAN_USE_EVENTLET)
class RsdnsEventletTests(object):
"""Makes sure the RSDNS client can be used from multiple green threads."""
def assert_record_created(self, index):
msg = "Record %d wasn't created!" % index
assert_true(index in self.new_records, msg)
@before_class(enabled=WHITE_BOX and should_run_rsdns_tests())
def create_driver(self):
"""Creates the DNS Driver used in subsequent tests."""
self.driver = utils.import_object(FLAGS.dns_driver)
self.entry_factory = RsDnsInstanceEntryFactory()
self.test_uuid = uuid.uuid4().hex
self.new_records = {}
def make_record(self, index):
"""Creates a record with the form 'eventlet-%s-%d'."""
uuid = "eventlet-%s-%d" % (self.test_uuid, index)
instance = {'uuid': uuid}
entry = self.entry_factory.create_entry(instance)
entry.name = uuid + "." + self.entry_factory.default_dns_zone.name
entry.content = "123.123.123.123"
self.driver.create_entry(entry)
self.new_records[index] = True
@test(enabled=WHITE_BOX and should_run_rsdns_tests())
def use_dns_from_a_single_thread(self):
"""Add DNS records one at a time."""
self.new_records = {}
for index in range(-1, -5, -1):
self.make_record(index)
self.assert_record_created(index)
@test(enabled=WHITE_BOX and should_run_rsdns_tests())
def use_dns_from_multiple_greenthreads(self):
"""Add multiple DNS records at once."""
self.new_records = {}
def make_record(index):
def __cb():
self.make_record(index)
self.assert_record_created(index)
return index
return __cb
pile = eventlet.GreenPile()
indices = range(1, 4)
for index in indices:
pile.spawn(make_record(index))
list(pile) # Wait for them to finish
for index in indices:
self.assert_record_created(index)